動作の変更点: Android 12 をターゲットとするアプリ

これまでのリリースと同様、Android 12 には、アプリに影響する可能性がある動作変更が含まれています。下記の動作変更は、Android 12 以上をターゲットとするアプリにのみ適用されます。アプリが Android 12 をターゲットとする場合は、必要に応じてアプリを変更し、下記の動作に適切に対応できるようにしてください。

Android 12 で動作するすべてのアプリに影響する動作変更のリストも必ずご確認ください。

ユーザー エクスペリエンス

ピクチャー イン ピクチャーの動作の改善

Android 12 では、ピクチャー イン ピクチャー(PIP)モードの動作が改善されています。詳細については、ピクチャー イン ピクチャーの改善をご覧ください。

カスタム通知

Android 12 では、フルカスタム通知の外観と動作が変更されました。以前のカスタム通知では、通知領域全体を使用して、独自のレイアウトとスタイルを指定することが可能でした。その結果、アンチパターンが発生して、ユーザーが混乱したり異なるデバイス間でレイアウト互換性の問題が生じたりすることがありました。

Android 12 をターゲットとするアプリでは、カスタム コンテンツ ビューを使用する通知は通知領域全体を使用せず、代わりにシステムが標準テンプレートを適用するようになります。このテンプレートにより、カスタム通知がすべての状態において他の通知と同じ装飾を持つことが保証されます。たとえば、通知のアイコンと展開のアフォーダンス(折りたたまれた状態の場合)や、通知のアイコン、アプリ名、および折りたたみのアフォーダンス(展開された状態の場合)などです。この動作は、Notification.DecoratedCustomViewStyle の動作とほぼ同じです。

これにより、Android 12 では、すべての通知の視覚的な一貫性が確保されます。また、ユーザーにとって見つけやすく親しみやすい外観で通知が展開されるため、スキャンが容易になります。

次の図は、標準テンプレートによるカスタム通知を示しています。

次の例は、折りたたまれた状態と展開された状態でカスタム通知がどのようにレンダリングされるかを示しています。

Android 12 における変更は、Notification.Style のカスタム サブクラスを定義しているアプリや、Notification.Builder のメソッド setCustomContentView(RemoteViews)setCustomBigContentView(RemoteViews)setCustomHeadsUpContentView(RemoteViews) を使用しているアプリに影響します。

フルカスタム通知を使用しているアプリがある場合は、できるだけ早く新しいテンプレートでテストすることをおすすめします。

  1. カスタム通知の変更を有効にするには:

    1. アプリの targetSdkVersionS に変更して、新しい動作を有効にします。
    2. 再コンパイルします。
    3. Android 12 を実行しているデバイスまたはエミュレータにアプリをインストールします。
  2. カスタムビューを使用する通知をすべてテストし、シェード内で想定どおりに表示されることを確認します。テストの際には、これらの点を考慮し、必要な調整を行います。

    • カスタムビューの寸法が変更されました。一般的に、カスタム通知に提供される高さは以前より低くなります。折りたたまれた状態では、カスタム コンテンツの最大の高さは 106 dp から 48 dp に減少します。また、水平方向のスペースが縮小されます。

    • Android 12 をターゲットとするアプリでは、すべての通知を展開できます。そのため、setCustomContentView を使用している場合、通常は setBigCustomContentView も使用して、折りたたまれた状態と展開された状態に一貫性を持たせる必要があります。

    • 「ヘッドアップ」の状態が想定どおりに表示されるようにするには、通知チャンネルの重要度を必ず「高」(画面上のポップアップ表示)に上げてください。

Android 12 をターゲットとするアプリでは、Android アプリリンクの検証方法に変更が加えられます。この変更により、アプリリンク エクスペリエンスの信頼性が向上し、アプリ デベロッパーとエンドユーザーが、より細かく制御できるようになります。

Android 12 をターゲットとし、Android アプリリンクの検証を使用してアプリ内でウェブリンクを開く場合は、変更された検証プロセスをサポートするように Android アプリリンクの宣言を更新してください。ドメインの検証を手動で呼び出すことで、宣言の信頼性をテストすることもできます。

プライバシー

おおよその位置情報

