実行時の権限をリクエストする

すべての Android アプリは、アクセスが制限されたサンドボックス内で実行されます。アプリ自体のサンドボックスの外部にあるリソースや情報を使用する必要がある場合は、実行時の権限を宣言し、このアクセスを提供する権限リクエストを設定できます。この手順は、権限を使用するためのワークフローの一部です。

危険な権限を宣言し、Android 6.0(API レベル 23)以降を搭載しているデバイスにアプリがインストールされている場合は、このガイドの手順に沿って実行時に危険な権限をリクエストする必要があります。

危険な権限を宣言していない場合、または Android 5.1(API レベル 22)以前を搭載しているデバイスにアプリがインストールされている場合は、権限が自動的に付与されるため、このページの残りの手順を完了する必要はありません。

基本方針

実行時に権限をリクエストする際に適用される基本方針は次のとおりです。

  • 権限を必要とする機能をユーザーが操作し始めたら、その状況に応じた権限をリクエストすること。
  • ユーザーをブロックしないこと。権限をリクエストする根拠を提示するものなど、説明のための UI フローは、常にキャンセルできるようにしてください。
  • 機能に必要な権限をユーザーが拒否または取り消した場合は、グレースフル デグラデーションを行いアプリの使用を続けられるようにすること。その際、権限を必要とする機能が無効になる場合もあります。
  • システム動作を前提としないこと。たとえば、すべての権限が同じ権限グループにあるとは限りません。権限グループが役立つのは、アプリが密接に関連する権限をリクエストしたときに、ユーザーに表示されるシステム ダイアログの数を最小限に抑えられることだけです。

権限をリクエストする場合のワークフロー

アプリで実行時の権限を宣言してリクエストする前に、アプリでその権限が必要かどうかを検討してください。権限の宣言を必要とすることなく、写真の撮影、メディア再生の一時停止、関連性の高い広告の掲載など、アプリのさまざまなユースケースに対応できます。

アプリで実行時の権限を宣言してリクエストする必要があると判断した場合は、次の手順を行ってください。

  1. アプリのマニフェスト ファイル内で、アプリがリクエストする必要がある権限を宣言します。
  2. アプリの特定のアクションが特定の実行時の権限に関連付けられるようアプリの UX を設計します。非公開のユーザーデータにアプリがアクセスするための権限の付与がどのアクションで必要となるかをユーザーが認識できるようにします。
  3. 特定の非公開のユーザーデータへのアクセスを必要とするアプリ内のタスクやアクションをユーザーが起動するまで待ちます。ユーザーが起動した時点で、アプリはそのデータへのアクセスに必要となる実行時の権限をリクエストできます。
  4. アプリが必要とする実行時の権限をユーザーがすでに付与しているかどうかを確認します。すでに付与している場合、アプリは非公開のユーザーデータにアクセスできます。付与されていない場合は、次のステップに進みます。

    権限を必要とする操作を実行するたびに、その権限の有無を確認する必要があります。

  5. アプリがユーザーに根拠を示す必要があるかどうかを確認します。この根拠によって、特定の実行時の権限を付与してもらう必要がある理由を説明します。アプリが根拠を示す必要がないとシステムで判断された場合は、UI 要素を表示せずに、直接次のステップに進みます。

    ただし、アプリが根拠を示す必要があるとシステムで判断された場合は、UI 要素でその根拠をユーザーに提示します。この根拠では、アプリがアクセスしようとしているデータと、実行時の権限を付与した場合にアプリからユーザーにもたらされるメリットを明確に説明する必要があります。ユーザーが根拠を確認したら、次のステップに進みます。

  6. アプリが非公開のユーザーデータにアクセスするために必要な実行時の権限をリクエストします。システムによって、実行時の権限を求めるメッセージが表示されます(権限の概要ページに表示されるメッセージなど)。

  7. ユーザーの応答で、ユーザーが実行時の権限を付与するか、拒否するかを確認します。

  8. ユーザーがアプリに権限を付与した場合は、非公開のユーザーデータにアクセスできます。ユーザーが権限を拒否した場合は、アプリ エクスペリエンスのグレースフル デグラデーションを行って、その権限で保護される情報がなくてもユーザーに機能が提供されるようにします。

