はじめに
CYBIRDエンジニア Advent Calendar 4日目担当の@chikako_ikedaです。
3日目は@kyorokyoroのアプリの通信回数を減らすためにやったことでした。
最近は速い通信規格が出てきてあまり気にならないこともありますが、アプリの通信回数はアプリの操作感が変わるので、「回数を減らす」というのは大事ですよね。
概要
2021/11/01からGoogle PlayではTargetSDKをAPI Level 30(Android11)へ対応することが必須となりました。
CYBIRDのアプリでも順次対応を進めているところですが、こんなところでハマったよ、ということで、
APKの署名スキーマv2への対応について紹介しようかと思います。
※以下、「TargetSDKをAPI Level 30(Android11)へ対応」は「TargetSDK30対応」と記載します。
目次
- 発端:出来上がったAPKがインストールできない
- 調査:とりあえず、エラー内容を確認しよう
- 原因:TargetSDK30から署名スキーマv2への対応が必須に
- 解決:署名スキーマv2の署名を追加しよう
APKの署名スキーマv2への対応
発端:出来上がったAPKがインストールできない
当社のアプリは全てではないですが、Jenkinsを使ってビルドの自動化を行なっています。
各開発者の環境に左右されず、ビルド後に必要な処理を自動でやることが可能になります。
(例:テスト用バイナリを特定のサーバにバックアップする、とか)
コードを修正して、Jenkinsでのビルドが成功したのち、実機で確認すべくインストールをしようとしました。
ところが、「このアプリはインストールできません」とだけ表示を出し、インストールに失敗しました。
ビルドログを見ても、「Success」と出ている。
色々バージョンを別に確認をしたところ、TargetSDK30対応分のコードでだけ発生していました。
調査:とりあえず、エラー内容を確認しよう
古のアンドロイダーである自覚のある私は、こういう時に真っ先にケーブルを繋ぎADBコマンドを叩きます。
※ADBはAndroidの開発ツールです。
端末の中に入ったり、アプリ内DBの中身を引っこ抜いたりするのに使います。
// -r オプションをつけると上書きインストールになります
adb install -r ${APKのパス}
adb: failed to open ${APKのパス}: Operation not permitted
許可がない。しかも、「署名が違うから入れられない」というありがちなエラーではない。
署名をしたけれど不正で、どうやら端末には入れられない、とのこと。
この現象に気づいたのが間の悪いことに、テスト開始前夜。
当社のテストは原則として、製品版相当の状態で確認を行うため、テスト担当の方に慌てて一時的にデバッグ版での確認をお願いすることとなりました…
原因:TargetSDK30から署名スキーマv2への対応が必須に
ところで、TargetSDK30対応を始める前に事前調査を行っていました。2021年の3月くらいに。
その中に、「署名スキーマv2が必須になる」という記載があったことを思い出しました。
APK署名スキームv2が必要(下位互換でv1も必要)
ちなみに、署名スキーマv2って何? という話なのですが、ものすごく大雑把に言うと、
いままでのアプリに付与していた開発者(あるいは配信者)の本人確認にプラスした情報が必要になるよということです。
詳細はこちら。
この署名スキーマv2は、API Level 24(Android 7.0)から対応していたそうです。
ただし、この問題が起きるのはAndroidStudioでAPKを作っていない場合です。
AndroidStudioを使っている場合は、minSdkVersionを見て、自動でこの署名の切り替えをしてくれているそうです。
だからbuild Valiantをreleaseにして実行していた時は、普通に実機で動いたのか…
解決:署名スキーマv2の署名を追加しよう
既存のJenkinsのジョブ設定にあるビルドと署名では実機インストールができないので、
対応しなくてはいけません。
ただ、幸運なことにいままで使っていたkeystore (署名のためのファイル)はそのまま使えます。
ちなみに、問題が起きたアプリの下限OSはAPI Level 23(Android 6.0)なので、署名スキーマv1の署名も必要です。
なので、方針としては以下の通りになります。
- いままで通りのビルド+署名を行う
- 署名スキーマv2を追加して署名する
Jenkinsのビルドシェルに、以下のコマンドを追加しました。
./apksigner sign -ks ${keystoreのパス} --ks-key-alias ${アプリのエイリアス} --v1-signing-enabled=true --v2-signing-enabled=true ${APKのパス}
でも、こんなコマンド1つで本当に、署名できてるの? と不安になるかと思います。
なので、検証もしてみましょう。
apksigner verify --print-certs -v [署名済みのAPKファイル]
このコマンドを叩くと、以下のような形で検証結果が出てきます。
v1スキーマとv2スキーマ両方がtrueになっていれば、対応成功です。
Verifies
Verified using v1 scheme (JAR signing): true
Verified using v2 scheme (APK Signature Scheme v2): true
※以下略
なお、この署名方法はTargetSDK30対応をしていなくても、特に問題なくインストールできることも確認しました。
さいごに
実装とか設定にばかり目が行きがちになりますが、ツールへの対応も忘れちゃいけませんね。。。
明日のCYBIRDエンジニア Advent Calendar 2021 5日目は、 @kappysan が担当します。
ありがとうございました。