ダイアログでは 2 つのオプション セットが上下に表示されています
図 1. アプリが Android 12 をターゲットとし、1 つのランタイム リクエストで ACCESS_FINE_LOCATIONACCESS_COARSE_LOCATION の両方をリクエストした場合に表示されるシステム権限ダイアログ。

Android 12 をターゲットとするアプリを使用している場合、ユーザーはアプリがおおよその位置情報のみにアクセスするようリクエストできます。

Android 12 をターゲットとするアプリが ACCESS_FINE_LOCATION ランタイム権限をリクエストする場合は、ACCESS_COARSE_LOCATION 権限もリクエストする必要があります(1 つのランタイム リクエストに両方の権限を含めます)。

アプリが ACCESS_FINE_LOCATIONACCESS_COARSE_LOCATION の両方をリクエストすると、図 1 に示すように、システム権限ダイアログには以下の新しいオプションが含まれます。

  • 正確: ACCESS_FINE_LOCATION 権限によって指定される位置情報の精度を提供します。
  • おおよそ: ACCESS_COARSE_LOCATION 権限によって指定される位置情報の精度を提供します。

詳細については、Android 12 のおおよその位置情報をご覧ください。

アプリの休止状態

Android 12 では、Android 11(API レベル 30)で導入された許可のオートリセットの動作が拡張されています。アプリが Android 12 をターゲットとしていて、ユーザーが数か月にわたってアプリを操作しなかった場合、付与されたすべての権限が自動的にリセットされ、アプリが休止状態になります。

休止状態のアプリには、次の特徴があります。

  • パフォーマンスではなく保存容量に合わせて最適化されます。アプリのキャッシュ内のファイルはすべて削除されます。
  • アプリはバックグラウンドでジョブやアラートを実行できません。
  • アプリはプッシュ通知(Firebase Cloud Messaging を介して送信される優先度の高いメッセージなど)を受信できません。

ユーザーが次にアプリを操作すると、アプリは休止状態を終了し、再びジョブ、アラート、通知を作成できるようになります。ただし、アプリが休止状態になる前にスケジュールされたジョブ、アラート、通知は、スケジュールを再設定する必要があります。このワークフローは、ユーザーがシステム設定からアプリを手動で強制停止する場合と同様です。このワークフローを簡単にサポートするには、WorkManager を使用します。また、ACTION_BOOT_COMPLETED ブロードキャスト レシーバにスケジュール変更ロジックを追加することもできます。このブロードキャスト レシーバは、アプリが休止状態を終了したときや、デバイスが起動した後に呼び出されます。

休止状態を無効にするようユーザーにリクエストする

アプリのユースケースが休止状態により影響を受けると思われる場合は、休止状態および許可のオートリセットの対象からアプリを除外するよう、ユーザーにリクエストを送信できます。この除外は、アプリが主にバックグラウンドで(アプリを操作していない場合でも)動作することをユーザーが予期している状況で役立ちます。たとえば、アプリが次のうち 1 つまたは複数のことを行っている場合などです。

  • 家族の現在地を定期的に報告して、家族の安全を確保する。
  • デバイスとアプリのサーバーの間でデータを同期する。
  • テレビなどのスマート デバイスと通信する。
  • スマートウォッチなどのコンパニオン デバイスとペア設定する。

除外をリクエストするには、Intent.ACTION_APPLICATION_DETAILS_SETTINGS インテント アクションを含むインテントを呼び出します。表示される画面で、ユーザーは [権限を削除して空き容量を増やす] オプションをオフにできます。

休止状態の動作をテストする

テスト目的でアプリを休止状態にするには、次のようにします。

  1. デバイスで休止状態の動作を有効にします。

    adb shell device_config put app_hibernation app_hibernation_enabled true
    
  2. アプリの状態を変更して休止状態にします。--global フラグを含むコマンドを使用すると、アプリを強制的に「完全な休止状態」にすることが可能です。これにより、マルチユーザー デバイスのすべてのユーザーに対して、アプリが休止状態になった状況をシミュレートできます。

    adb shell cmd app_hibernation set-state PACKAGE-NAME true && \
      adb shell cmd app_hibernation set-state --global PACKAGE-NAME true
    