図 1 は、このプロセスに関連するワークフローと一連の判断を示します。

図 1. Android で実行時の権限を宣言してリクエストする場合のワークフローを示す図

アプリに権限が付与されているかどうかを確認する

ユーザーがすでに特定の権限をアプリに付与しているかどうかを確認するには、その権限を ContextCompat.checkSelfPermission() メソッドに渡します。このメソッドは、アプリに権限があるかどうかに応じて、PERMISSION_GRANTED または PERMISSION_DENIED のいずれかを返します。

アプリが権限を必要とする理由を説明する

requestPermissions() を呼び出したときにシステムが表示する権限ダイアログでは、アプリが必要とする権限は示されますが、その理由は示されません。そのため、ユーザーが困惑する可能性があります。requestPermissions() を呼び出す前に、アプリが権限を必要とする理由をユーザーに説明することをおすすめします。

調査によると、ユーザーはアプリに権限が必要な理由(アプリの重要な機能をサポートするためや、広告を配信するためなど)を知っていると、権限リクエストを快く受け入れるようになることがわかっています。そのため、権限グループに属する API 呼び出しの一部のみを使用している場合は、使用する権限とその権限を使用する理由の明示的なリストを作成することをおすすめします。たとえば、おおまかな位置情報のみを使用している場合は、これについて、アプリの説明またはアプリに関するヘルプ記事でユーザーに知らせます。

特定の状況では、機密性の高いデータへのアクセスをリアルタイムでユーザーに知らせることもおすすめします。たとえば、カメラやマイクにアクセスする場合は、アプリ内の任意の場所に表示される通知アイコンまたは通知トレイ(アプリがバックグラウンドで実行されている場合)を使ってユーザーに知らせることにより、データをひそかに収集しているわけではないことを示すことをおすすめします。

最後に、アプリの機能を動作させるために権限をリクエストする必要があるが、その理由がユーザーに明確ではない場合は、最も機密性の高い権限を必要とする理由をユーザーに知らせる方法を探してください。

ContextCompat.checkSelfPermission() メソッドが PERMISSION_DENIED を返した場合は、shouldShowRequestPermissionRationale() を呼び出します。このメソッドが true を返した場合は、ユーザーに説明 UI を表示します。この UI で、ユーザーが有効にしようとしている機能が特定の権限を必要とする理由を説明します。

さらに、アプリが位置情報、マイク、またはカメラに関連する権限をリクエストする場合は、対象の情報にアプリがアクセスする必要性を説明することを検討してください。

権限をリクエストする

ユーザーに説明 UI を表示した後、または shouldShowRequestPermissionRationale() の戻り値で説明 UI を表示する必要がないことが判明したときは、権限をリクエストします。システム権限ダイアログがユーザーに表示され、アプリに特定の権限を付与するかどうかの選択をユーザーに促します。

これを行うには、AndroidX ライブラリに含まれる RequestPermission コントラクトを使用して、システムに権限リクエスト コードの管理を許可します。RequestPermission コントラクトを使用するとロジックが簡素化されるため、可能であればこの解決策を使用することをおすすめします。ただし、必要に応じて、権限リクエストの一部としてデベロッパー自身がリクエスト コードを管理し、このリクエスト コードを権限コールバック ロジックに含めます。

システムに権限リクエスト コードの管理を許可する

権限リクエストに関連付けられたリクエスト コードの管理をシステムに許可するには、モジュールの build.gradle ファイルに次のライブラリへの依存関係を追加します。

次のクラスのいずれかを使用できます。

