nashcft's blog

時々何か書く。

Android: 新しいバージョンがリリースされる時の対応の流れに関する備忘録

何度か同じような内容を人に伝える機会に遭遇するなと思ったのでブログ記事にしてしまおう、ということで、 Android の新しいバージョンのリリースに対してどういう流れで対応を進めるかについての自分の考え方のメモ。

Android バージョンアップによって発生する変更

以下の3種類に大別できる:

  1. アプリの target API level にかかわらず、当該バージョンで動くデバイス上でアプリを動かす際に関係する変更
  2. アプリの target API level (= target SDK version) をその SDK に合わせた時、当該バージョンで動くデバイス上でアプリを動かす際に関係するもの
  3. SDKAPI 変更
    • Android framework の API の追加・変更・削除
    • Non-SDK interface restrictions の更新

バージョンアップ対応の進め方

まず自分の開発しているアプリへの影響について調査し、必要な対応タスクを上述の3種類に対応した3つのタスクグループとしてまとめる。着手は以下の優先順位で行う:

  1. "Behavior changes: all apps" 関連
  2. SDKAPI 変更 -> compileSdk を上げる
  3. "Behavior changes: Apps targeting Android XX" 関連 -> targetSdk を上げる

優先順位は実質的なデッドラインに当たるイベントに基づいている。つまり、1. に関しては新バージョンの final release, 2. は Jetpack などのライブラリが compileSdk を上げたリリースを行った時 (final release が行われてしばらく経ったくらい)、そして3. は Google Play の target API level requirements で要求されるようになったら (2024年現在の目安としては final release の翌年の8月末)、ということになる。

Final release 前後で全ての対応を完了できるならそのように進めるのが望ましいが、諸々の事情でもっとかかるみたいな状況になった場合は上記の優先順位とデッドラインをもとにいつからいつまでの間に取り組ませてほしいなど調整をしつつやっていくことになる。 Target SDK version を上げるための対応は素朴にデッドラインに合わせて計画を立てるとスケジュールが間延びしてダレがちなので、リリースされた年内で完了させられるように持っていきたいなと考えている。

なぜこういうことを考えるのか

主にはプロダクトオーナーとかプロジェクトマネージャーとかと計画づくりやスケジュール調整をする時に、どういう対応の段階があってそれぞれの対応が完了すると何がクリアになるかというのを共有するため。あとは何かしらの事情でスケジュール的に余裕がなくて、それぞれの対応に十分な期間や人員を確保しつつビジネス要望にも応えるには何がどの程度まで調整可能かみたいな相談というか交渉というかみたいなのが発生した時に必要になることもある。

Android: Photo Picker 近況

以下の記事を書いた後くらいから眺めていた photo picker 関連の issue についてのメモ。

nashcft.hatenablog.com

Photo picker から返却されるファイルの並び順

issue: https://issuetracker.google.com/issues/264215151

上記の記事でも言及した result で返ってくるファイルの順序が選択順ではない問題。こちらは Google Play の2024年2月のアップデートで修正され、 photo picker 上で選択した順序で返ってくるようになった。

選択ファイル数上限の指定タイミング

issue: https://issuetracker.google.com/issues/303112556

Photo picker で複数のファイルを選択する場合は registerForActivityResultPickMultipleVisualMedia を与えるが、現在選択可能なファイルの上限を指定するにはこの PickMultipleVisualMedia の constructor の maxItems で指定するため、 launcher を作成する時点で上限が固定される仕組みになっていた。

https://cs.android.com/androidx/platform/frameworks/support/+/a0eabef3092da562c3f9f7b95468b3c368ffee02:activity/activity/src/main/java/androidx/activity/result/contract/ActivityResultContracts.kt;l=826

この issue はこれに対して launcher で実際に photo picker を呼び出す際に上限を指定できるようにしてほしいというもので、以下の CL で対応され、 launch 時に渡すPickVisualMediaRequest を作成する関数に上限数を指定する引数が追加されたものが新たに実装された*1

CL: https://android-review.googlesource.com/c/platform/frameworks/support/+/3106768

この変更によって PickMultipleVisualMedia の constructor と PickVisualMediaRequest の二箇所で上限数を指定できるようになったが、実際に使われるのは2つのうち小さい方になる。

この変更は AndroidX Activity の 1.10.0-alpha01 でリリースとのこと。

Exif 情報の取得ができない

issue: https://issuetracker.google.com/issues/243294058

Photo picker 経由で取得したメディアファイルの exif 情報が取れなかったり、 MediaStore.setRequireOriginal を使うと permission 不足で SecurityException になるというもの。 MediaStore.ACTION_PICK_IMAGES のドキュメントによると photo picker で取得した URI には様々な制限があるとのこと。