モーション センサーのレート制限

アプリが Android 12 をターゲットにしている場合、ユーザーの機密に該当する可能性がある情報を保護するため、特定のモーション センサーや位置センサーからのデータのリフレッシュ レートに制限が課されます。このデータには、デバイスの加速度計ジャイロスコープ地磁気センサーによって記録された値が含まれます。

リフレッシュ レートの制限は、センサーデータへのアクセス方法によって異なります。

  • registerListener() メソッドを呼び出すと、センサーのサンプリング レートは 200 Hz に制限されます。これは、registerListener() メソッドのオーバーロードされたすべてのバリアントに適用されます。
  • SensorDirectChannel クラスを使用する場合、センサーのサンプリング レートは RATE_NORMAL(通常は約 50 Hz)に制限されます。

アプリが Android 12 をターゲットとし、より高いレートでモーション センサーデータを収集する必要がある場合は、HIGH_SAMPLING_RATE_SENSORS 権限を宣言する必要があります。アプリがこの権限を宣言せずにより高いレートでモーション センサーデータを収集しようとすると、SecurityException が発生します。

データアクセスの監査

Android 11(API レベル 30)で導入された Data Access Auditing API を使用すると、アプリのユースケースに基づいてアトリビューション タグを作成できます。これらのタグを使用することで、特定の種類のデータアクセスをアプリのどの部分で実行するかを簡単に指定できます。

Android 12 をターゲットとするアプリの場合、アプリのマニフェスト ファイル内で、以下のコード スニペットに示す形式を使用して、これらのアトリビューション タグを宣言する必要があります。アプリが Android 12 をターゲットとしていて、アプリのマニフェスト ファイルで宣言していないアトリビューション タグを使用しようとすると、システムが null タグを作成し、Logcat にメッセージを記録します。


<manifest ...>
    <!-- The value of "android:tag" must be a literal string, and the
         value of "android:label" must be a resource. The value of
         "android:label" should be user-readable. -->
    <attribution android:tag="sharePhotos"
                 android:label="@string/share_photos_attribution_label" />
    ...
</manifest>

WebView での最新の SameSite Cookie

Android の WebView コンポーネントは、Google の Chrome ブラウザを支えるオープンソース プロジェクトである Chromium をベースにしています。昨年 Chromium は、セキュリティとプライバシーを強化してより高い透明性と管理性をユーザーに提供するため、サードパーティ Cookie の処理に関する変更を導入しました。この変更はすでに多くの Chrome ユーザーにロールアウトされており、Android 12 以降は WebView に適用されます。

Cookie の SameSite 属性は、Cookie を任意のリクエストで送信できるか、同一サイト リクエストのみで送信できるかを制御します。サードパーティ Cookie のデフォルト処理を改善し、意図しないクロスサイト共有を防止するため、Android 12 における WebView のベース バージョン(89.0.4385.0)には、次に示すプライバシー保護の変更が取り入れられています。

  • SameSite 属性が設定されていない Cookie は SameSite=Lax として扱われます。
  • SameSite=None の Cookie には、Secure 属性も指定する必要があります。つまり、そうした Cookie はセキュア コンテキストを必要とし、HTTPS で送信する必要があります。
  • サイトの HTTP バージョンと HTTPS バージョン間のリンクは、クロスサイト リクエストとして扱われるようになりました。したがって、SameSite=None; Secure として適切にマークされていない限り、Cookie は送信されません。

デベロッパー向けのガイダンスとして、重要なユーザーフローでクロスサイト Cookie の依存関係を明らかにし、必要に応じて SameSite 属性に適切な値が明示的に設定されていることを確認するようおすすめします。ウェブサイト間で、または HTTP から HTTPS に移動する同一サイト ナビゲーションで動作することを許可する Cookie を明示的に指定する必要があります。

これらの変更に関するウェブ デベロッパー向けの詳細なガイダンスについては、SameSite Cookie の説明およびスキームフル SameSite の記事をご覧ください。

アプリで SameSite 動作をテストする

アプリで WebView を使用している場合や、Cookie を使用するウェブサイトまたはサービスを管理している場合は、Android 12 の WebView でフローをテストすることをおすすめします。問題が見つかった場合は、新しい SameSite 動作に対応するために Cookie の更新が必要になる可能性があります。

