---
# System prepended metadata

title: 'Android App 設計開發課程 #9'

---

# 剪刀石頭布遊戲 app 參考

```kotlin=
package tw.josephku.rpsnow

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Button
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import tw.josephku.rpsnow.ui.theme.RPSNowTheme

enum class Choice {
    ROCK, PAPER, SCISSORS
}

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            RPSNowTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    RPSNow()
                }
            }
        }
    }
}

@Composable
fun choiceButton(bvlaue: String, onClick: () -> Unit) {
    // buttons generator
    Button(
        modifier = Modifier
            .height(130.dp)
            .width(130.dp)
            .padding(5.dp),
        onClick = onClick,
        shape = RoundedCornerShape(14.dp)
    ) {
        Text(text = bvlaue)
    }
}

@Composable
fun displayChoice(player: String, action: String) {
    //player and android choices display
    Text(
        text = player,
        fontSize = 16.sp,
        modifier = Modifier
            .fillMaxWidth()
            .wrapContentWidth(Alignment.CenterHorizontally)
    )
    Text(
        text = action,
        fontSize = 32.sp,
        modifier = Modifier
            .fillMaxWidth()
            .wrapContentWidth(Alignment.CenterHorizontally),
        fontWeight = FontWeight.Bold
    )
}

@Composable
fun RPSNow() {
    //main compose
    val image = painterResource(id = R.drawable.rpsnow_banner)
    var playerChoiceName by remember { mutableStateOf("--") }
    var computerChoiceName by remember { mutableStateOf("--") }

    var playerWins by remember { mutableIntStateOf(0) }
    var computerWins by remember { mutableIntStateOf(0) }

    var records by remember { mutableStateOf("0 / 0") }

    Column {
        //main column
        Image(
            painter = image,
            contentDescription = null
        )
        Text(
            text = "Records",
            fontSize = 30.sp,
            modifier = Modifier
                .fillMaxWidth()
                .wrapContentWidth(Alignment.CenterHorizontally)
                .padding(top = 16.dp)
        )
        Text(
            text = records,
            fontSize = 50.sp,
            modifier = Modifier
                .fillMaxWidth()
                .wrapContentWidth(Alignment.CenterHorizontally),
            fontWeight = FontWeight.Bold
        )

        Row(modifier = Modifier.padding(top = 85.dp)) {
            Column(
                Modifier
                    .fillMaxWidth(0.5f)
                    .wrapContentWidth(Alignment.CenterHorizontally)
            ) {
                displayChoice("Your Choice", playerChoiceName)
            }
            Column(
                Modifier
                    .fillMaxWidth()
                    .wrapContentWidth(Alignment.CenterHorizontally)
            ) {
                displayChoice("Computer's Choice", computerChoiceName)
            }
        }

        Row(modifier = Modifier.padding(top = 70.dp)) {
            Choice.entries.forEach { choice ->
                choiceButton(bvlaue = choice.name) {
                    playerChoiceName = choice.name
                    val computerChoice = Choice.entries.random()
                    computerChoiceName = computerChoice.name

                    val result = (choice.ordinal - computerChoice.ordinal + 3) % 3
                    when (result) {
                        0 -> {}
                        1 -> { playerWins++ }
                        else -> { computerWins++ }
                    }
                    records = "$playerWins / $computerWins"
                }
            }
        }
    }
}

@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
    RPSNowTheme {
        RPSNow()
    }
}
```

[Banner 圖](https://slack-files.com/T06ARGM2N-F070MND4L4F-c7943aebdc)

**Apktool**
https://apktool.org

macOS 安裝
```
$ brew install apktool
```

Windows 安裝
```
$ choco install apktool
```

Usage:
```
$ apktool d -f app-debug.apk
```
Revise strings.xml
```
$ apktool b app-debug -o new.apk
```

```
$ keytool -genkey -v -keystore my-test-key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias my-alias
```

```
$ keytool -genkey -v -keystore my-test-key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias my-alias
```

```
$ zipalign -v -p 4 new.apk new-align.apk
```

```
$ apksigner sign --ks my-test-key.jks --ks-pass pass:12345678 -out new-final.apk new-align.apk
```

zipalign 與 apksigner 在 $ANDROID_HOME/build-tool 中

**ApkLeaks**
https://github.com/dwisiswant0/apkleaks

macOS 安裝
```
$ brew install apkleaks
```

PyPi 安裝
```
$ pip3 install apkleaks 
```

Usage:
```
$ apkleaks -f app-debug.apk
```