Output: MediaStore content URI(s) of the item(s) that was picked. Unlike other MediaStore URIs, these are referred to as 'picker' URIs and expose a limited set of read-only operations. Specifically, picker URIs can only be opened for read and queried for columns in PickerMediaColumns.

developer.android.com

報告者の Google の人の会話で位置情報に関しては一応 feature request として受け止められたが、 intended behavior として close されてしまった*2

Close として処理されたが feature request として管理するための issue が作成された様子がないことからか、様々なアプリの開発者たちによる自分のアプリでのユースケースexif 情報を読み出せるようにすることの必要性についての投稿が続いていたところ、4月に突然 issue が reopen された。とはいえそこから何か表明があったり話が進んだりしたわけでもなく、状況については不明なままである。

オリジナルのファイル名が取得できない

issue: https://issuetracker.google.com/issues/268079113

Photo picker 経由で取得したメディアファイルのファイル名が数字の連番になっており、元々のファイル名が取得できないというもの。多分 exif 情報と同じような理由でマスクしているのだと思うが、こちらは特に対応の期待を感じさせるような話もないまま intended behavior として close された。

Google 製のアプリはどうしているのか気になって見てみたところ、 Gmail での画像添付ではマスクされたファイル名をそのまま使っていた。

所感

ポリシーの変更によって、来年からはアップロードのためのファイル選択のような用途でのメディアファイルへのアクセスには photo picker を使わざるを得なくなるはずなのに、機能面でアプリ開発者と足並み揃えられてないのまあまあ不安に思う。

*1:元々存在した関数の引数に追加せず別に関数を実装したのはバイナリ互換性を保つためとのこと。CL 内の関連する議論

*2:Google の人の回答が報告者の関心とやや噛み合っていないのも個人的に気になる

Android 15 で edge-to-edge が強制されるかもという話のメモ

何のこと?

www.androidauthority.com

この記事の途中に実装に関する言及があった:

[...], while I was digging through Android 14 QPR2 Beta 3, I discovered a new app compatibility change named EDGE_TO_EDGE_BY_DEFAULT with this description: “make app go edge-to-edge by default if the target SDK is VANILLA_ICE_CREAM or above.” Vanilla Ice Cream happens to be the internal dessert name for Android 15, which means this compatibility change will be applied to apps that target this year’s upcoming release.

じゃあどんな感じか見てみるか、となったので軽く目を通した。

実装とかのリンク

当該の compatibility change のフラグと追加された commit は以下:

あと現時点ではこれ関連だと以下の commit とか mDefaultEdgeToEdge が使われているあたりを見ておけば十分だろうか:

実装内のコメントを見るに SDK version 35 から入れるつもりでいると捉えて良さそうに思う。

おわりに

本当に Android 15 から有効になるなら、その内以下のページにリストアップされるだろう。とはいえこのレベルの挙動変更なら release note で言及されるとは思う。

developer.android.com

Android 13 で getSerializable/getParcelable の API 置き換えが発生して、でも getParcelable にはバグがあって、その後

Android 13 のリリースに関して以下のような Serializable / Parcelable の扱いがしんどいという話があった。この記事ではその後どうなったかについて簡単に記録しておこうと思う。

speakerdeck.com

先に結論を書いておくと、 AndroidX Core に compatible API が実装されたのでそれらを使えば OK という状況になった*1

スライドの要点

その後

Parcelable 向けの対応

https://issuetracker.google.com/issues/242048899 を読むと、実はスライド発表時点で Parcelable 関係の compatible API の対応については既に実装されていたことがわかる。ただしその時点では未リリースだったし、 issue の関連付けも行われていなかった*2。この変更は年が明けてすぐの 2023-01-11 に行われた AndroidX Core の 1.10.0-alpha01 でリリースされている。

Serializable 向けの対応

上記の Parcelable への対応に関する issue に以下の issue が Serializable 向けの feature request としてリンクされており、こちらでトラッキングされるものと思って見ていたが結局使われることはなかった。

その後以下の issue と CL が提出され、 Serializable についてはこちらで話が進められることになった。

この変更は 2024-01-10 に AndroidX Core の 1.13.0-alpha03 でリリースされている。なぜか release note に記載はない。

まとめ

  • AndroidX Core の BundleCompat, IntentCompat, ParcelCompat を使おう
    • Parcelable 取得の compatible API1.10.0 から
    • Serializable 取得の compatible API1.13.0 から

*1:Serializable に関しては AndroidX Core 1.13.0-alpha03 からなので 2024-03-31 時点で stable は未リリース