ログインと埋め込みコンテンツで問題が発生しないか、また、ユーザーが安全でないページから出発して安全なページに移動するログインフロー、購入フロー、およびその他の認証フローで問題が発生しないかを確認してください。

WebView を使用するアプリをテストするには、次のいずれかの手順を実施して、テスト対象のアプリで新しい SameSite 動作を有効にする必要があります。

  • WebView DevToolsUI フラグ webview-enable-modern-cookie-same-site を切り替えることにより、テストデバイス上の SameSite 動作を手動で有効にします。

    このアプローチでは、Android 5.0(API レベル 21)以上(Android 12 を含む)と WebView バージョン 89.0.4385.0 以上を実行しているデバイスで、テストを実施できます。

  • targetSdkVersion により、Android 12 をターゲットとしてアプリをコンパイルします。

    このアプローチでは、Android 12 と WebView バージョン 89.0.4385.0 以上を実行しているデバイスを使用する必要があります。

Android での WebView のリモート デバッグについては、Android デバイスでリモート デバッグを開始するをご覧ください。

その他のリソース

最新の SameSite 動作と Chrome および WebView へのロールアウトについて詳しくは、Chromium の SameSite アップデートのページをご覧ください。WebView または Chromium でバグが見つかった場合は、一般公開されている Chromium Issue Tracker での報告をお願いします。

ADB バックアップの制限

限定公開アプリのデータを保護するため、Android 12 では adb backup コマンドのデフォルト動作が変更されました。Android 12 をターゲットとするアプリでは、ユーザーが adb backup コマンドを実行したとき、デバイスからエクスポートされる他のシステムデータからアプリデータが除外されます。

テストまたは開発ワークフローが adb backup を使用して取得するアプリデータに依存している場合は、アプリのマニフェスト ファイルで android:debuggabletrue に設定することにより、アプリデータのエクスポートを有効にすることができるようになりました。

セキュリティ

コンポーネントのエクスポートの安全性を改善

Android 12 をターゲットとするアプリに、インテント フィルタを使用するアクティビティサービス、またはブロードキャスト レシーバが含まれている場合は、それらのアプリ コンポーネントで android:exported 属性を明示的に宣言する必要があります。

次のコード スニペットは、インテント フィルタを含むサービスが Android 12 用に正しく構成されている例を示しています。

<service android:name="com.example.app.backgroundService"
         android:exported="false">
    <intent-filter>
        <action android:name="com.example.app.START_BACKGROUND" />
    </intent-filter>
</service>

Android Studio のメッセージ

インテント フィルタを使用し、android:exported を宣言していないアクティビティ、サービス、ブロードキャスト レシーバがアプリに含まれている場合は、使用する Android Studio のバージョンに応じて、次の警告メッセージが表示されます。

Android Studio 2020.3.1 Canary 版 11 以降

次のメッセージが表示されます。

  1. マニフェスト ファイルに、次の lint 警告が表示されます。

    When using intent filters, please specify android:exported as well
    
  2. アプリをコンパイルしようとすると、次のビルド エラー メッセージが表示されます。

    Manifest merger failed : Apps targeting Android 12 and higher are required \
    to specify an explicit value for android:exported when the corresponding \
    component has an intent filter defined.
    
古いバージョンの Android Studio

アプリをインストールしようとすると、logcat に次のエラー メッセージが表示されます。

Installation did not succeed.
The application could not be installed: INSTALL_FAILED_VERIFICATION_FAILURE
List of apks:
[0] '.../build/outputs/apk/debug/app-debug.apk'
Installation failed due to: 'null'

ペンディング インテントの可変性

Android 12 をターゲットとするアプリでは、アプリが作成する個々の PendingIntent オブジェクトの可変性を指定する必要があります。この追加要件により、アプリのセキュリティが強化されます。

特定の PendingIntent オブジェクトが可変または不変であることを宣言するには、PendingIntent.FLAG_MUTABLE フラグまたは PendingIntent.FLAG_IMMUTABLE フラグをそれぞれ使用します。アプリがどちらの可変性フラグも設定せずに PendingIntent オブジェクトを作成しようとすると、IllegalArgumentException がスローされ、logcat に次のメッセージが表示されます。