RequestPermission コントラクトを使用する手順を以下に示します。RequestMultiplePermissions コントラクトを使用する手順もこれとほぼ同じです。

  1. アクティビティまたはフラグメントの初期化ロジックで、registerForActivityResult() の呼び出しに ActivityResultCallback の実装を渡します。ActivityResultCallback は、権限リクエストに対するユーザーの応答の処理方法を定義します。

    ActivityResultLauncher 型の戻り値 registerForActivityResult() への参照を保持します。

  2. 必要に応じてシステム権限ダイアログを表示するには、前の手順で保存した ActivityResultLauncher のインスタンスで launch() メソッドを呼び出します。

    launch() が呼び出されると、システム権限ダイアログが表示されます。ユーザーが選択すると、前のステップで定義した ActivityResultCallback の実装が非同期で呼び出されます。

    注: launch() を呼び出したときに表示されるダイアログをアプリでカスタマイズすることはできません。ユーザーに詳細な情報やコンテキストを提供するには、アプリの UI を変更して、アプリの機能に特定の権限が必要な理由をユーザーにわかりやすく説明します。たとえば、機能を有効にするボタンのテキストを変更します。

    また、権限をリクエストするシステム ダイアログのテキストでは、リクエストする権限に関連付けられた権限グループを参照します。この権限グループはシステムを使いやすくするために設計されたものです。アプリでは、権限が特定の権限グループに属しているかどうかに依存するロジックを使用するべきではありません。

次のコード スニペットは、権限に関する応答の処理方法を示しています。

Kotlin

// Register the permissions callback, which handles the user's response to the
// system permissions dialog. Save the return value, an instance of
// ActivityResultLauncher. You can use either a val, as shown in this snippet,
// or a lateinit var in your onAttach() or onCreate() method.
val requestPermissionLauncher =
    registerForActivityResult(RequestPermission()
    ) { isGranted: Boolean ->
        if (isGranted) {
            // Permission is granted. Continue the action or workflow in your
            // app.
        } else {
            // Explain to the user that the feature is unavailable because the
            // feature requires a permission that the user has denied. At the
            // same time, respect the user's decision. Don't link to system
            // settings in an effort to convince the user to change their
            // decision.
        }
    }

Java

// Register the permissions callback, which handles the user's response to the
// system permissions dialog. Save the return value, an instance of
// ActivityResultLauncher, as an instance variable.
private ActivityResultLauncher<String> requestPermissionLauncher =
    registerForActivityResult(new RequestPermission(), isGranted -> {
        if (isGranted) {
            // Permission is granted. Continue the action or workflow in your
            // app.
        } else {
            // Explain to the user that the feature is unavailable because the
            // feature requires a permission that the user has denied. At the
            // same time, respect the user's decision. Don't link to system
            // settings in an effort to convince the user to change their
            // decision.
        }
    });

このコード スニペットは、権限を確認し、必要に応じてユーザーに権限をリクエストする場合の推奨されるプロセスを示しています。

Kotlin

when {
    ContextCompat.checkSelfPermission(
            CONTEXT,
            Manifest.permission.REQUESTED_PERMISSION
            ) == PackageManager.PERMISSION_GRANTED -> {
        // You can use the API that requires the permission.
    }
    ActivityCompat.shouldShowRequestPermissionRationale(
            this, Manifest.permission.REQUESTED_PERMISSION) -> {
        // In an educational UI, explain to the user why your app requires this
        // permission for a specific feature to behave as expected, and what
        // features are disabled if it's declined. In this UI, include a
        // "cancel" or "no thanks" button that lets the user continue
        // using your app without granting the permission.
        showInContextUI(...)
    }
    else -> {
        // You can directly ask for the permission.
        // The registered ActivityResultCallback gets the result of this request.
        requestPermissionLauncher.launch(
                Manifest.permission.REQUESTED_PERMISSION)
    }
}

Java

if (ContextCompat.checkSelfPermission(
        CONTEXT, Manifest.permission.REQUESTED_PERMISSION) ==
        PackageManager.PERMISSION_GRANTED) {
    // You can use the API that requires the permission.
    performAction(...);
} else if (ActivityCompat.shouldShowRequestPermissionRationale(
        this, Manifest.permission.REQUESTED_PERMISSION)) {
    // In an educational UI, explain to the user why your app requires this
    // permission for a specific feature to behave as expected, and what
    // features are disabled if it's declined. In this UI, include a
    // "cancel" or "no thanks" button that lets the user continue
    // using your app without granting the permission.
    showInContextUI(...);
} else {
    // You can directly ask for the permission.
    // The registered ActivityResultCallback gets the result of this request.
    requestPermissionLauncher.launch(
            Manifest.permission.REQUESTED_PERMISSION);
}

