アプリの権限をリクエストする

すべての Android アプリは、アクセスが制限されたサンドボックス内で実行されます。アプリ自体のサンドボックスの外部にあるリソースや情報を使用しなければならない場合は、適切な権限をリクエストする必要があります。アプリ マニフェストに権限をリストすることにより、アプリが権限を必要としていることを宣言し、実行時に権限ごとにユーザーの承認をリクエストします(Android 6.0 以降)。

次の基本原則があります。

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

このページでは、アプリに権限を追加する手順と、必要に応じてそれらの権限を実行時にリクエストする手順を詳しく説明します。

マニフェストに権限を追加する

アプリが権限を必要としていることを宣言するには、Android のバージョンにかかわらず、アプリ マニフェスト内で最上位の <manifest> 要素の子要素として <uses-permission> 要素を挿入します。

たとえば、アプリでインターネットにアクセスする必要がある場合は、マニフェストに次の行を記述します。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.snazzyapp">

    <uses-permission android:name="android.permission.INTERNET"/>
    <!-- other permissions go here -->

    <application ...>
        ...
    </application>
</manifest>

権限を宣言した後のシステムの動作は、権限の保護レベルによって異なります。「normal」とみなされる権限はインストール直後にシステムによって付与されますが、「dangerous」とみなされる権限については、ユーザーがアプリのアクセスを明示的に許可する必要があります。権限の種類について詳しくは、保護レベルをご覧ください。

権限を確認する

アプリに dangerous 権限が必要な場合は、dangerous 権限が必要な操作を実行するたびに、権限の有無を確認する必要があります。Android 6.0(API レベル 23)以降では、ユーザーは任意のアプリから dangerous 権限をいつでも取り消すことができます。

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

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

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

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

権限をリクエストする

ユーザーに説明 UI を表示してアプリに特定の権限が必要な理由を説明した後、あるいは、shouldShowRequestPermissionRationale()false を返した後、requestPermissions() を呼び出して、権限をリクエストするシステム ダイアログを表示します。requestPermissions() を呼び出すときは、整数のリクエスト コードを渡す必要があります。このコードは、権限リクエストへの応答を処理するときに再度使用します。

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

また、権限をリクエストするシステム ダイアログのテキストでは、リクエストする権限に関連付けられた権限グループを参照します。この権限グループはシステムを使いやすくするように設計されたものであり、アプリでは、権限が特定の権限グループ内またはグループ外にあることに依存しないようにしてください。

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

Kotlin

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

Java

if (ContextCompat.checkSelfPermission(
        CONTEXT, Manifest.permission.REQUESTED_PERMISSION) ==
        PackageManager.PERMISSION_GRANTED) {
    // You can use the API that requires the permission.
    performAction(...);
} else if (shouldShowRequestPermissionRationale(...)) {
    // In an educational UI, explain to the user why your app requires this
    // permission for a specific feature to behave as expected. In this UI,
    // include a "cancel" or "no thanks" button that allows the user to
    // continue using your app without granting the permission.
    showInContextUI(...);
} else {
    // You can directly ask for the permission.
    requestPermissions(...);
}

権限リクエストへの応答を処理する

ユーザーがアプリからの権限のリクエストに応答すると、システムはアプリの 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 features 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 onRequestPermissionsResults(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 features 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.
    }
}

権限の拒否を処理する

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

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

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

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

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

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

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

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

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

API レベルで権限を宣言する

実行時の権限をサポートするデバイス、つまり Android 6.0(API レベル 23)以降を実行しているデバイスでのみ権限を宣言するには、uses-permission タグではなく uses-permission-sdk-23 タグを追加します。

このいずれかのタグを使用すると、maxSdkVersion 属性を設定して、新しいバージョンが実行されているデバイスでは特定の権限が不要であることを指定できます。

参考情報

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

権限のリクエストについて詳しくは、以下のサンプルアプリをダウンロードしてください。

  • Android RuntimePermissionsBasic サンプル Java | Kotlin