PACKAGE_NAME: Targeting S+ (version 10000 and above) requires that one of \
FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent.

Strongly consider using FLAG_IMMUTABLE, only use FLAG_MUTABLE if \
some functionality depends on the PendingIntent being mutable, e.g. if \
it needs to be used with inline replies or bubbles.

可能な限り不変のペンディング インテントを作成する

ほとんどの場合において、アプリでは不変の PendingIntent オブジェクトを作成するようにしてください(次のコード スニペットを参照)。PendingIntent オブジェクトが不変の場合、アプリはそのインテントを変更して、インテント呼び出しの結果を調整することはできません。

Kotlin

val pendingIntent = PendingIntent.getActivity(applicationContext,
        REQUEST_CODE, intent,
        /* flags */ PendingIntent.FLAG_IMMUTABLE)

Java

PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(),
        REQUEST_CODE, intent,
        /* flags */ PendingIntent.FLAG_IMMUTABLE);

ただし、次の場合には可変の PendingIntent オブジェクトを作成する必要があります。

  • 通知内のダイレクト返信アクションが、返信に関連付けられた PendingIntent オブジェクト内のクリップデータの変更を必要とする場合。通常は、fillIn() メソッドに FILL_IN_CLIP_DATA をフラグとして渡すことにより、この変更をリクエストします。
  • アプリが PendingIntent を使用して会話をバブルに配置する場合は、システムが FLAG_ACTIVITY_MULTIPLE_TASKFLAG_ACTIVITY_NEW_DOCUMENT などの正しいフラグを適用できるように、インテントを可変にする必要があります。

アプリで可変の PendingIntent オブジェクトを作成する場合は、明示的インテントを使用して ComponentName の値をフィルインすることを強くおすすめします。そうすれば、別のアプリが PendingIntent を呼び出してアプリに制御を戻すたびに、常にアプリ内の同じコンポーネントが開始されます。

ペンディング インテントの可変性の変更をテストする

アプリに可変性の宣言が欠けているかどうかを確認するには、Android Studio で次の lint 警告を検索します。

Warning: Missing PendingIntent mutability flag [UnspecifiedImmutableFlag]

デベロッパー プレビューを使用している場合に、テスト目的でこのシステム動作を無効にするには、PENDING_INTENT_EXPLICIT_MUTABILITY_REQUIRED アプリ互換性フラグをオフにします。

インテントの安全でない起動

Android 12 では、プラットフォームのセキュリティを強化するため、インテントの安全でない起動をアプリが実行したときに警告するデバッグ機能が導入されました。たとえば、URI から再作成されたインテントの安全でない起動や、ネストされたインテント(次のセクションで定義します)の安全でない起動などをアプリが実行する場合があります。

ネストされたインテントについて

「ネストされたインテント」とは、別のインテント内でエクストラとして渡されるインテントです。アプリが次のアクションの両方を実行すると、StrictMode 違反が発生します。

インテントの安全でない起動が検出されるようにアプリを構成する

アプリでの安全でないインテントの起動を確認するには、VmPolicy を構成する際に detectUnsafeIntentLaunch() を呼び出します。次のコード スニペットをご覧ください。アプリで StrictMode 違反が検出された場合は、機密に該当する可能性がある情報を保護するために、アプリの実行を停止することをおすすめします。

Kotlin

fun onCreate() {
    StrictMode.setVmPolicy(VmPolicy.Builder()
        // Other StrictMode checks that you've previously added.
        // ...
        .detectUnsafeIntentLaunch()
        .penaltyLog()
        // Consider also adding penaltyDeath()
        .build())
}

Java

protected void onCreate() {
    StrictMode.setVmPolicy(new VmPolicy.Builder()
        // Other StrictMode checks that you've previously added.
        // ...
        .detectUnsafeIntentLaunch()
        .penaltyLog()
        // Consider also adding penaltyDeath()
        .build());
}

インテントをより厳格に使用する