デベロッパー自身がリクエスト コードを管理する

システムに権限リクエスト コードの管理を許可する代わりに、デベロッパー自身がリクエスト コードを管理することもできます。そのためには、requestPermissions() の呼び出しにリクエスト コードを含めます。

次のコード スニペットは、リクエスト コードを使用して権限をリクエストする方法を示しています。

Kotlin

when {
    ContextCompat.checkSelfPermission(
            CONTEXT,
            Manifest.permission.REQUESTED_PERMISSION
            ) == PackageManager.PERMISSION_GRANTED -> {
        // You can use the API that requires the permission.
        performAction(...)
    }
    ActivityCompat.shouldShowRequestPermissionRationale(
            this, Manifest.permission.REQUESTED_PERMISSION) -> {
        // In an educational UI, explain to the user why your app requires this
        // permission for a specific feature to behave as expected, and what
        // features are disabled if it's declined. In this UI, include a
        // "cancel" or "no thanks" button that lets the user continue
        // using your app without granting the permission.
        showInContextUI(...)
    }
    else -> {
        // You can directly ask for the permission.
        requestPermissions(CONTEXT,
                arrayOf(Manifest.permission.REQUESTED_PERMISSION),
                REQUEST_CODE)
    }
}

Java

if (ContextCompat.checkSelfPermission(
        CONTEXT, Manifest.permission.REQUESTED_PERMISSION) ==
        PackageManager.PERMISSION_GRANTED) {
    // You can use the API that requires the permission.
    performAction(...);
} else if (ActivityCompat.shouldShowRequestPermissionRationale(
        this, Manifest.permission.REQUESTED_PERMISSION)) {
    // In an educational UI, explain to the user why your app requires this
    // permission for a specific feature to behave as expected, and what
    // features are disabled if it's declined. In this UI, include a
    // "cancel" or "no thanks" button that lets the user continue
    // using your app without granting the permission.
    showInContextUI(...);
} else {
    // You can directly ask for the permission.
    requestPermissions(CONTEXT,
            new String[] { Manifest.permission.REQUESTED_PERMISSION },
            REQUEST_CODE);
}

ユーザーがシステム権限ダイアログに応答すると、システムはアプリの onRequestPermissionsResult() の実装を呼び出します。システムは、ユーザーの応答と、デベロッパーが定義したリクエスト コードを権限ダイアログに渡します。次のコード スニペットをご覧ください。

Kotlin

override fun onRequestPermissionsResult(requestCode: Int,
        permissions: Array<String>, grantResults: IntArray) {
    when (requestCode) {
        PERMISSION_REQUEST_CODE -> {
            // If request is cancelled, the result arrays are empty.
            if ((grantResults.isNotEmpty() &&
                    grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
                // Permission is granted. Continue the action or workflow
                // in your app.
            } else {
                // Explain to the user that the feature is unavailable because
                // the feature requires a permission that the user has denied.
                // At the same time, respect the user's decision. Don't link to
                // system settings in an effort to convince the user to change
                // their decision.
            }
            return
        }

        // Add other 'when' lines to check for other
        // permissions this app might request.
        else -> {
            // Ignore all other requests.
        }
    }
}

Java

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions,
        int[] grantResults) {
    switch (requestCode) {
        case PERMISSION_REQUEST_CODE:
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0 &&
                    grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // Permission is granted. Continue the action or workflow
                // in your app.
            }  else {
                // Explain to the user that the feature is unavailable because
                // the feature requires a permission that the user has denied.
                // At the same time, respect the user's decision. Don't link to
                // system settings in an effort to convince the user to change
                // their decision.
            }
            return;
        }
        // Other 'case' lines to check for other
        // permissions this app might request.
    }
}