*2:NPE バグの報告 issue にはリンクされていた https://issuetracker.google.com/issues/240585930#comment6

Klock の今

Kotlin multiplatform 向け datetime ライブラリの Klock は昨年の8月にリリースされた 4.0.10 以降リリースされていないように見える。

参考: https://mvnrepository.com/artifact/com.soywiz.korlibs.klock/klock

実際は現在もメンテが継続されており、 korlibs-time という名前で公開されている。現時点で最新バージョンは 5.4.0

https://mvnrepository.com/artifact/com.soywiz.korge/korlibs-time

これは Klock が含まれる Kotlin 製ゲームエンジン KorGE の 5.0 開発段階で仕切り直し的な状況が発生しライブラリ群の構造が整理されたことによる。そのため 5.0.0 - 5.1.0 の間は korge-foundation という全部入りライブラリとして公開されていた。その後また機能毎に module をばらして公開するかということになり現在再び分離中という状況である。 korlibs-timekorlibs-template と共に 5.2.0 から独立した module としてリリースされた。

github.com

また、 Korlibs 系の module 群は project の構成をもっとシンプルにするために別の repository に移すかという計画も進められており、暫くしたらメンテは以下の repository で行われるようになると思われる。

github.com

github.com

余談

"仕切り直し的な状況が発生し" と書いたが、何があったかというと2023年の7月に KorGE の作者が引退宣言をし暫く有志によるメンテナンスモードになるということが起こっていた。

web.archive.org

https://github.com/korlibs/korge/blob/v4.0.10/README.md

In maintenance mode. Soywiz (the founder/primary lead/developer) has retired from maintaining this project (2023/07/27).
Currently this project is only being maintained by a handful of people who may/may not be as familiar with the architecture.
Do not expect any major updates in the future and expect less support if you do decide to use this project.
We are open for pull requests if there are any issues you'd like to fix yourself.

その後作者に心境の変化があったようで9月中頃から開発に復帰し KorGE 5 のロードマップを発表して KorGE 復活、という流れで現在に至る。

web.archive.org

前掲の記事2つは KorGE の公式ブログから削除されているので wayback machine から引っ張ってきている。

Dependabot: 設定の備忘録

最近 dependabot でライブラリ更新を自動化している repository の dependabot.yml を手入れしていたのでそのメモ。

Gradle: settings.gradle で依存取得先を設定している場合に更新検知できないライブラリがある

2024-02-19 追記

以下の修正によって dependencyResulutionManagement の設定は読まれるようになった:

github.com

追記おわり

Project の依存解決の設定を settings.gradledependencyResolutionManagementpluginManagement で記述している場合、一部のライブラリの更新検知ができないということが起こる。 Log を見てみると maven-metadata.xml の取得先として Maven Central (plugin の場合はこれに加えて Gradle plugin portal) しか参照しておらず、たとえば AndroidJetpack library など Google Maven Repository に配置されているライブラリはバージョン情報の取得に失敗していることがわかる。

# e.g. AndroidX Core
updater | YYYY/MM/DD hh:mm:ss INFO <job_xxxxx> Checking if androidx.core:core-ktx 1.12.0 needs updating
  proxy | YYYY/MM/DD hh:mm:ss [xxxx] GET https://repo.maven.apache.org:443/maven2/androidx/core/core-ktx/maven-metadata.xml
  proxy | YYYY/MM/DD hh:mm:ss [xxxx] 404 https://repo.maven.apache.org:443/maven2/androidx/core/core-ktx/maven-metadata.xml
updater | YYYY/MM/DD hh:mm:ss INFO <job_xxxxx> Latest version is 
updater | YYYY/MM/DD hh:mm:ss INFO <job_xxxxx> Requirements to unlock update_not_possible
updater | YYYY/MM/DD hh:mm:ss INFO <job_xxxxx> Requirements update strategy 
updater | YYYY/MM/DD hh:mm:ss INFO <job_xxxxx> No update possible for androidx.core:core-ktx 1.12.0

build.gradle で依存解決の設定を記述している場合は設定した repository が maven-metadata.xml の取得先に追加されていて期待通りにバージョン情報を取得できているので参照先の取得のために settings.gradle を読んでいないのだと思われる。 Dependabot のコードを何となく眺めた感じでもそうっぽい気がする。根拠にしてるのは以下のファイル:

github.com

これに関する issue はすでに報告されている:

github.com

以下の issue のコメントに workaround が示されており、 private package へアクセスするための設定に使われる registries にアクセスしたい maven repository について追記してそれを参照するようにすれば metadata の取得先に追加される。

github.com

docs.github.com