アプリは、アプリ内のコンポーネント間を移動するため、または別のアプリに代わってアクションを実行するため、インテントを起動することがあります。いずれの場合も StrictMode 違反が発生する可能性を最小限に抑えるために、以下を実施してください。

  • インテント内の必須のエクストラのみをコピーして、必要なサニタイズと検証を行います。アプリは、あるインテントから、新しいコンポーネントの起動に使用される別のインテントに、エクストラをコピーすることがあります。これは、アプリが putExtras(Intent) または putExtras(Bundle) を呼び出したときに発生します。アプリがこれらのオペレーションのいずれかを実行する場合、受信コンポーネントで想定されるエクストラのみをコピーします。コピーを受信するインテントがエクスポートされていないコンポーネントを起動する場合は、エクストラをサニタイズして検証してから、コンポーネントを起動するインテントにコピーします。
  • ネストされたインテントの内部起動: 該当コンポーネントがエクスポートされないようにします。
  • ネストされたインテントのクロスアプリ起動: ネストされたインテントの代わりに PendingIntent を使用します。この方法では、Intent からその内部の PendingIntent が取り出されたとき、アプリ コンポーネントが呼び出しプロセスの識別子を使用して PendingIntent を起動できます。このように構成すると、プロバイダ アプリは、任意のコンポーネント(呼び出し元アプリのエクスポートされないコンポーネントを含む)にコールバックを送信できます。

    この状況を識別してアプリに変更を加える方法について詳しくは、Medium の Android のネスト インテント に関するブログ記事をご覧ください。

パフォーマンス

フォアグラウンド サービスの起動に関する制限

Android 12 をターゲットとするアプリは、バックグラウンドで動作しているとき、少数の特殊なケースを除いて、フォアグラウンド サービスを起動できなくなりました。アプリがバックグラウンドで動作しているときにフォアグラウンド サービスを起動しようとすると、(少数の特殊なケースを除いて)例外が発生します。アプリがバックグラウンドで動作しているときに作業のスケジュールを設定して開始するには、WorkManager の使用を検討してください。

アプリが受ける影響と、この変更に基づいてアプリを更新する方法について詳しくは、フォアグラウンド サービスの起動に関する制限のガイドをご覧ください。また、GitHub の WorkManagerSample を確認することもできます。

正確なアラームの権限

アプリによるシステム リソースの節約を促進するため、Android 12 では、Android 12 をターゲットとし、正確なアラームを設定するアプリには、「アラームとリマインダー」の特別なアプリアクセスが必要となっています。

この特別なアプリアクセスを取得するには、マニフェストで SCHEDULE_EXACT_ALARM 権限をリクエストします。

正確なアラームは、ユーザー向けの機能(可能なユースケース セクションで説明するような状況に当てはまるもの)にのみ使用する必要があります。

ユーザーとシステムの両方が、「アラームとリマインダー」の特別なアプリアクセスを取り消すことができます。アプリの「アラームとリマインダー」の特別なアプリアクセスが取り消されると、アプリは停止され、今後の正確なアラームはすべてキャンセルされます。

「アラームとリマインダー」の特別なアプリアクセスがアプリに付与されると、システムはそのアプリに ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED ブロードキャストを送信します。アプリでは、以下を行うブロードキャスト レシーバを実装する必要があります。

  1. アプリにまだ特別なアプリアクセスがあることを確認する。これを行うには、canScheduleExactAlarms() を呼び出します。
  2. アプリが必要とする正確なアラームのスケジュールを、現在の状態に基づいて変更する。このロジックは、アプリが ACTION_BOOT_COMPLETED ブロードキャストを受信したときの動作と同様です。

正確なアラームが設定されているものの、特別なアプリアクセスが付与されていない API をアプリが使用しようとすると、SecurityException が発生します。

アプリのユースケースで正確なアラームがどうしても必要かどうか(可能なユースケース セクションに記載されている状況のいずれかに該当するか)を検討してください。長時間の作業や、ネットワーク アクセスが必要な作業を行うには、WorkManager または JobScheduler を使用します。デバイスが Doze モードの間に作業を行うには、setAndAllowWhileIdle() を使用して不正確なアラームを作成し、そのアラームによってジョブを開始します。

正確なアラームと不正確なアラーム

アプリでは、次のようなメソッドを呼び出すときに正確なアラームを設定します。