位置情報の利用許可をリクエストする

位置情報の利用許可をリクエストする場合は、他の実行時の権限と同じおすすめの方法に従ってください。ただし、位置情報の利用許可には、関連する権限がシステムに複数あるという重要な違いがあります。リクエストする権限とリクエストの方法は、アプリのユースケースにおける位置情報の要件によって異なります。

フォアグラウンドでの位置情報

1 回のみ、あるいは指定した期間にわたって位置情報を共有または受信する機能がアプリに含まれている場合には、フォアグラウンドでの位置情報へのアクセスが必要です。以下はその一例です。

  • ナビゲーション アプリで、ターンバイターン方式の経路案内をする機能。
  • メッセージ アプリで、現在地を別のユーザーと共有する機能。

アプリの機能が次のいずれかの状況でデバイスの現在地にアクセスする場合、システムはアプリがフォアグラウンドで位置情報を使用しているとみなします。

  • アプリに属するアクティビティが可視状態にある。
  • アプリがフォアグラウンド サービスを実行している。フォアグラウンド サービスが実行されているとき、システムはユーザーに対して常に通知を表示します。ユーザーがデバイスのホームボタンを押したりディスプレイをオフにしたりしてアプリがバックグラウンドに移動しても、アクセスは継続します。

    Android 10(API レベル 29)以降では、次のコード スニペットに示すように、locationフォアグラウンド サービス タイプを宣言する必要があります。それ以前のバージョンの Android でも、このフォアグラウンド サービス タイプを宣言することをおすすめします。

    <!-- Recommended for Android 9 (API level 28) and lower. -->
    <!-- Required for Android 10 (API level 29) and higher. -->
    <service
        android:name="MyNavigationService"
        android:foregroundServiceType="location" ... >
        <!-- Any inner elements go here. -->
    </service>
    

次のスニペットに示すように、アプリが ACCESS_COARSE_LOCATION または ACCESS_FINE_LOCATION のいずれかの権限をリクエストするときに、フォアグラウンドでの位置情報が必要であることを宣言します。

<manifest ... >
  <!-- Include this permission any time your app needs location information. -->
  <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

  <!-- Include only if your app benefits from precise location access. -->
  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
</manifest>

バックグラウンドでの位置情報

アプリ内の機能が常に他のユーザーと位置情報を共有する場合や、Geofencing API を使用する場合、アプリはバックグラウンドでの位置情報へのアクセスを必要とします。以下はその一例です。

  • 家族間位置情報共有アプリで、家族と位置情報を継続的に共有する機能。
  • IoT アプリで、ユーザーが自宅を離れるとオフになり、帰宅すると再びオンになるようにホームデバイスを設定する機能。

フォアグラウンドでの位置情報のセクションで説明した以外の状況で、アプリがデバイスの現在地にアクセスする場合、システムはアプリがバックグラウンドで位置情報を使用しているとみなします。バックグラウンドでの位置情報の精度は、フォアグラウンドでの位置情報の精度と同じであり、アプリが宣言する位置情報へのアクセスによって異なります。

Android 10(API レベル 29)以降では、実行時にバックグラウンドでの位置情報へのアクセスをリクエストするために、アプリのマニフェストで ACCESS_BACKGROUND_LOCATION 権限を宣言する必要があります。以前のバージョンの Android では、アプリがフォアグラウンドでの位置情報へのアクセスを取得すると、バックグラウンドでの位置情報へのアクセスも自動的に取得します。

<manifest ... >
  <!-- Required only when requesting background location access on
       Android 10 (API level 29) and higher. -->
  <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
</manifest>

権限の拒否を処理する

