Android 11 Labs Day2 のまとめです。
今日の話題
Scoped Storage
- ストレージのスコープ化についての最新情報
App compatibility framework & non-SDK interface
- 非公開 API の利用制限
- アプリ互換性の向上のために
Selected new features
- IME 体験の向上
- variable framerate
- Process termination stats
Scoped Storage
ストレージのスコープ化についての最新技術情報
Android10でも導入されていましたが、Andorid11で変更があったのでそちらについてお話ししていきます。
Android 10 より前
Storage Permission があれば他のアプリのデータにもアクセスが出来ていました。
Android 10
メディアデータの領域とそれ以外の領域に、外部ストレージの領域を分けました。メディアデータ以外の領域については、他のアプリからアクセスが出来なくなった。これにはファイルの持ち主は誰か、というのをはっきりさせるという意図があります。
典型的な例だと、PDFに個人情報(確定申告や給与明細の情報など)が含まれていた場合。これを他のアプリに勝手に読まれるという事態が起きないようにシステムの方で設計したのが Scoped Storage というものです。
もう少し詳しく見ると、
- Media と Downloads フォルダにファイルを書く事は出来ました。
- Storage Permission で読み込めるのは Media フォルダだけです。
- 他の領域については Picker 経由でユーザーに選んでもらう事で(ユーザーの同意を得て)ファイルアクセスをさせます
というのが Android 10 の Scoped Storage。
ただし、 Android 10 ではこの機能をオプトアウト出来ました。
Android 11
一番大きな変更点は、機能のオプトアウトが出来なくなったという事です。
それ以外に、ストレージのAPI、メディアを扱うための MediaStore のAPIにいくつかの変更点が加わっています。
Storage & MediaStore の変更点
- Storage Permission の名前が Files & Media に変更になりました。
WRITE_EXTERNAL_STORAGE
&WRITE_MEDIA_STORAGE
のパーミッションの振る舞いが変わります。権限を貰っても読み書きの領域が変わりません。
(Mediaは権限を貰わなくても読み書き可能、External Storage はそもそも読み書きが出来ないため)- bulk access (複数のファイルにまとめてアクセス) が可能になりました。
Android 10 では Media への
- ネイティブライブラリからのアクセス
- パスを使った直接的なアクセス
が出来ませんでしたが、 Android 11 では可能になりました。
ただし、I/Oパフォーマンスが遅いです。また、バッテリー消費面でも問題がありますので、通常は MediaStore によるアクセスを推奨します。
File Access について
Android 10 以前では ACTION_OPEN_DOCUMENT_TREE
という Intent を使う事でディレクトリ構造の取得が出来ましたが、Android 11 からはそれが出来なくなります。
root や Download フォルダ、 Android フォルダ以下の data, obb フォルダにもアクセスできなくなります。
[ACTION_OPEN_DOCUMENT_TREE]root <- NG!
├ Download <- NG!
└ Android
├ data <- NG!
└ obb <- NG!
また、 ACTION_OPEN_DOCUMENT
で Picker を使って利用者にファイルを選ばせる事もできますが、この時も他のアプリが管理している data, obb フォルダにはアクセスできません。(Download にはアクセス可能)
[ACTION_OPEN_DOCUMENT]root
├ Download
└ Android
├ data <- NG!
└ obb <- NG!
特別なアクセス権
- ファイルマネージャ
- ファイルのバックアップ & リストア
といった機能を持つアプリ向けに、特別な権限が追加されました。(Manage External Storage)
これを使うと、外部ストレージを全て読むことができます。
ですが、これには厳しいガイドラインが設定される予定です。
App compatibility framework & non-SDK interface
アプリとゲームの互換性における非公開 API の利用制限
前提:可能な限り、公開 API のみを利用して欲しいです。
しかし、非公開 API を利用しているデベロッパーはたくさんいます。Googleは API を壊して、アプリが動かなくならないように努力しています。
しかし、昔から存在しているバグや昔からの挙動に依存する API が数多く存在し、Google はそれらを修正したいという気持ちがあります。
そのために、Android 10 では、非公開 API の BlackList を公開させて頂きました。
Android 11 では新しく LightGreyList、DarkGreyList を紹介させて頂きます。
LightGreyList に含まれている API は、様々なアプリに利用されていることが分かりました。現在は BlackList に移動する事は考えていませんが、将来的に移動する可能性はあります。
DarkGreyList に含まれている API は、Android 11 以降を target (targetSdkVersion = R)としている場合は、もう起動できません。
ただし、Android 10 以下を target にしているアプリは、まだしばらくの間使えます。
具体的にどの API が WhiteList / LightGreyList / DarkGreyList / BlackList であると判断するか?
- WhiteList … 公開されている API
- BlackList … 全てのデベロッパーが利用していないと思われる API
- LightGreyList, DarkGreyList … 世の中のデベロッパーが利用していると思われる非公開 API
LightGreyList と DarkGreyList の主な違い
DarkGreyList に入っている API には、代わりに同じ挙動、もしくは似たような挙動を提供する API が WhiteList に存在しています。
LightGreyList に入っている API には、代わりとなる API がまだ存在していません。
Googleはどうやって LightGreyList, DarkGreyList, BlackList に API を入れるのか?
Googleの基本的な考え方は、あまり利用されていないメソッドから始めます。こちらは可能な限り BlackList に入れるか、 DarkGreyList に入れます。
BlackList, DarkGreyList に入れる API を利用しているデベロッパーには、可能な限り連絡するようにしています。
最後に、なぜその API が利用されているかを理解し、同じ挙動、似たような挙動を提供する 公開API を作るのがGoogleの責務です。
Annotaion
プログラム側から、どのAPIがどのListに入っているかをアノテーションで判断できます。
- LightGreyList …
@UnsupportedAppUsage
- BlackList …
@UnsupportedAppUsage(maxTargetSdk = 0)
- DarkGreyList …
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.X)
(targetSdkVersion <= X で利用可能)
Android 10 -> 11 での変更点
約 2000 API -> LightGreyList 入り
約 800 API -> DarkGreyList 入り
約 900 API -> BlackList 入り @TestApis
アノテーションが付いている API は BlackList 入りしています。
新しく公開された全ての @TestApis
は BlackList 入り
全ての @SystemApis
も基本的に BlackList 入り
アプリが非公開 API を利用しているかを知る方法
以下の方法を利用してアプリが非公開 API を利用しているかどうか知ることができます。
- デバッグアプリでテストするとデバッグログに警告が出力される
- Play Console にアプリをアップロードする
- Android Studioの lint ツールを使う
- StrictMode API を利用する or veridex tool を使う
Compatibility Framework
新しい機能について、機能単位で有効化/無効化を切り替えられる機能。
機能を切り替える方法は、以下の2つの方法が存在します。
- 設定画面のトグルを切り替える方法
- ADB から以下のコマンドを使う方法
adb shell am combat enable|disable|reset <CHANGE_ID|CHANGE_NAME> <PACKAGE_NAME>
具体的にどういった機能を有効・無効にできるかのリストを取得するには
adb shell dump sys platform_compat
で知ることができます。
そのほかの新機能
IMEの体験向上
今までIMEは勝手に現れて、勝手に消えていましたが、もっと自由にコントロールできるようになりました。
- IMEの状況が変わった時に呼び出されるCallbackの追加
- IMEの表示を細かくコントロールするためのAPIの追加
WindowInsetsAnimation.Callback
IMEの表示変更が
- 始まる前
- 始まった時
- 表示変更している最中
- 表示変更が終わった時
の時のCallbackが追加されました。
WindowInsetsAnimationControlListener
IMEの表示方法を細かくコントロールできます。
Android11のサンプルコードにあるチャットアプリでは、IMEの表示を細かく指でコントロールする方法を紹介しています。
setFrameRateの追加
フレームレートを設定可能になりました。高いフレームレートを設定するとバッテリーの消費が激しくなる可能性があるので、必要な時だけ使うことを推奨します。
アプリの終了ログの取得
アプリがクラッシュしてしまった後、アプリを再度起動した時に、プロセスが終了した際の細かい情報を取得できます。
質疑応答
Q: いわゆるファイルマネージャー的なアプリは今後作ることができなくなるのでしょうか?
A: できます。ファイル全体を管理する権限というものができる。ただ、その権限を利用する正当な理由は求められると思います。(現在こちらで情報は持っていないが)今後公開されるガイドラインに沿っていることが重要になります。
Q: 他のアプリから読めなくするという目的であれば他にも手段があると思います。
センシティブな情報を暗号化する仕組みやセンシティブな情報を保存する場所を設けるなど。
それらの手段ではなく、外部ストレージ全体を制限するという仕様を選択した理由をお聞かせください。
A: 確かにそういう選択肢もあると思います。なぜそちらの方法を選ばなかったかという答えは私は持っていません。
フィードバックとしては理解できています。そのようなフィードバックがあったという事はプロダクトに伝えます。
これは自分の理解ですが、ファイルがあった時、これを誰が作ったのか、という所有権が曖昧なままになっているのが現在なので、その所有権をハッキリさせたかったというのが一つの要因ではないかと想像しています。
Q: 非公開APIを使っているアプリをPlayで公開し、その後そのAPIがブラックリストに入った場合、リジェクトとなる事はあるのでしょうか?
A: ホワイトリスト・ブラックリストは、APIレベルが設定された時にしか適用されません。ビルドした時に検知されます。
Google PlayにアップロードしたapkのAPIレベル( = targetSdkVersion)で判定されるため、リジェクトされる事はありませんが、Google Playのポリシーとして、毎年古いAPIレベルは使えなくなっているので、アプリを更新しようとした時に、(APIレベルを更新した場合は)それぞれのAPIレベルに応じたホワイトリスト・ブラックリストに対応していただく必要があります。
Q: 非公開ではなく非推奨になったAPIについてはどのように考えているのかを教えてください。
A: 非推奨になったAPIというのが具体的にどのAPIを指すのかが分かってから、具体的にお答えしたいですが、「プライバシーに関わる非公開API」については WhiteList / LightGreyList / DarkGreyList / BlackList というシステムを作りました。
しかし、プライバシーとは関係なく、公開APIではあるが、(例えば暗号化APIで、直接暗号化APIを使うのではなく、暗号化フレームワークを推奨しているという場合、ブラックリストに入ったりはせず)
、使いにくいので暗号化フレームワークを使ってくれ、という案内になるのではないかと思います。
このあたりは非推奨APIの資料を見て、なぜ推奨されていないのかを確認いただいてご判断頂くのが良いのではないかと思います。
補足:あとはAPIバージョンが古いものは非推奨になっていくのかなという感じはします。
非推奨になっている場合は「推奨API」があるはずなので、そちらで対応して頂くのが良いと思います。完全にケースバイケースになるとは思います。
Q: Android11での動作確認は targetSdkVersion も R にして行うのがおすすめなのでしょうか。
のちのち targetSdkVersion を R にする対応も必須かと思いますが、同じタイミングで行う方がよいのでしょうか。
A: targetSdkVersion を最新にするのはGoogleは推奨しているので、早めに targetSdkVersion を R にしていただいて、アプリをビルドできるか、どのような互換性の問題が出ているのか確認して、それぞれの対策方法を考えて頂くのが良いのではないかと思います。
targetSdkVersion = R となっていた場合でも、Android 10 でも動かないわけではないので、互換性の問題がなければ targetSdkVersion を最新にしない理由はあまり無いと思うので、いつも最新にすることを推奨します。
補足:挙動が変更になるAPIの中には targetSdkVersion = Rにした場合に初めて変更になるAPIも存在しています。問題が起こらないかどうか、早くに社内で動作確認するという意味では早く targetSdkVersion = R にするというのが方法の一つだと思います。
ただ、それを製品版に反映するかどうかというのは別の判断になるかと考えている。
社内検証用に targetSdkVersion = R にするタイミングと、製品版を targetSdkVersion = R にするタイミングは別に検討いただくと良いのではないかと思います。
Q: 4月に入ってGoogle Play Developer Program Policy Updateがありました。
その中に、ファミリー向けアプリに対するポリシー変更や位置情報のポリシー変更がありました。
このような開発者に影響する情報も、今回のようなイベントで情報共有して欲しいです。以前ならばAPP DOJOでフォローいただいてました。
A: このようなポリシーは年を通じて定期的にアップデートがあります。4月は特に大きなアップデートがありましたので、確かに今回のようなフォーマットで扱う事ができれば、僕らとしても是非検討していきたいと思っています。また、フォーマットは違うが、今回のポリシーアップデートを担当したチームの社員が短いビデオを作って日本語で公開する準備をしているので、近々ご案内できると思います。
Q: scoped storage 未対応のアプリが対応するにあたっての best pradctice のようなものはありますでしょうか?(既存のデータをどうするべきか)
A: 必要なのは非常にわかります。とはいえ答えるのが非常に難しい質問だなぁと思います。なぜ難しいかというと、(まず大前提としてはscoped storageに移行してくださいというのがあった上で、)どんなファイルをアプリ間で共有しているか、どういう風にストレージを使っているかというのは個別のアプリで異なると思うので、ベストプラクティスと作りたいという気持ちはあるけれども、僕らの方に良い Use Case が溜まっていないというのも確かなので、どんな風に移行すれば良いかお困りの場合は、Google 社員にご連絡いただいて、一緒に考えていければと思っております。ご連絡お待ちしております。
Q: 同じ開発者が作ったアプリ間でファイルを共有する方法はありますか?
例えば前作のゲームのセーブデータファイルを、続編でも読み込んで引き継ぎを行いたい場合などでしょうか。
A: 現在、僕の方にパッとお出しできる案は無いです。バックエンドにデータを持っておくとかは出来るのかなとは思うのですが、相談しながら方法を考えていければと思っています。
補足: ローカルのファイルを直接共有するというのが結構危険かもしれないと考えられるんですけれども、ロドリゲスさんご意見ありますか。
ロドリゲス: Google 社内でもアプリ同士の情報連携をどのようにすれば良いのかは課題となっています。確かにこういうゲームなどの Use Case は出てきていますので、一つ言えるのは、現在のベータ段階での方針は先ほどお話しした方針ですけれども、最終的に変わる可能性もありますので、少々お待ちください、としか言えない。
しかしこの Use Case に関しては Google としては知っています。
Q: TimePickerのカスタマイズ(時間を5分間隔にしたいようなケースなど)はこれまでのノウハウがリフレクションを行う方法しかありませんでしたが、今回の非公開APIの禁止により利用不可となりました。
今後、公式のウィジェットのカスタマイズ方法は公式で提供される事はありますでしょうか?
A: 現在答えられない。フィードバックを伝えます。
Q: ユーザーがUSB経由で任意に転送したファイルは Document, Download, またはメディア以外の場所に転送した場合、アプリからは扱えなくなるという事でしょうか?
A: そうです。
一方で、ユーザーにUSBで任意の場所にファイルを転送させて使うという Use Case が何があるのか、という事が興味があります。1つ考えられるのはレストアやバックアップですが、そういった場合はストレージ全体に対するアクセスが必要なので、先ほど申し上げたストレージ全体を管理する権限を取っていただければ、それを使っていただくとやりたい事は達成できるのかなと思います。
これ以外の使い方になりますと、そのような Use Case が想定されていないと思うので、ご連絡ください。一緒に考えていきましょう。
Q: Appが終了した理由をRing Bufferに入れてくれるとの事ですが、最新のFirebaseを利用するとこの部分のLogも自動的に収集される機能が入っていたりしますか?
A: いまご紹介しているAPIはアプリのOSレベルのAPIとなっていますので、Firebaseがこのシステムを導入するかどうかについては、今お答えする事はできません。わかりません。
このAPIをご紹介した目的は、Crashlytics をはじめとする、サードパーティの重いパッケージを導入していただかなくても、最低限の簡単なクラッシュ情報をアプリから直接取得できるという事ですので、ぜひ使ってみてください。
Q: ACTION_OPEN_DOCUMENT_TREEで初期表示されるフォルダを指定できるようにできないでしょうか。
A: フィードバックありがとうございます。チームにシェアします。意図や用途をご連絡していただけるとフィードバックが捗ります。
Q: 新しいAPIのAndroid5.0などで使えるAndroid JetpackなどでのCompatibilityライブラリの提供の予定はあったりしますか?
A: Jetpackに対するご要望という事で、フィードバックを伝えます。
Q: SAFではドキュメントしか扱えなくなるようですが、DownloadにもアクセスできなくなるとPDFなどのドキュメントはどこで読み書きするようになるのでしょうか?
また、既存のデータはアプリがアプリの責任で引っ越しをしなければならないのでしょうか?
A: 1つ目。自分がダウンロードしてパス(URI)を知っているものであれば読めるはずです。また、アプリ自身のストレージに格納したものも読み書きできます。
パスを知らないもの(ex: Chromeからダウンロードしたファイル)についてフォルダ内を探索して読み書きは行えない、という認識です。
2つ目。そうですね。アプリの責任で引っ越しをしてください。
Q: 画像などのメディアファイルとその他のファイルでアクセスする仕組みを分けるには何か理由があるのでしょうか?
具体的にはMediaStoreとStorage Access Frameworkに分離している意図です。
A: メディア、特に写真は、撮ったら人と共有したいなどの使われ方も多いと思うので、単純にファイルではなく、メディアはメディアで切り出した方が使い勝手が良かったのかなと想像しています。メディアファイルとその他のファイルは質的に異なる面も多いので、切り分けできるのかなと思っています。
質問の意図が分からないのでとっ散らかった回答になりますが…
Q: Process Terminationは強制終了、異常終了のみのイベントしか取れないのか、またログの格納先はexternalなのかsystemのどちらに格納されるのでしょうか?
A: アプリが正常に終了したとか、アンインストールされたなどの情報も定義されていますので、結構細かく情報を取得できます。
また、ログについては、APIからしか取得できません。直接アクセスはできません。
Q: Scoped Storageが有効な状態で、ACTION_VIDEO_CAPTUREで動画の撮影をしようとした時、EXTRA_OUTPUTで出力先のuriを指定すると、Pixelのカメラアプリで動画撮影後、確定せずに再撮影するとクラッシュします。
他に必要なオプション等、原因として何か思い当たるところはありますでしょうか。
A: すみません、今は何も思いつかないので、色々検証していけたらと思います。Pixelだけで起きるのか、他の端末でも起きるのかなど、ご連絡いただければと思います。
Q: ライトグレーリストで、OSアップデート時に使えなくなる可能性はあるのでしょうか。
ホワイトリストになかったのに1年後に切り替えると同様なAPIに変更する際に大幅な改修が必要になると思いますが猶予はあるのでしょうか?
A: ホワイトリスト・ライトグレーリスト・ダークグレーリストはOSで定義されているのではなく、APIレベルで定義されています。なので、OSがアップデートされていきなり使えなくなった、という事はありません。
これはアプリをビルドしたときに選択したAPIレベルに応じたホワイトリスト・ライトグレーリスト・ダークグレーリストが適用されます。
なので、ご質問のようなシナリオが発生する事は無いのでご安心ください。
以上になります。