一方、次のようなメソッドを呼び出すときは、不正確なアラームを設定します。

この権限の可能なユースケース

[アラームとリマインダーの設定を許可する] というオプション
図 2. システム設定の [アラームとリマインダー] の特別なアプリアクセスのページ。ユーザーはここで、アプリが正確なアラームを設定することを許可できます。

ユーザー向けの機能で正確な時刻にアクションを実行する必要がある場合に限り、アプリで正確なアラームを使用して、関連する権限とブロードキャスト レシーバを宣言する必要があります。これには次のような状況が考えられます。

  • 目覚まし時計アプリやタイマーアプリの場合。
  • タスクやイベントの通知など、正確な時刻に実行されるアクションのスケジュールをユーザーが設定できる場合。

Android 12 では、正確なアラームは時間的制約のある重要な割り込みと見なされます。そのため、正確なアラームは、新しいフォアグラウンド サービスの起動に関する制限の影響を受けません。

アプリにアクセス権を付与するようユーザーにリクエストする

必要に応じて、図 2 に示すように、システム設定の [アラームとリマインダー] 画面にユーザーを誘導できます。手順は次のとおりです。

  1. アプリの UI で、アプリが正確なアラームのスケジュールを設定する必要がある理由をユーザーに説明します。
  2. ACTION_REQUEST_SCHEDULE_EXACT_ALARM インテント アクションを含むインテントを呼び出します。

動作変更を有効にする

テストのために動作変更を有効にするには、次のいずれかを行います。

  • [開発者向けオプション] 設定画面で、[アプリの互換性の変更] を選択します。表示された画面でアプリの名前をタップし、[REQUIRE_EXACT_ALARM_PERMISSION] をオンにします。
  • 開発マシンのターミナル ウィンドウで次のコマンドを実行します。

    adb shell am compat enable REQUIRE_EXACT_ALARM_PERMISSION PACKAGE_NAME
    

通知トランポリンの制限

ユーザーが通知を操作したとき、一部のアプリは通知のタップに反応してアプリ コンポーネントを起動し、このアプリ コンポーネントにより、ユーザーが最終的に確認して操作するアクティビティが開始されます。このようなアプリ コンポーネントを「通知トランポリン」と呼びます。

アプリのパフォーマンスと UX を改善するため、Android 12 をターゲットとするアプリは、通知トランポリンとして使用されるサービスまたはブロードキャスト レシーバからアクティビティを開始できなくなりました。つまり、ユーザーが通知または通知内のアクション ボタンをタップした後、アプリはサービスまたはブロードキャスト レシーバ内で startActivity() を呼び出すことができません。

通知トランポリンとして機能するサービスまたはブロードキャスト レシーバからアプリがアクティビティを開始しようとすると、システムによってアクティビティの開始が阻止され、logcat に以下のメッセージが表示されます。

Indirect notification activity start (trampoline) from PACKAGE_NAME, \
this should be avoided for performance reasons.

通知トランポリンとして機能するアプリ コンポーネントを特定する

アプリをテストするとき、通知をタップすると、アプリ内の通知トランポリンとして機能したサービスまたはブロードキャスト レシーバを特定できます。そのためには、次のターミナル コマンドの出力を確認します。

adb shell dumpsys activity service \
  com.android.systemui/.dump.SystemUIAuxiliaryDumpService

出力のセクションには、「NotifInteractionLog」というテキストが含まれます。このセクションには、通知をタップすると開始されるコンポーネントを特定するために必要な情報が含まれています。

アプリの更新

通知トランポリンとして機能するサービスまたはブロードキャスト レシーバからアクティビティを開始するアプリがある場合は、次の移行手順を実施します。

  1. ユーザーが通知をタップしたときに表示されるアクティビティに関連付けられた PendingIntent オブジェクトを作成します。
  2. 通知を作成する際に、前の手順で作成した PendingIntent オブジェクトを使用します。

たとえば、ロギングを行う目的でアクティビティの発生元を特定するには、通知の送信時にエクストラを使用します。ロギングを一元的に行う場合は、ActivityLifecycleCallbacks または Jetpack ライフサイクル オブザーバーを使用します。

