# Android Code Signing

import { Image } from 'astro:assets';
import { Code, Tabs, TabItem } from '@astrojs/starlight/components';
import BuildGradleFiletree from '@assets/distribute/sign/build-gradle-kts-filetree.png';

To publish on the Play Store, you need to sign your app with a digital certificate.

Android App Bundles and APKs must be signed before being uploaded for distribution.

Google also provides an additional signing mechanism for Android App Bundles distributed in the Play Store.
See the [official Play App Signing documentation] for more information.

## Creating a keystore and upload key

Android signing requires a Java Keystore file that can be generated using the official `keytool` CLI:

<Tabs syncKey="OS">
  <TabItem label="macOS/Linux">
  
```
keytool -genkey -v -keystore ~/upload-keystore.jks -keyalg RSA -keysize 2048 -validity 10000 -alias upload
```

  </TabItem>

  <TabItem label="Windows">
  
```
keytool -genkey -v -keystore $env:USERPROFILE\upload-keystore.jks -storetype JKS -keyalg RSA -keysize 2048 -validity 10000 -alias upload
```

  </TabItem>
</Tabs>

This command stores the `upload-keystore.jks` file in your home directory.
If you want to store it elsewhere, change the argument you pass to the `-keystore` parameter.

:::tip

- The `keytool` command might not be in your PATH.
  You may find it installed in the JDK that is installed with Android Studio:

<Tabs syncKey="OS">

<TabItem label="Linux">
  <Code code="/opt/android-studio/jbr/bin/keytool ...args" lang="sh" />
  **Android Studio directory path depends on your Linux distribution**
</TabItem>

<TabItem label="macOS">
  <Code
    code="/Applications/Android\ Studio.app/Contents/jbr/Contents/Home/bin/keytool ...args"
    lang="sh"
  />
</TabItem>

<TabItem label="Windows">
  <Code
    code="C:\\Program Files\\Android\\Android Studio\\jbr\\bin\\keytool.exe ...args"
    lang="sh"
  />
</TabItem>

</Tabs>

:::

:::caution[Security Warning]

Keep the `keystore` file private; don't check it into public source control!

:::

See the [official documentation](https://developer.android.com/studio/publish/app-signing#generate-key) for more information.

## Configure the signing key

Create a file named `[project]/src-tauri/gen/android/keystore.properties` that contains a reference to your keystore:

```
password=<password defined when keytool was executed>
keyAlias=upload
storeFile=<location of the key store file, such as /Users/<user name>/upload-keystore.jks or C:\\Users\\<user name>\\upload-keystore.jks>
```

:::caution[Security Warning]
Keep the `keystore.properties` file private; don't check it into public source control.
:::

You will usually generate this file in your CI/CD platform. The following snippet contains an example job step for GitHub Actions:

```yml
- name: setup Android signing
  run: |
    cd src-tauri/gen/android
    echo "keyAlias=${{ secrets.ANDROID_KEY_ALIAS }}" > keystore.properties
    echo "password=${{ secrets.ANDROID_KEY_PASSWORD }}" >> keystore.properties
    base64 -d <<< "${{ secrets.ANDROID_KEY_BASE64 }}" > $RUNNER_TEMP/keystore.jks
    echo "storeFile=$RUNNER_TEMP/keystore.jks" >> keystore.properties
```

In this example the keystore was exported to base64 with `base64 -i /path/to/keystore.jks` and set as the `ANDROID_KEY_BASE64` secret.

### Configure Gradle to use the signing key

Configure gradle to use your upload key when building your app in release mode by editing the `[project]/src-tauri/gen/android/app/build.gradle.kts` file.

:::tip

There are multiple different `build.gradle.kts` files in a typical Android project. If there is no `buildTypes` block you're looking at the wrong file. The one you need is in the `app/` directory relative to the keystore file from the prior step.

<details>
  <summary>
    Click here for a screenshot showing its location in a typical file tree.
  </summary>
  <Image
    src={BuildGradleFiletree}
    alt="build.gradle.kts location in file tree"
  />
</details>

:::

1.  Add the needed import at the beginning of the file:

    ```kotlin
    import java.io.FileInputStream
    ```

2.  Add the `release` signing config before the `buildTypes` block:

    ```kotlin {3-12}
    signingConfigs {
        create("release") {
            val keystorePropertiesFile = rootProject.file("keystore.properties")
            val keystoreProperties = Properties()
            if (keystorePropertiesFile.exists()) {
                keystoreProperties.load(FileInputStream(keystorePropertiesFile))
            }

            keyAlias = keystoreProperties["keyAlias"] as String
            keyPassword = keystoreProperties["password"] as String
            storeFile = file(keystoreProperties["storeFile"] as String)
            storePassword = keystoreProperties["password"] as String
        }
    }

    buildTypes {
        ...
    }
    ```

3.  Use the new `release` signing config in the `release` config in `buildTypes` block:

    ```kotlin {3}
    buildTypes {
        getByName("release") {
            signingConfig = signingConfigs.getByName("release")
        }
    }
    ```

Release builds of your app will now be signed automatically.

[official Play App Signing documentation]: https://support.google.com/googleplay/android-developer/answer/9842756?hl=en&visit_id=638549803861403647-3347771264&rd=1