🍣

AndroidStdioで署名付きreleaseビルド時・インストール時の署名エラーを解決する

に公開

結論

以下手順でAndroid Studioでも署名付きビルドイメージを使うことができました。

  • 署名などのシークレットを定義するファイルを作成する
  • 定義したファイルをbuild.gradle.ktsでよみこむ
  • 読み込んだ値を使い、署名を設定する

詳しくは以下に書いていきます。

はじめに

android studioでアプリをreleaseビルドしてエミュレーターにインストールしようとしたところエラーになってしまった。

The application could not be installed: INSTALL_PARSE_FAILED_NO_CERTIFICATES APK signature verification failed. List of apks: [0] '/Users/xxxxxxxx/hoge/app/build/intermediates/extracted_apks/release/extractApksFromBundleForRelease/base-en.apk' [1] '/Users/xxxxxxxx/hoge/app/build/intermediates/extracted_apks/release/extractApksFromBundleForRelease/base-arm64_v8a.apk' [2] '/Users/xxxxxxxx/hoge/app/build/intermediates/extracted_apks/release/extractApksFromBundleForRelease/base-xxhdpi.apk' [3] '/Users/xxxxxxxx/hoge/app/build/intermediates/extracted_apks/release/extractApksFromBundleForRelease/base-master.apk'

NO_CERTIFICATES とあるので、署名に問題があるのは明らかです。

記載しない事

  • 署名の作り方
  • 署名付きビルドのやり方

環境

$ ./gradlew --version

------------------------------------------------------------
Gradle 8.11.1
------------------------------------------------------------

Build time:    2024-11-20 16:56:46 UTC
Revision:      481cb05a490e0ef9f8620f7873b83bd8a72e7c39

Kotlin:        2.0.20
Groovy:        3.0.22
Ant:           Apache Ant(TM) version 1.10.14 compiled on August 16 2023
Launcher JVM:  17.0.12 (JetBrains s.r.o. 17.0.12+1-b1207.37)
Daemon JVM:    /Users/xxxxxxxx/Library/Java/JavaVirtualMachines/jbr-17.0.12/Contents/Home (no JDK specified, using current Java home)
OS:            Mac OS X 15.4.1 aarch64

今ある情報

ビルドしたapiをバラして署名を更新している。

apkをコマンドラインで署名付きにして使うという感じの情報が多い。
でももっと楽したい!

対策

署名情報をAndroid Studio で設定することができるので、設定後にビルドすればインストールできる。

AndroidStudioで署名情報を設定する方法

後述のgit管理の問題で本方法は実際には使えないが、署名の動作確認するに当たり使うことがあるかも。

Project Structureを開く

Signing Configsを設定する

これでbuild.gradle.ktsに設定がされる。
慣れればbuild.gradle.ktsに直接設定をすればいいだけ。

とりあえずこれでビルドはできるようになる。
ただ、git管理する必要があるbuild.gradle.ktsにシークレットが記載されてしまうのは困る。
またgradle.propertiesもgit管理対象なのでこちらにも書けない。

署名情報をgit管理しない方法

署名情報をプロジェクトルートにあるlocal.propertiesに記載する
android studioで自動生成されるファイルで最初にsdk.dirが記載されている。
ここにシークレットを追記する。

シークレットのイメージ

内容はシークレット作成時に自分で指定したもの。

sdk.dir=/Users/xxxxxxxx/Library/Android/sdk
signing.keyAlias = キーエイリアス
signing.storeFile = /Users/xxxxxxxx/anrdoid-upload-key/キーストア.jks
signing.storePassword = キーストアパスワード
signing.keyPassword = キーパスワード

シークレットをbuild.gradle.ktsに反映する

以下の設定を記載します。
loadProperties関数でlocal.propertiesを読み込んで、signingConfigsでそれぞれ設定しています。

// Kotlinの拡張関数を使用してプロパティファイルを読み込む
fun loadProperties(filename: String): Map<String, String> {
    val properties = mutableMapOf<String, String>()
    val file = rootProject.file(filename)
    if (file.exists()) {
        file.reader().use { reader ->
            reader.buffered().forEachLine { line ->
                if (!line.startsWith("#") && line.contains("=")) {
                    val (key, value) = line.split("=", limit = 2)
                    properties[key.trim()] = value.trim()
                }
            }
        }
    }
    return properties
}

android {
    // 署名情報をreleaseビルドに追加
    signingConfigs {
        create("release") {
            val localProperties = loadProperties("local.properties")
            storeFile = localProperties["signing.storeFile"]?.toString()?.let { file(it) }
            storePassword = localProperties["signing.storePassword"]?.toString()
            keyAlias = localProperties["signing.keyAlias"]?.toString()
            keyPassword = localProperties["signing.keyPassword"]?.toString()
        }
    }

    // 署名情報をログに出力
    tasks.register("printSigningInfo") {
        doLast {
            println("Release signing config:")
            println("storeFile: ${android.signingConfigs.getByName("release").storeFile}")
            println("storePassword: ${android.signingConfigs.getByName("release").storePassword}")
            println("keyAlias: ${android.signingConfigs.getByName("release").keyAlias}")
            println("keyPassword: ${android.signingConfigs.getByName("release").keyPassword}")
        }
    }

    // ビルドタイプに署名設定を追加
    buildTypes {
        getByName("release") {
            isMinifyEnabled = true
            proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro")
            signingConfig = signingConfigs.getByName("release")
        }
    }
    // ...other settings

なお、署名情報が正しいかどうかの確認のためにprintSigningInfoを追加してみました。
以下のように使用できます。
設定ができていない場合はnullになります。

$ ./gradlew printSigningInfo --no-configuration-cache

> Configure project :app
w: file:///Users/xxxx/hoge/app/build.gradle.kts:115:5: 'packagingOptions(Packaging.() -> Unit): Unit' is deprecated. Renamed to packaging

> Task :app:printSigningInfo
Release signing config:
storeFile: ストアファイル.jks"
storePassword: "ストアパスワード"
keyAlias: "キーエイリアス"
keyPassword: "キーパスワード"

BUILD SUCCESSFUL in 1s
1 actionable task: 1 executed

以上です!

Discussion