こんにちは!または初めまして!
開発部第1グループ、Android担当の沓名です。
毎年11月は、Google Playの対象APIレベルの引き上げの時期ですね。
Androidアプリケーションエンジニアは毎年、これを意識しながら開発を行っているものかと思います。
今年の11月に対象APIレベルが31に引き上げになったので、その対応で、対応内容や苦労した点をこちらで紹介させていただきます。
APIレベルの引き上げとは
まず、APIレベルの引き上げとは何か、ということですが、Androidアプリのプロジェクトで設定しているtargetSdkVersionという項目を指定されたバージョン以上にしておかないと、アプリをGoogle Play上にリリースしたりアップデートしたりが出来なくなる、というものです。
毎年Androidの新バージョンがリリースされるのに伴い、このバージョンも毎年引き上げが行われます。
なので、プロジェクトのtargetSdkVersionをGoogle Playの対象APIレベルと同一にしている場合は、毎年これを上げる作業が必要、ということですね。
targetSdkVersionとは
targetSdkVersionとは、「アプリが動作するように設計されている API レベル」です。(参考:https://developer.android.com/guide/topics/manifest/uses-sdk-element?hl=ja#uses)
「そのレベルの機能を使ってアプリを開発するよ」という感じですね。
例えば、今までtargetSdkVersion 30を使っていたけど、今回からtargetSdkVersion 31にするよ。とバージョンを上げた時、
「API Level 30にはあったけどAPI Level 31から消えた機能」は使えなくなりますし、
「API Level にはあってAPI Level 31にもあるけど記述の仕方が変わった機能」はバージョンに合わせて該当箇所を修正する必要があります。
「API Level 30にはあってAPI Level 31にもあるけど記述の仕方が変わった機能」はバージョンに合わせて該当箇所を修正する必要があります。
ただバージョンの数値を上げるだけでは済まないことが多いです。
対応した内容
今回、とある既存プロジェクトのtargetSdkVersionを31に上げたのですが、ビルドが通って正常に動作させることができるようになるため大変な苦労がありました。
その具体的な内容をまとめます。
基本的な対応
- targetSdkVersionを31に上げる
- AndroidManifest内でIntentFilterがある項目についてexported=trueを追加(targetSdkVersion 31から必須対応)
- アプリ内のPendingIntentの記述を修正(targetSdkVersion 31から必須対応)(参考:https://developer.android.com/about/versions/12/behavior-changes-12?hl=ja)
- ライブラリについてもtargetSdkVersion 31に対応されているものを使う必要があるので、該当ライブラリをバージョンアップ
ここまでやって、ビルドは通ったがインストール時にアプリがクラッシュ
想定外の対応
- とあるライブラリのバージョンを上げたら、Kotlinのバージョンを上げないとビルドが通らなくなった
- Kotlinのバージョンはしばらく上げておらず、1.3.72から1.6.0のバージョンアップ
- Kotlinのバージョンを上げたら他のライブラリ(kapt関連: room, dagger2, moshiなど)が正常に動かなくなり、連鎖的に他のライブラリのバージョンアップが必要に
- androidx.lifecycleもバージョンが古く動かなくなったため、バージョンアップ、それに伴う記述の修正
難読化(ProGuard周り)の対応
- ビルドは通り、アプリインストール時にクラッシュしないようにはなったが、リリースビルドアプリが正常に動作しない(ログイン状態が維持出来ないなど)
- 難読化(ProGuard)周りが怪しいと当たりをつけ、調査
- moshiのバージョンアップにより、ProGuardの記述方法が変わったことが判明(参考:https://github.com/square/moshi/issues/717)
- 具体的には、jsonコンバート対象のオブジェクトクラスを難読化対象から外すことが必須となった
- 起動/ログイン済みの旧バージョンアプリでは、すでに難読化された情報をアプリで保持しているため、そのままアプリを起動するとクラッシュする
- コンバート対象のオブジェクトを難読化対象から外してアプリをビルドすると、「旧アプリ:難読化済み情報」「新アプリ:非難読化情報」という不整合が発生し、ログイン状態などが維持できない(コンバートの時点で失敗してnullになる)
- クラッシュしないようmoshiではなく、もう一つのメジャーなJsonコンバートライブラリであるGsonを使ってコンバートするよう試したところ、上手くいった
- Jsonコンバートライブラリはmoshiが推奨されているが、今回に限りはどうしようもないのでGsonを許容することに
- moshiのバージョンアップにより、ProGuardの記述方法が変わったことが判明(参考:https://github.com/square/moshi/issues/717)
- 難読化(ProGuard)周りが怪しいと当たりをつけ、調査
苦労した点
このバージョンをあげたらあのバージョンをあげろと怒られ、を繰り返して結果的にtargetSdkVersionだけでなくKotlinやライブラリのバージョンをあげさせられ、ソースコードの修正にProGuardファイルの修正まで必要になりました。
一番の原因はKotlinのバージョンをしばらくあげていなかったことに起因しています。
言語のバージョンアップは想像以上に影響が大きい、ということですね。
まとめ
- targetSdkVersionのバージョンアップは引き上げは数値を上げるだけで終わることは稀
- 言語のバージョンアップは影響範囲が非常に大きいので、こまめに確認したほうが良い
- ライブラリのバージョンも放置しすぎるといざ上げたときに調査が必要になるので、こちらもこまめに確認したほうが良い
- リリースビルドアプリでのみ発生する不具合はProGuardを疑う、日頃からリリースビルドアプリでの動作確認を行っていると安心(リリース直前に判明しがち)
参考URL
- Android での API レベルの使用
- 動作の変更点: Android 12 をターゲットとするアプリ
- Kotlin data class with Retrofit2 ProGuard #717