version: 2
# ↓を追加
registries:
  maven-google:
    type: maven-repository
    url: "https://dl.google.com/dl/android/maven2/" # https://docs.gradle.org/current/javadoc/org/gradle/api/artifacts/dsl/RepositoryHandler.html#google--
updates:
  - package-ecosystem: "gradle"
    directory: "/"
    # ↓を追加
    registries:
      - maven-google
    # ...

設定を追記した後の実行ログは以下のような感じ。 maven-metadata.xml の取得時のアクセス先に https://dl.google.com:443/dl/android/maven2/ が増えて、そちらで取得成功しておりバージョン情報の評価ができていることがわかる。

 updater | YYYY/MM/DD hh:mm:ss INFO <job_xxxxx> Checking if androidx.core:core-ktx 1.12.0 needs updating
   proxy | YYYY/MM/DD hh:mm:ss [xxxx] GET https://repo.maven.apache.org:443/maven2/androidx/core/core-ktx/maven-metadata.xml
   proxy | YYYY/MM/DD hh:mm:ss [xxxx] 404 https://repo.maven.apache.org:443/maven2/androidx/core/core-ktx/maven-metadata.xml
   proxy | YYYY/MM/DD hh:mm:ss [xxxx] GET https://dl.google.com:443/dl/android/maven2/androidx/core/core-ktx/maven-metadata.xml
   proxy | YYYY/MM/DD hh:mm:ss [xxxx] 200 https://dl.google.com:443/dl/android/maven2/androidx/core/core-ktx/maven-metadata.xml
 updater | YYYY/MM/DD hh:mm:ss INFO <job_xxxxx> Latest version is 1.12.0
 updater | YYYY/MM/DD hh:mm:ss INFO <job_xxxxx> No update needed for androidx.core:core-ktx 1.12.0

GitHub Actions: repository local な composite action 内で使用している action の更新検知をしたい

Repository 内で composite action を定義している場合、その中で使われている action の更新を検知するには / で設定しているのとは別にそれぞれの composite action に対して設定を書く必要がある。

参考:

qiita.com

version: 2
updates:
  - package-ecosystem: "github-actions"
    directory: "/" # これは .github/workflows/ 以下の yaml が対象になる
    # ...
  - package-ecosystem: "github-actions"
    directory: "/.github/actions/my-action1"
    # ...
  - package-ecosystem: "github-actions"
    directory: "/.github/actions/my-action2"
    # ...

directory の指定にワイルドカードを使えるようにする feature request はあるにはあるけど何年も動いてないのであまり期待できなそう:

github.com

おわりに

セットアップまで含めて Renovate 使うのとどっちが楽なんだろ

READ_MEDIA_IMAGES と READ_MEDIA_VIDEO の使用に制限がつくらしい

API level 33 からアプリ外のメディアファイルへのアクセスに必要な permission として READ_MEDIA_IMAGES, READ_MEDIA_VIDEO, READ_MEDIA_AUDIO が追加された*1が、これらの内 READ_MEDIA_IMAGESREAD_MEDIA_VIDEO の使用に関するポリシーの追加が 2023-10-25 付で発表されていた。

support.google.com

更新されたポリシーの preview は以下のページから確認できる。

support.google.com

これらのページによると、画像や動画のデータは "personal and sensitive user data subject to Google Play's User Data policy" であるためあまり無闇に対象となる permission を使わせないようにしたいので、デバイス上の画像や動画への広範なアクセスがアプリの主たる機能に直接関係するような場合だけこれらの permission を要求していいことにするよ、そのために READ_MEDIA_IMAGESREAD_MEDIA_VIDEO を要求するアプリに関しては使用が妥当なものかを審査するよ、とのこと。また、ファイル選んでアップロードするみたいなユースケースは上記の審査には通らないので system で提供している photo picker を使って permission 無しでのアクセスをするようにしてほしいということだそう。細かい話は以下のヘルプページの FAQ で色々書かれているのでそちらを確認してほしい。

support.google.com

スケジュール的にはだいたい来年中に対応を済ませましょうという感じ。

メジャーな対応ケースとしては、アプリに画像や動画の投稿・アップロード機能があって、そのために自作の picker を使っているとかで API level 33 以上で当該 permission を要求している場合に、 picker を Android が提供している photo picker に置き換えて permission 要求の記述を削除するというものになるだろう。 Photo picker の使い方は activity result contract を作って投げるだけで簡単なので、公式ドキュメントに目を通せばその他の事項含めて割とすぐに置き換えることはできると思う。

developer.android.com

余談だが複数選択をした際に photo picker から返ってくるファイルの順番が選択順ではないので、それだと困るという人は以下の issue に vote しておくと早く対応してくれるかもしれない。