Android 12 プラットフォームには、アプリに影響する可能性がある動作変更が含まれています。下記の動作変更は、targetSdkVersion
に関係なく、Android 12 上で稼働するすべてのアプリに適用されます。該当する場合は、アプリをテストし、必要に応じて修正して、適切に対応してください。
Android 12 をターゲットとするアプリにのみ影響する動作変更のリストも必ずご確認ください。
ユーザー エクスペリエンス
ストレッチ オーバースクロール効果
Android 12 以降を搭載したデバイスでは、オーバースクロール イベントの視覚的な動作が変更されます。
Android 11 以前では、オーバースクロール イベントによって視覚要素にグローが表示されます。Android 12 以降の場合、ドラッグ イベントでは視覚要素がストレッチして元に戻り、フリング イベントではフリングして元に戻ります。
詳しくは、スクロール操作のアニメーション化に関するガイドをご覧ください。
アプリのスプラッシュ画面
Android 11 以前でカスタム スプラッシュ画面を実装している場合は、それが Android 12 以降でも適切に表示されるよう、アプリを SplashScreen
API に移行する必要があります。アプリを移行しない場合、アプリの起動時にエクスペリエンスの低下や予期しないエクスペリエンスが生じる可能性があります。
手順については、既存のスプラッシュ画面の実装を Android 12 以降に移行するをご覧ください。
また、Android 12 以降では、新しい Android システムのデフォルトのスプラッシュ画面が、すべてのアプリのコールド スタートおよびウォーム スタートに常に適用されます。システムのデフォルトのスプラッシュ画面は、デフォルトでは、アプリのランチャー アイコン要素とテーマの windowBackground
(単色の場合)を使用して作成されます。
詳しくは、スプラッシュ画面デベロッパー ガイドをご覧ください。
ウェブ インテントの解決
Android 12(API レベル 31)以降、一般的なウェブ インテントは、そのウェブ インテントに含まれる特定のドメインについてアプリが承認されている場合のみ、アプリのアクティビティに解決されます。アプリがそのドメインに対して承認されていない場合、ウェブ インテントは代わりにユーザーのデフォルトのブラウザアプリに解決されます。
アプリの承認は、次のいずれかの方法で行います。
Android アプリリンクを使用してドメインを検証する。
Android 12 以降をターゲットとするアプリでは、アプリの Android アプリリンクを自動的に検証する方法が変更されます。アプリのインテント フィルタで、
BROWSABLE
カテゴリが設定され、https
スキームがサポートされていることを確認します。Android 12 以降では、アプリの Android アプリリンクを手動で検証し、更新されたロジックがアプリに及ぼす影響をテストできます。
システム設定でアプリをドメインに関連付けるようユーザーにリクエストする。
アプリがウェブ インテントを呼び出す場合は、ユーザーにアクションの確認を求めるプロンプトまたはダイアログを追加することをご検討ください。
ジェスチャー ナビゲーションの没入モードの改善
Android 12 では既存の動作が統合され、ユーザーが没入モード時にジェスチャー ナビゲーション コマンドを実行しやすくなりました。さらに、Android 12 ではスティッキー没入モードの下位互換性が確保されています。
Display#getRealSize と getRealMetrics: 非推奨と制約
Android デバイスには、大画面、タブレット、折りたたみ式など、さまざまなフォーム ファクタがあります。各デバイスでコンテンツを適切にレンダリングするには、アプリで画面またはディスプレイのサイズを判断する必要があります。Android では、この情報を取得するためのさまざまな API が提供されてきました。Android 11 では WindowMetrics
API が導入され、以下のメソッドが非推奨となりました。
Android 12 では引き続き WindowMetrics
の使用を推奨し、以下のメソッドが非推奨となっています。
Display API を使用してアプリの境界を取得する動作を軽減するために、Android 12 は、完全にサイズ変更可能ではないアプリに対して API から返される値を制限します。これにより、MediaProjection
でこの情報を使用しているアプリに影響が出る可能性があります。
アプリは、WindowMetrics
API を使用してウィンドウの境界をクエリし、Configuration.densityDpi
を使用して現在の密度をクエリする必要があります。
旧バージョンの Android との互換性を高めるために、Android 4.0(API レベル 14)以降をサポートする WindowMetrics
クラスが含まれる、Jetpack WindowManager
ライブラリを使用できます。
WindowMetrics の使用方法の例
まず、アプリのアクティビティが完全にサイズ変更可能であることを確認します。
アクティビティは、UI 関連の処理(特に WindowManager.getCurrentWindowMetrics()
や Jetpack の WindowMetricsCalculator.computeCurrentWindowMetrics()
)では、アクティビティ コンテキストの WindowMetrics
に依存する必要があります。
アプリで MediaProjection
を作成する場合は、プロジェクター アプリが実行されているディスプレイ パーティションをプロジェクションがキャプチャするため、境界を正しいサイズにする必要があります。
アプリが完全にサイズ変更可能な場合、アクティビティ コンテキストは次のように正しい境界を返します。
Kotlin
val projectionMetrics: WindowMetrics = activityContext .getSystemService(WindowManager::class.java).maximumWindowMetrics
Java
WindowMetrics projectionMetrics = activityContext .getSystemService(WindowManager.class).getMaximumWindowMetrics();
アプリが完全にサイズ変更可能ではない場合は、WindowContext
インスタンスからクエリを実行し、WindowManager.getMaximumWindowMetrics()
または Jetpack メソッド WindowMetricsCalculator.computeMaximumWindowMetrics()
を使用して、アクティビティの境界の WindowMetrics
を取得する必要があります。
Kotlin
val windowContext = context.createWindowContext(mContext.display!!, WindowManager.LayoutParams.TYPE_APPLICATION, null) val projectionMetrics = windowContext.getSystemService(WindowManager::class.java) .maximumWindowMetrics
Java
Context windowContext = context.createWindowContext(mContext.getDisplay(), WindowManager.LayoutParams.TYPE_APPLICATION, null); WindowMetrics projectionMetrics = windowContext.getSystemService(WindowManager.class) .getMaximumWindowMetrics();
マルチウィンドウ モードのすべてのアプリ
Android 12 では、マルチウィンドウ モードが標準の動作です。
画面が大きい(画面幅 600 dp 以上)場合は、アプリの設定にかかわらず、すべてのアプリでマルチウィンドウ モードがサポートされます。resizeableActivity="false"
でディスプレイ ディメンションに合わせるために必要な場合は、アプリが互換性モードになります。
画面が小さい(画面幅 600 dp 未満)場合は、システムによりアクティビティの minWidth
と minHeight
がチェックされ、マルチウィンドウ モードで実行可能かどうかが判断されます。resizeableActivity="false"
の場合は、幅と高さの最小値にかかわらず、アプリはマルチウィンドウ モードで実行されません。
詳しくは、マルチウィンドウのサポートをご覧ください。
大画面でのカメラ プレビュー
一般にカメラアプリでは、デバイスの向きとカメラ プレビューのアスペクト比の間に一定の関係があることが想定されています。しかし、折りたたみ式デバイスなどの大画面フォーム ファクタや、マルチウィンドウやマルチディスプレイなどの表示モードには、その前提が当てはまりません。
Android 12 では、特定の画面の向きを要求する、サイズ変更できないカメラアプリ(resizeableActivity="false"
)は自動的にインセットの縦向きモードになり、カメラ プレビューの適切な向きとアスペクト比が維持されます。カメラの Hardware Abstraction Layer(HAL)を備えた折りたたみ式デバイスやその他のデバイスでは、カメラセンサーの方向を補正するために、カメラ出力に追加の回転が適用されます。アプリのカメラ プレビューのアスペクト比に合わせて出力がトリミングされます。トリミングと追加の回転によって、デバイスの向きやデバイスの折りたたみ / 展開状態に関係なく、カメラ プレビューが適切に表示されます。
フォアグラウンド サービス通知の UX の遅延
短時間実行されるフォアグラウンド サービスのエクスペリエンスを簡素化するため、Android 12 以降を実行するデバイスでは、特定のフォアグラウンド サービスについて、フォアグラウンド サービス通知の表示を 10 秒間遅らせることができます(少数の例外があります)。この変更により、通知が表示される前に存続時間の短いタスクを完了する機会が与えられます。
パフォーマンス
アプリ スタンバイ バケットの制限
Android 11(API レベル 30)では、アプリ スタンバイ バケットとして制限付きバケットが導入されました。Android 12 以降、このバケットはデフォルトでアクティブになっています。 制限付きバケットは、すべてのバケットの中で、優先度が最も低い(かつ制限が最も多い)バケットです。バケットを優先度の高いものから低いものの順に示すと次のようになります。
- アクティブ(active): 現在使用されている、またはごく最近使用されたアプリ
- ワーキング セット(working set): 定期的に使用されているアプリ
- 高頻度(frequent): 毎日ではないが、よく使用されるアプリ
- 低頻度(rare): あまり使用されないアプリ
- 制限あり(restricted): アプリがシステム リソースを大量に消費するか、望ましくない動作を引き起こす可能性がある
システムは、使用パターンだけでなくアプリの動作も考慮して、アプリを制限付きバケットに配置するかどうかを判断します。
アプリがシステム リソースを厳重に使用するのであれば、制限付きバケットに配置される可能性は低くなります。また、ユーザーがアプリを直接操作する場合、アプリは制限の少ないバケットに配置されます。
アプリが制限付きバケットに配置されているかどうかを確認する
アプリが制限付きバケットに配置されているかどうかを確認するには、getAppStandbyBucket()
を呼び出します。このメソッドの戻り値が STANDBY_BUCKET_RESTRICTED
の場合、アプリは制限付きバケットに配置されています。
制限付きバケットの動作をテストする
アプリが制限付きバケットに配置されたときの動作をテストする場合は、アプリをそのバケットに手動で移動できます。そのためには、ターミナル ウィンドウで次のコマンドを実行します。
adb shell am set-standby-bucket PACKAGE_NAME restricted
セキュリティとプライバシー
おおよその現在地
Android 12 以上を搭載したデバイスの場合、ユーザーはアプリがおおよその位置情報のみにアクセスするようリクエストできます。
アプリで ACCESS_FINE_LOCATION
実行時権限をリクエストする場合は、ACCESS_COARSE_LOCATION
権限もリクエストして、ユーザーがアプリにおおよその位置情報へのアクセスを許可する場合にも対応する必要があります。両方の権限を 1 つの実行時リクエストに含める必要があります。
図 1 に示すように、システム権限ダイアログには以下のオプションがあります。
- Precise: 正確な位置情報の取得を許可します。
- Approximate: おおよその位置情報の取得のみを許可します。
マイクとカメラの切り替え
Android 12 以降を搭載するサポート対象デバイスでは、切り替えオプションを 1 回押すだけで、デバイス上のすべてのアプリに対するカメラとマイクへのアクセスを有効または無効にできます。ユーザーは図 1 に示すように、クイック設定から、またはシステム設定の [プライバシー] 画面から、切り替えオプションにアクセスできます。
これらの切り替えについて、またアプリが CAMERA
および RECORD_AUDIO
権限に関するベスト プラクティスに沿っていることを確認する方法について、詳細をご確認ください。
マイクとカメラのインジケーター
Android 12 以降を搭載しているデバイスでは、アプリがマイクまたはカメラにアクセスすると、ステータスバーにアイコンが表示されます。
これらのインジケーターについて、またアプリが CAMERA
および RECORD_AUDIO
権限に関するベスト プラクティスに沿っていることを確認する方法について、詳細をご確認ください。
権限パッケージの公開設定
Android 12 以降を搭載したデバイスでは、Android 11(API レベル 30)以降をターゲットとし、以下のいずれかのメソッドを呼び出すアプリは、他のアプリに対するアプリのパッケージの公開設定に基づいてフィルタされた結果セットを受け取ります。
BouncyCastle の実装を削除
Android 12 では、すべての AES アルゴリズムを含め、これまで非推奨となっていた多数の暗号アルゴリズムの BouncyCastle 実装が削除されました。代わりに、システムはこれらのアルゴリズムの Conscrypt 実装を使用します。
次のいずれかに該当する場合、この変更はアプリに影響します。
- アプリが 512 ビットの鍵サイズを使用する。Conscrypt はこの鍵サイズをサポートしていません。必要に応じて、異なる鍵サイズを使用するよう、アプリの暗号ロジックを更新します。
アプリが
KeyGenerator
で無効な鍵サイズを使用する。Conscrypt のKeyGenerator
の実装では、BouncyCastle と比較して、鍵パラメータに対して追加の検証が行われます。たとえば、AES は 128 ビット、192 ビット、256 ビットの鍵しかサポートしていないため、Conscrypt では 64 ビットの AES 鍵を生成できません。BouncyCastle では無効なサイズの鍵を生成できますが、その鍵を
Cipher
で使用すると後で失敗します。Conscrypt は先に失敗します。12 バイト以外のサイズを使用して Galois/Counter Mode(GCM)暗号を初期化する。Conscrypt の
GcmParameterSpec
の実装では、NIST が推奨する 12 バイトの初期化が必要です。
クリップボードへのアクセスの通知
Android 12 以降では、アプリが初めて getPrimaryClip()
を呼び出して、別のアプリからクリップデータにアクセスすると、トースト メッセージによって、このクリップボードへのアクセスがユーザーに通知されます。
トースト メッセージ内のテキストには、APP pasted from your clipboard.
の形式が含まれます。
クリップの説明のテキストに関する情報
Android 12 以降では、getPrimaryClipDescription()
が次の詳細を検出できます。
isStyledText()
を使用してスタイル設定されたテキスト。getConfidenceScore()
を使用した、URL などテキストの各種分類。
アプリからシステム ダイアログを閉じるアクションが不可に
アプリとシステムを操作しているときのユーザー制御を改善するため、Android 12 では ACTION_CLOSE_SYSTEM_DIALOGS
インテント アクションのサポートが終了しました。少数の特殊なケースを除いて、アプリがこのアクションを含むインテントの呼び出しを試みると、アプリのターゲット SDK バージョンに応じてシステムは次のいずれかを行います。
- アプリが Android 12 以降を対象にしている場合、
SecurityException
が発生します。 Android 11(API レベル 30)以下をターゲットとするアプリの場合は、インテントを実行しません。logcat には次のメッセージが表示されます。
E ActivityTaskManager Permission Denial: \ android.intent.action.CLOSE_SYSTEM_DIALOGS broadcast from \ com.package.name requires android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS, \ dropping broadcast.
例外
次の場合、アプリは Android 12 以降で引き続きシステム ダイアログを閉じることができます。
- アプリがインストルメンテーション テストを実行している。
アプリが Android 11 以下をターゲットとしており、通知ドロワーの上にウィンドウを表示している。
アプリが Android 11 以下をターゲットとしている。さらに、ユーザーが(おそらく通知のアクション ボタンを使用して)通知を操作し、アプリがそのユーザー アクションに応じてサービスまたはブロードキャスト レシーバを処理している。
アプリが Android 11 以前をターゲットとしており、ユーザー補助サービスが有効になっている。アプリが Android 12 をターゲットとし、通知バーを閉じる場合は、代わりに
GLOBAL_ACTION_DISMISS_NOTIFICATION_SHADE
ユーザー補助アクションを使用します。
信頼できないタッチイベントはブロックされる
システム セキュリティと優れたユーザー エクスペリエンスを維持するため、Android 12 は、オーバーレイが安全でない方法でアプリを覆い隠している場合にタッチイベントをアプリが使用することを許しません。つまり、少数の例外を除いて、特定のウィンドウをパススルーするタッチはシステムによってブロックされます。
影響を受けるアプリ
この変更は、たとえば FLAG_NOT_TOUCHABLE
フラグを使用してタッチにウィンドウをパススルーさせているアプリに影響します。具体例の一部を以下に示します。
TYPE_APPLICATION_OVERLAY
を使用し、FLAG_NOT_TOUCHABLE
フラグを使用するウィンドウなど、SYSTEM_ALERT_WINDOW
権限を必要とするオーバーレイ。FLAG_NOT_TOUCHABLE
フラグを使用するアクティビティ ウィンドウ。
例外
次の場合は「パススルー」タッチが許可されます。
- アプリ内の操作: アプリがオーバーレイを表示し、ユーザーがアプリを操作しているときにのみオーバーレイが表示されます。
信頼済みのウィンドウ: 信頼済みのウィンドウの例の一部を次に示します。
完全に透明なウィンドウ:
alpha
プロパティが 0.0 のウィンドウ。十分に透明なシステム アラート ウィンドウ: 不透明度の組み合わせの総和がタッチに対するシステムの最大隠蔽不透明度以下である場合、一連のシステム アラート ウィンドウは十分に透明であると見なされます。Android 12 では、この最大不透明度はデフォルトで 0.8 になっています。
信頼できないタッチがブロックされたときに検出する
タッチ アクションがシステムによってブロックされると、logcat は次のメッセージを記録します。
Untrusted touch due to occlusion by PACKAGE_NAME
変更をテストする
Android 12 以降を搭載したデバイスでは、信頼できないタッチはデフォルトでブロックされます。信頼できないタッチを許可するには、ターミナル ウィンドウで次の adb コマンドを実行します。
# A specific app adb shell am compat disable BLOCK_UNTRUSTED_TOUCHES com.example.app # All apps # If you'd still like to see a Logcat message warning when a touch would be # blocked, use 1 instead of 0. adb shell settings put global block_untrusted_touches 0
動作をデフォルト(信頼できないタッチがブロックされる)に戻すには、次のコマンドを実行します。
# A specific app adb shell am compat reset BLOCK_UNTRUSTED_TOUCHES com.example.app # All apps adb shell settings put global block_untrusted_touches 2
アクティビティのライフサイクル
戻るボタンを押してもルート ランチャー アクティビティが終了しない
Android 12 では、タスクのルートにあるランチャー アクティビティの戻るボタンのデフォルト処理が変更されています。以前のバージョンでは、これらのアクティビティを戻るボタンを押して終了していました。Android 12 では、アクティビティを終了する代わりに、アクティビティとそのタスクをバックグラウンドに移動させるようになりました。 この新しい動作は、ホームボタンやジェスチャーを使用してアプリから移動する際の現在の動作と一致しています。
ほとんどのアプリでは、この変更により、戻るボタンでアプリを終了した場合に、コールド状態からアプリを再起動するのではなく、ウォーム状態からすばやくアプリを再開できるようになります。
この変更についてアプリをテストすることをおすすめします。アプリで onBackPressed()
をオーバーライドすることで「戻る」ナビゲーションを処理し、Activity
を終了していた場合は、終了せずに super.onBackPressed()
を呼び出すように実装を更新してください。super.onBackPressed()
を呼び出すと、必要に応じてアクティビティとそのタスクがバックグラウンドに移動し、アプリ間で一貫性のあるナビゲーションを実現できます。
また一般に、onBackPressed()
をオーバーライドする代わりに、AndroidX Activity API を使用して「戻る」カスタム ナビゲーションを提供することをおすすめします。戻るボタンをインターセプトするコンポーネントがない場合、AndroidX Activity API は自動的に適切なシステム動作に従います。
グラフィックと画像
リフレッシュ レートの切り替えの改善
Android 12 では、ディスプレイが新しいリフレッシュ レートへのシームレスな移行をサポートするかどうかにかかわらず、setFrameRate()
を使用してリフレッシュ レートを変更できます。シームレスな移行とは、画面が 1~2 秒黒くなるなどの視覚的な中断がないことを指します。これまでは、ディスプレイがシームレスな移行をサポートしていない場合、setFrameRate()
が呼び出された後も通常は同じリフレッシュ レートを使用し続けていました。getAlternativeRefreshRates()
を呼び出すことで新しいリフレッシュ レートへの移行がシームレスに行われるかどうかを事前に判断できます。一般に、コールバック onDisplayChanged()
はリフレッシュ レートの切り替えが終わった後に呼び出されますが、一部の外部接続ディスプレイでは、シームレスでない移行の間に呼び出されます。
実装例を次に示します。
Kotlin
// Determine whether the transition will be seamless. // Non-seamless transitions may cause a 1-2 second black screen. val refreshRates = this.display?.mode?.alternativeRefreshRates val willBeSeamless = Arrays.asList<FloatArray>(refreshRates).contains(newRefreshRate) // Set the frame rate even if the transition will not be seamless. surface.setFrameRate(newRefreshRate, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS)
Java
// Determine whether the transition will be seamless. // Non-seamless transitions may cause a 1-2 second black screen. Display display = context.getDisplay(); // API 30+ Display.Mode mode = display.getMode(); float[] refreshRates = mode.getAlternativeRefreshRates(); boolean willBeSeamless = Arrays.asList(refreshRates).contains(newRefreshRate); // Set the frame rate even if the transition will not be seamless. surface.setFrameRate(newRefreshRate, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, CHANGE_FRAME_RATE_ALWAYS);
接続
Passpoint の更新
Android 12 では、次の API が追加されています。
isPasspointTermsAndConditionsSupported()
: 利用規約は Passpoint 機能であり、ネットワーク デプロイにおいて、オープン ネットワークを使用する安全でないキャプティブ ポータルを安全な Passpoint ネットワークに置き換えることができます。利用規約への同意が必要な場合は、通知が表示されます。利用規約によって制限される Passpoint ネットワークを提案するアプリでは、まずこの API を呼び出して、デバイスが機能をサポートしていることを確認する必要があります。デバイスが機能をサポートしていない場合、このネットワークには接続できず、代替ネットワークまたはレガシー ネットワークを提案する必要があります。isDecoratedIdentitySupported()
: プレフィックス装飾でネットワークの認証を行う場合、装飾された ID プレフィックスにより、ネットワーク事業者はネットワーク アクセス識別子(NAI)を更新して、AAA ネットワーク内の複数のプロキシを経由して明示的なルーティングを行えます(詳細については RFC 7542 をご覧ください)。Android 12 では、PPS-MO 拡張の WBA 仕様に適合するようにこの機能が実装されています。装飾された ID を必要とする Passpoint ネットワークを提案するアプリでは、まずこの API を呼び出して、デバイスが機能をサポートしていることを確認する必要があります。デバイスが機能をサポートしていない場合、ID が装飾されず、ネットワークの認証が失敗する可能性があります。
Passpoint の提案を作成するには、アプリで PasspointConfiguration
、Credential
、HomeSp
クラスを使用する必要があります。これらのクラスは、Wi-Fi Alliance Passpoint 仕様で定義されている Passpoint プロファイルを記述します。
詳しくは、インターネット接続のための Wi-Fi サジェスチョン API をご覧ください。
非 SDK インターフェースの制限の更新
Android 12 では、Android デベロッパーの協力と直近の内部テストに基づいて、制限を受ける非 SDK インターフェースのリストが更新されています。Google は、非 SDK インターフェースを制限する前に、可能な限り、その代わりとなる公開インターフェースを利用可能にしています。
Android 12 をターゲットとしないアプリでは、この変更の一部はすぐには影響しない可能性があります。ただし、現時点で(アプリのターゲット API レベルに応じて)一部の非 SDK インターフェースを利用できていても、非 SDK のメソッドまたはフィールドをそのまま使用し続けると、将来的にアプリが機能しなくなるリスクが高くなります。
アプリが非 SDK インターフェースを使用しているかどうか不明な場合は、アプリをテストして確認できます。アプリが非 SDK インターフェースに依存している場合は、SDK の代替インターフェースへの移行を計画してください。ただし Google も、一部のアプリには非 SDK インターフェースを使用する正当なユースケースがあると承知しています。アプリの機能で使用している非 SDK インターフェースの代替インターフェースが見つからない場合は、新しい公開 API をリクエストしてください。
Android の今回のリリースの変更について詳しくは、非 SDK インターフェースの制限に関する Android 12 での変更点をご覧ください。非 SDK インターフェース全般について詳しくは、非 SDK インターフェースの制限をご覧ください。