ユーザーが権限のリクエストを拒否した場合は、その影響をユーザーが理解できるようにする必要があります。特に、権限がないために動作しない機能をユーザーに知らせる必要があります。その際は、次のベスト プラクティスを念頭に置いてください。

  • ユーザーの注意を引く。アプリに必要な権限がないために機能が制限されている UI を強調します。次のような方法が考えられます。

    • 機能の結果やデータが表示される場所にメッセージを表示する。
    • エラーアイコンとエラーを示す色を含んだ別のボタンを表示する。
  • 具体的に記述する。汎用メッセージは表示しないでください。代わりに、アプリに必要な権限がないためにどの機能が利用できないかを明記します。

  • ユーザー インターフェースをブロックしない。具体的には、アプリの使用を妨げるような全画面の警告メッセージは表示しないでください。

同時に、アプリは権限のリクエストを拒否するというユーザーの決定を尊重する必要があります。Android 11(API レベル 30)以降では、デバイスにインストールされたアプリの全期間に、同じ権限に対してユーザーが何度も [許可しない] をタップした場合、アプリがその権限を再度リクエストしても、ユーザーにシステム権限ダイアログが表示されることはありません。このユーザーのアクションにより、[次回から表示しない] が選択されたことになります。以前のバージョンでは、ユーザーが以前に [次回から表示しない] チェックボックスまたはオプションをオンにしていない限り、アプリが権限をリクエストするたびに、システム権限ダイアログが表示されていました。

ユーザーが権限リクエストを複数回拒否した場合、これは完全な拒否とみなされます。特定の機能へのアクセスを必要とする場合のみ権限の許可をユーザーに求めることが非常に重要です。そうしないと、権限を再リクエストできなくなる可能性があります。

状況によっては、権限が自動的に拒否され、ユーザーによるアクションを必要としない場合があります(権限が自動的に付与される場合もあります)。自動的な動作を想定しないことが重要です。権限を必要とする機能にアプリがアクセスするたびに、その権限がアプリに付与されていることを確認する必要があります。

アプリの権限を求めるときのユーザー エクスペリエンスを向上させるには、アプリの権限に関するおすすめの設定もご覧ください。

テストとデバッグ時の拒否ステータスの検査

アプリが(デバッグとテストを行う目的の)権限を完全に拒否されたかどうかを確認するには、次のコマンドを使用します。

adb shell dumpsys package PACKAGE_NAME

ここでの PACKAGE_NAME は検査するパッケージの名前です。

コマンドの出力には、次のようなセクションが含まれます。

...
runtime permissions:
  android.permission.POST_NOTIFICATIONS: granted=false, flags=[ USER_SENSITIVE_WHEN_GRANTED|USER_SENSITIVE_WHEN_DENIED]
  android.permission.ACCESS_FINE_LOCATION: granted=false, flags=[ USER_SET|USER_FIXED|USER_SENSITIVE_WHEN_GRANTED|USER_SENSITIVE_WHEN_DENIED]
  android.permission.BLUETOOTH_CONNECT: granted=false, flags=[ USER_SENSITIVE_WHEN_GRANTED|USER_SENSITIVE_WHEN_DENIED]
...

ユーザーが 1 回拒否した権限は、USER_SET によってフラグが設定されます。[拒否] を 2 回選択して恒久的に拒否された権限は、USER_FIXED によってフラグが設定されます。

テスト中はテスターにリクエスト ダイアログが表示されるようにして、アプリのデバッグが完了したら、これらのフラグをリセットしてください。これを行うには、次のコマンドを使用します。

adb shell pm clear-permission-flags PACKAGE_NAME PERMISSION_NAME user-set user-fixed

PERMISSION_NAME は、リセットする権限の名前です。

Android アプリの権限の一覧については、権限 API リファレンスのページをご覧ください。

1 回だけのアクセス許可

[今回のみ] というオプションは、ダイアログにある 3 つのボタンのうち 2 つ目のオプションです。
図 2. アプリが 1 回だけのアクセス許可をリクエストしたときに表示されるシステム ダイアログ

Android 11(API レベル 30)以降では、アプリが位置情報、マイク、またはカメラに関連する権限をリクエストするたびに、図 2 に示すように、ユーザー向けの権限ダイアログに [今回のみ] というオプションが表示されます。ユーザーがダイアログでこのオプションを選択した場合、アプリには一時的な「1 回だけのアクセス許可」が付与されます。