動作の切り替え

デベロッパー プレビューでアプリをテストする場合は、NOTIFICATION_TRAMPOLINE_BLOCK アプリ互換性フラグを使用して、この制限を有効または無効にできます。

バックアップと復元

Android 12 では、Android 12 以降をターゲットとしてそのバージョンで実行されているアプリのバックアップと復元の方法が変更されています。詳細については、バックアップと復元での変更点をご覧ください。

接続

ピアツーピア接続とインターネット接続の同時実行

Android 12 以降、ピアツーピア接続とインターネット接続の同時実行をサポートするデバイスは、ピアデバイスと、プライマリ インターネットを提供するネットワークの両方との Wi-Fi 接続を同時に維持することで、よりシームレスなユーザー エクスペリエンスを提供できます。この機能は、API レベル 31 以降をターゲットとするすべてのアプリで自動的に有効になります。それより低い API レベルをターゲットとするアプリの場合、これまでと同様に、ピアデバイスに接続する前にプライマリ Wi-Fi ネットワークが切断されます。

互換性

WifiManager.getConnectionInfo() は、1 つのネットワークの WifiInfo のみを返すことができます。そのため、Android 12 では API の動作が次のように変更されました。

  • 利用可能な Wi-Fi ネットワークが 1 つのみの場合は、WifiInfo が返されます。
  • 複数の Wi-Fi ネットワークが利用可能で、呼び出し元のアプリがピアツーピア接続をトリガーした場合、ピアデバイスに対応する WifiInfo が返されます。
  • 複数の Wi-Fi ネットワークが利用可能で、呼び出し元のアプリがピアツーピア接続をトリガーしていない場合、プライマリ インターネット接続の WifiInfo が返されます。

同時に 2 つの Wi-Fi ネットワークをサポートするデバイスでのユーザー エクスペリエンスを向上させるため、すべてのアプリ(特にピアツーピア接続をトリガーするアプリ)で、WifiManager.getConnectionInfo() を呼び出すのではなく、NetworkCallback.onCapabilitiesChanged() を使用するように移行することをおすすめします。これにより、NetworkCallback の登録に使用された NetworkRequest に一致するすべての WifiInfo オブジェクトを取得できるようになります。Android 12 では getConnectionInfo() のサポートが終了しています。

次のコードサンプルは、NetworkCallbackWifiInfo を取得する方法を示しています。

Kotlin

val networkCallback = object : ConnectivityManager.NetworkCallback() {
  ...
  override fun onCapabilitiesChanged(
           network : Network,
           networkCapabilities : NetworkCapabilities) {
    val transportInfo = networkCapabilities.getTransportInfo()
    if (transportInfo !is WifiInfo) return
    val wifiInfo : WifiInfo = transportInfo
    ...
  }
}

Java

final NetworkCallback networkCallback = new NetworkCallback() {
  ...
  @Override
  public void onCapabilitiesChanged(
         Network network,
         NetworkCapabilities networkCapabilities) {
    final TransportInfo transportInfo = networkCapabilities.getTransportInfo();
    if (!(transportInfo instanceof WifiInfo)) return;
    final WifiInfo wifiInfo = (WifiInfo) transportInfo;
    ...
  }
  ...
};

NFC 決済での画面オフを有効にする

Android 12 以降をターゲットとするアプリでは、requireDeviceScreenOnfalse に設定することで、デバイスの画面をオンにすることなく NFC 決済を有効にできます。画面がオフまたはロック時の NFC 決済の詳細については、画面オフとロック画面の動作をご覧ください。

ベンダー ライブラリ

ベンダー提供のネイティブ共有ライブラリ

シリコン ベンダーまたはデバイス メーカーが提供する非 NDK のネイティブ共有ライブラリは、アプリが Android 12 以降をターゲットとしている場合、デフォルトではアクセスできません。ライブラリにアクセスするには、<uses-native-library> タグを使用して明示的にリクエストする必要があります。

アプリが Android 11 以下をターゲットとする場合、<uses-native-library> タグは必要ありません。この場合、ネイティブ共有ライブラリは、NDK ライブラリかどうかにかかわらずアクセスできます。

非 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 インターフェースの制限をご覧ください。