アプリの動作とユーザーの操作に応じて、アプリは該当するデータに一定時間アクセスできます。

  • アプリのアクティビティが表示されている間、アプリはデータにアクセスできます。
  • ユーザーがアプリをバックグラウンドに移行した場合、アプリは短時間だけ引き続きデータにアクセスできます。
  • アクティビティが表示されている間にフォアグラウンド サービスを起動した場合、ユーザーがアプリをバックグラウンドに移動しても、そのフォアグラウンド サービスが停止するまで、アプリは引き続きそのデータにアクセスできます。

権限が取り消されたときにアプリプロセスを終了する

ユーザーがシステム設定などで 1 回だけのアクセス許可を取り消した場合、アプリはフォアグラウンドサービスを開始したかどうかにかかわらず、データにアクセスできなくなります。他の権限と同様に、ユーザーがアプリの 1 回だけのアクセス許可を取り消すと、アプリのプロセスは終了します。

ユーザーが次にアプリを開いて、アプリ内の機能が位置情報、マイク、またはカメラへのアクセスをリクエストすると、ユーザーに再度権限の付与が求められます。

未使用の権限をリセットする

Android では、未使用の実行時の権限をデフォルトの拒否状態にリセットする方法がいくつか用意されています。

アプリのアクセス権を削除する

Android 13(API レベル 33)以降では、アプリで不要になった実行時の権限に対するアプリのアクセス権を削除できます。アプリを更新するときに、アプリが特定の権限を要求し続ける理由をユーザーが理解しやすくなるように、この手順を実施してください。このような情報提供は、アプリに対するユーザーの信頼を構築するうえで役立ちます。

実行時の権限へのアクセス権を削除するには、その権限の名前を revokeSelfPermissionOnKill() に渡します。実行時の権限のグループへのアクセス権を一度に削除するには、権限の名前のコレクションを revokeSelfPermissionsOnKill() に渡します。権限の削除プロセスは非同期で行われ、アプリの UID に関連付けられているすべてのプロセスが強制終了します。

システムが権限へのアプリのアクセス権を削除するには、アプリに関連付けられているすべてのプロセスを強制終了する必要があります。API の呼び出し時には、プロセスを強制終了しても問題ないタイミングをシステムが判断します。通常、システムは、アプリが長時間フォアグラウンド実行ではなくバックグラウンド実行であることを確認できるまで待機します。

アプリが特定の実行時の権限にアクセスする必要がなくなったことをユーザーに知らせるには、ユーザーが次回アプリを起動したときにダイアログを表示します。このダイアログに権限のリストを含めることができます。

使用していないアプリの権限を自動リセットする

Android 11(API レベル 30)以降をターゲットとするアプリを数か月間使用しないと、ユーザーデータを保護するため、システムはユーザーがアプリに付与した機密情報に関する実行時の権限を自動的にリセットします。詳細については、アプリの休止状態に関するガイドをご覧ください。

必要に応じてデフォルト ハンドラになるようリクエストする

アプリによっては、通話履歴や SMS メッセージに関するユーザーの機密情報にアクセスする必要があります。通話履歴や SMS メッセージにのみ使用される権限をリクエストするアプリを Play ストアに公開する場合は、実行時の権限をリクエストする前に、アプリを中核的システム機能のデフォルト ハンドラとして設定することをユーザーに求める必要があります。

デフォルト ハンドラの詳細(デフォルト ハンドラのプロンプトをユーザーに表示する方法など)については、デフォルト ハンドラでのみ使用される権限のガイドをご覧ください。

テスト用にすべての実行時の権限を付与する

エミュレータまたはテストデバイスにアプリをインストールする際にすべての実行時の権限を自動的に付与するには、次のコード スニペットに示すように、adb shell install コマンドで -g オプションを使用します。

adb shell install -g PATH_TO_APK_FILE

参考情報

権限について詳しくは、以下の記事をご覧ください。

権限のリクエストについての詳細は、権限のサンプルをご覧ください。

また、プライバシーに関するおすすめの方法が説明されている Codelab も活用してください。