page.title=パーミッション page.tags=previewresources, androidm page.keywords=パーミッション,実行時,プレビュー page.image={@docRoot}preview/features/images/permissions_check.png @jd:body

クイックビュー

本書の内容

  1. 概要
  2. 実行時のパーミッションのコード
  3. 実行時のパーミッションをテストする
  4. ベスト プラクティス

M Developer Preview では、アプリをインストールしてアップグレードするユーザーのプロセスを効率化する新しいアプリのパーミッション モデルが導入されました。 M Preview で実行しているアプリで新しいパーミッション モデルがサポートされている場合、ユーザーはアプリをインストールまたはアップグレードするときにパーミッションを付与する必要はありません。その代わりに、アプリは必要になるとパーミッションを要求し、パーミッションを確認するよう求めるダイアログが表示されます。

アプリで新しいパーミッション モデルがサポートされている場合、以前のバージョンの Android を実行している端末で、以前のパーミッション モデルを使ってインストールして実行することもできます。

概要

M Developer Preview とともに、プラットフォームでは新しいアプリのパーミッション モデルが導入されました。 この新しいモデルの主要なコンポーネントの概要を次に示します。

このパーミッション モデルにより、パーミッションを要求する機能に対するアプリの動作方法が変わります。 このモデルに合わせるために、従う必要のある開発プラクティスの概要を次に示します。

注: アプリのターゲットが M Developer Preview の場合、新しいパーミッション モデルを使う必要があります

M Developer Preview のローンチ時点では、すべての Google アプリで新しいパーミッション モデルが完全に実装されているわけではありません。 Google はこれらのアプリを M Developer Preview 中にアップデートして、パーミッションの切り替え設定を完全に実装します。

注: アプリに独自の API サーフェスがある場合、まず呼び出し側にそのデータへのアクセスに必要なパーミッションがあることを確認しないままパーミッションをプロキシしないでください。

システムアプリと署名のパーミッション

本来、ユーザーがアプリをインストールするとき、システムはアプリに {@link android.content.pm.PermissionInfo#PROTECTION_NORMAL PROTECTION_NORMAL} のみを付与します。ただし、特定の環境では、アプリにより多くのパーミッションが付与されます。

どちらの場合でも、ユーザーはシステムの [設定] 画面に移動して [アプリ] > [app_name] > [パーミッション] を選ぶと、いつでもパーミッションを取り消すことができます。アプリは実行時にパーミッションを継続して確認し、必要に応じて要求する必要があります。

上方互換と下方互換

アプリのターゲットが M Developer Preview 以外の場合、M Preview 端末でも以前のパーミッション モデルを引き続き使います。 ユーザーがアプリをインストールするとき、ユーザーはアプリのマニフェストでリストされているすべてのパーミッションを付与するように要求されます。

注: M Developer Preview を実行している端末で、ユーザーはアプリの [設定] 画面から従来のアプリを含むすべてのアプリのパーミッションをオフにできます。 従来のアプリに対してパーミッションをオフにすると、適切な機能がサイレント状態で無効になります。 アプリがそのパーミッションを必要とする操作を実行しようとするとき、その操作によって必ずしも例外が発生するとは限りません。 代わりに、空のデータセットを返す、エラーを示す、または予期しない動作を返すことがあります。 たとえば、パーミッションなしでカレンダーを照会すると、メソッドは空のデータセットを返します。

M Preview を実行していない端末で新しいパーミッション モデルを使ってアプリをインストールする場合、他のすべてのアプリと同様に扱われ、インストール時に、すべての宣言されたパーミッションを付与するようユーザーに求めます。

注: Preview リリースの場合、M Preview SDK に SDK の最小バージョンを設定して Preview SDK でコンパイルする必要があります。 つまり、Developer Preview 中は従来のプラットフォームでそのようなアプリをテストできません。

パーミッションとインテント

多くの場合、アプリがタスクを実行するには 2 つの方法から選択できます。 アプリ自体が操作を実行するパーミッションを要求できます。 アプリでインテントを使うようにして、別のアプリがそのタスクを実行するようにすることもできます。

たとえば、端末のカメラで写真を撮る機能がアプリに必要だとします。 アプリは android.permission.CAMERA パーミッションをリクエストでき、それによりアプリが直接カメラにアクセスできるようになります。 そのとき、アプリはカメラの API を使ってカメラを制御し、写真を撮ります。 このアプローチにより、アプリが写真のプロセスを完全に制御し、カメラの UI をアプリに組み込むことができます。

ただし、そのような制御が不要な場合は、{@link android.provider.MediaStore#ACTION_IMAGE_CAPTURE ACTION_IMAGE_CAPTURE} インテントを使うだけで画像を要求できます。 インテントを開始すると、カメラアプリ(デフォルトのカメラアプリがない場合)を選んでアプリで写真を撮るよう求めるメッセージが表示されます。 カメラアプリはアプリの {@link android.app.Activity#onActivityResult onActivityResult()} メソッドに写真を返します。

同様に、ユーザーの連絡先にアクセスするなどして電話をかける必要がある場合、適切なインテントを作成するか、パーミッションを要求して適切なオブジェクトに直接アクセスできます。 各アプローチにはメリットとデメリットがあります。

パーミッションを使う場合:

インテントを使う場合:

実行時のパーミッションのコード

アプリのターゲットが新しい M Developer Preview の場合、新しいパーミッション モデルを使う必要があります。 つまり、マニフェストで必要なパーミッションを宣言する他に、実行時にパーミッションがあることを確認し、まだパーミッションがない場合にはパーミッションを要求します。

新しいパーミッション モデルを有効にする

新しい M Developer Preview パーミッション モデルを有効にするには、アプリの targetSdkVersion 属性を "MNC" に、compileSdkVersion"android-MNC" に設定します。 このように設定することで、新しいパーミッション機能すべてが有効になります。

Preview リリースの場合、minSdkVersion"MNC" に設定して Preview SDK でコンパイルする必要があります。

M Preview のみに対するパーミッションの設計

アプリ マニフェストで新しい <uses-permission-sdk-m> 要素を使って、M Developer Preview のみで必要なパーミッションを表示できます。 このようにしてパーミッションを宣言すると、アプリを以前の端末にインストールする場合はユーザーにメッセージが表示されないか、アプリにパーミッションが付与されません。<uses-permission-sdk-m> 要素を使うと、新しいパーミッションを追加してインストールをアップデートするときにパーミッションの付与を強制せずにアプリのバージョンがアップデートされます。

M Developer Preview を使ってアプリが端末で実行されている場合、<uses-permission-sdk-m><uses-permission> と同じように動作します。 アプリをインストールするとき、パーミッションの付与を求めるメッセージは表示されず、アプリは必要なときにパーミッションを要求します。

パーミッションについてのダイアログを表示する

アプリで新しい M Developer Preview パーミッション モデルが使われている場合、M Preview を実行している端末でアプリを初めて起動するとき、すべての権限を付与する必要はありません。 その代わりに、アプリは必要なときにパーミッションを要求します。 アプリがパーミッションを要求すると、ユーザーにダイアログが表示されます。

SDK 22 以降がインストールされた端末でアプリを実行する場合、アプリでは以前のパーミッション モデルが使われます。 ユーザーがアプリをインストールすると、アプリがそのマニフェストで要求するすべてのパーミッションの付与を求めるメッセージが表示されます。ただし、<uses-permission-sdk-m> というラベルの付いたパーミッションは例外です。

アプリが実行されているプラットフォームを確認する

このパーミッション モデルは、M Developer Preview を実行している端末でのみサポートされます。 これらのメソッドのいずれかを呼び出す前に、アプリは {@link android.os.Build.VERSION#CODENAME Build.VERSION.CODENAME} の値を確認してどのプラットフォーム上で実行されているのかを確認する必要があります。 端末で M Developer Preview が実行されている場合、{@link android.os.Build.VERSION#CODENAME CODENAME} は "MNC" です。

アプリに必要なパーミッションがあるかどうかを確認する

ユーザーがパーミッションを要求する動作を行うと、アプリは現在この操作を実行するためのパーミッションがあるかどうかを確認します。 確認するために、アプリは Context.checkSelfPermission(permission_name) を呼び出します。ユーザーが既にパーミッションを付与していることをアプリが認識している場合でも、ユーザーはいつでもアプリのパーミッションを取り消すことができるため、この確認が行われます。 たとえば、ユーザーがアプリを使って写真を撮る場合、アプリは Context.checkSelfPermission(Manifest.permission.CAMERA) を呼び出します。

表 1.パーミッションとパーミッション グループ。

パーミッション グループ パーミッション
android.permission-group.CALENDAR
  • android.permission.READ_CALENDAR
  • android.permission.WRITE_CALENDAR
android.permission-group.CAMERA
  • android.permission.CAMERA
android.permission-group.CONTACTS
  • android.permission.READ_CONTACTS
  • android.permission.WRITE_CONTACTS
  • android.permission.READ_PROFILE
  • android.permission.WRITE_PROFILE
android.permission-group.LOCATION
  • android.permission.ACCESS_FINE_LOCATION
  • android.permission.ACCESS_COARSE_LOCATION
android.permission-group.MICROPHONE
  • android.permission.RECORD_AUDIO
android.permission-group.PHONE
  • android.permission.READ_PHONE_STATE
  • android.permission.CALL_PHONE
  • android.permission.READ_CALL_LOG
  • android.permission.WRITE_CALL_LOG
  • com.android.voicemail.permission.ADD_VOICEMAIL
  • android.permission.USE_SIP
  • android.permission.PROCESS_OUTGOING_CALLS
android.permission-group.SENSORS
  • android.permission.BODY_SENSORS
  • android.permission.USE_FINGERPRINT
android.permission-group.SMS
  • android.permission.SEND_SMS
  • android.permission.RECEIVE_SMS
  • android.permission.READ_SMS
  • android.permission.RECEIVE_WAP_PUSH
  • android.permission.RECEIVE_MMS
  • android.permission.READ_CELL_BROADCASTS

必要に応じてパーミッションを要求する

アプリに必要なパーミッションがない場合、アプリは Activity.requestPermissions(String[], int) メソッドを呼び出して適切なパーミッションを要求します。 アプリは必要なパーミッションと整数の「要求コード」を渡します。 このメソッドは非同期に機能します。このメソッドはすぐに返され、ユーザーがダイアログ ボックスに応答した後、システムはその結果と一緒にアプリのコールバック メソッドを呼び出し、アプリが requestPermissions() に渡すのと同じ「要求コード」を渡します。

次のコードは、ユーザーの連絡先を読み込むパーミッションがアプリにあることを確認し、必要に応じてパーミッションを要求します。

if (checkSelfPermission(Manifest.permission.READ_CONTACTS)
        != PackageManager.PERMISSION_GRANTED) {
    requestPermissions(new String[]{Manifest.permission.READ_CONTACTS},
            MY_PERMISSIONS_REQUEST_READ_CONTACTS);

    // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
    // app-defined int constant

    return;
}

パーミッションの要求への応答を処理する

アプリがパーミッションを要求すると、システムによってダイアログ ボックスが表示されます。 ユーザーが応答すると、システムはアプリの Activity.onRequestPermissionsResult(int, String[], int[]) を呼び出し、ユーザーの応答を渡します。 アプリはそのメソッドをオーバーライドする必要があります。コールバックには開発者が requestPermissions() に渡したのと同じ要求コードが渡されます。 たとえばアプリが READ_CONTACTS アクセスを要求する場合、次のコールバック メソッドが含まれる可能性があります。

@Override
public void onRequestPermissionsResult(int requestCode,
        String permissions[], int[] grantResults) {
    switch (requestCode) {
        case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                // permission was granted, yay! do the
                // calendar task you need to do.

            } else {

                // permission denied, boo! Disable the
                // functionality that depends on this permission.
            }
            return;
        }

        // other 'switch' lines to check for other
        // permissions this app might request
    }
}

ユーザーがパーミッションを付与すると、システムは、機能領域のアプリ マニフェストがリストするすべてのパーミッションを付与します。 ユーザーが要求を拒否する場合は、適切なアクションを取ってください。 たとえば、このパーミッションに応じて、すべてのメニュー アクションを無効にできます。

ユーザーにパーミッションの付与を確認するとき、ユーザーにそのパーミッションについて再度確認しないようにするオプションがあります。 この場合、アプリが requestPermissions() を使ってパーミッションを確認すると、システムはその要求をすぐに拒否します。 この場合、システムはユーザーが要求を再度明示的に拒否する場合と同様に onRequestPermissionsResult() を呼び出します。 このため、アプリではユーザーとの直接的なやり取りが発生することが想定されません。

実行時のパーミッションをテストする

アプリのターゲットが M Developer Preview の場合、パーミッションが正しく処理されることをテストする必要があります。 アプリ起動時に特定のパーミッションがアプリにあることは想定できません。 アプリが初めて起動されるとき、パーミッションがない可能性が高く、ユーザーはいつでもパーミッションを取り消すまたは復元できます。

アプリがすべてのパーミッションの状況下で確実に正しく動作することをテストしてください。 M Preview SDK とともに、新しい Android デバッグ ブリッジ(adb)コマンドが導入され、試す必要のあるあらゆるパーミッション設定でアプリをテストできます。

新しい adb コマンドとオプション

M Preview SDK Platform-tools では、アプリがパーミッションをどう処理するかをテストするための、いくつかの新しいコマンドが導入されました

パーミッション付きでインストールする

adb install コマンドの新しい -g オプションを使ってアプリをインストールし、そのマニフェストにリストされるすべてのパーミッションを付与できます。

$ adb install -g <path_to_apk>

パーミッションの付与と取り消し

新しい ADB Package Manager(pm)コマンドを使って、インストールされているアプリにパーミッションを付与したり取り消したりできます。この機能は自動化されたテストに役立ちます。

パーミッションを付与するには、Package Manager の grant コマンドを使います。

$ adb pm grant <package_name> <permission_name>

たとえば、com.example.myapp パッケージ パーミッションを付与してオーディオを録音するには、このコマンドを使います。

$ adb pm grant com.example.myapp android.permission.RECORD_AUDIO

パーミッションを取り消すには、Package Manager の revoke コマンドを使います。

$ adb pm revoke <package_name> <permission_name>

ベスト プラクティス

新しいパーミッション モデルにより、ユーザーはよりスムーズな操作感を得られ、アプリを簡単にインストールできるようになり、アプリが実行している内容に満足します。 新しいモデルを最大限に活用するために、次のベスト プラクティスをお勧めします。

必要なパーミッションのみを要求する

パーミッションを要求するたびに、ユーザーに決定するよう強制します。 ユーザーが要求を却下すると、アプリの機能が低下します。 これらの要求回数は最小限にしてください。

たとえば、アプリがパーミッションを要求する代わりに、インテントを使って必要な機能を取得できる場合がよくあります。 アプリが携帯電話のカメラで写真を撮る必要がある場合、そのアプリでは {@link android.provider.MediaStore#ACTION_IMAGE_CAPTURE MediaStore.ACTION_IMAGE_CAPTURE} インテントを使用できます。 アプリがインテントを実行すると、写真を撮るためのインストール済みのカメラアプリを選ぶようユーザーに促します。

ユーザーを疲れさせない

ユーザーにパーミッションをたくさん要求すると、ユーザーを疲れさせてしまい、アプリが終了される原因になります。代わりに、ユーザーには必要なパーミッションのみを要求してください。

アプリ対して 1 つ以上のパーミッションが必須である場合もあります。その場合は、アプリの起動後すぐに、すべてのパーミッションを要求することが合理的である場合があります。 たとえば、カメラアプリを作成する場合、アプリは端末のカメラにアクセスする必要があります。 アプリを初めて起動するときにカメラの使用についてのパーミッションを求められても驚かないはずです。 ただし、同じアプリにユーザーの連絡先と写真を共有する機能もある場合は、最初の起動時にパーミッションを要求しない方が無難です。 その代わりに、ユーザーが「共有」機能を使うまで待ち、そのときにパーミッションを要求します。

アプリにチュートリアルが含まれる場合は、チュートリアルのシーケンスの最後で、アプリに必須のパーミッションを要求する方が合理的です。

パーミッションが必要な理由を説明する

requestPermissions() を呼び出すとき、システムによって表示されるパーミッション ダイアログにはアプリが必要としているパーミッションは表示されますが、理由は表示されません。 これによりユーザーが困惑する場合もあります。 requestPermissions() を呼び出す前に、アプリがパーミッションを必要としている理由をユーザーに説明するのはよい方法です。

たとえば、カメラアプリでは、位置情報サービスを使って写真に位置情報タグを付けられるようにする場合があります。 通常のユーザーは、写真に位置情報が含まれる場合があることを認識していない可能性があり、なぜカメラアプリで位置情報が必要なのか困惑する可能性があります。 この場合、アプリが requestPermissions() を呼び出すに、この機能についてユーザーに知らせることをお勧めします。

その方法として、これらの要求をアプリのチュートリアルに組み込むこともできます。チュートリアルでは、アプリの各機能を順番に表示できるので、必要なパーミッションを説明できます。 たとえば、カメラアプリのチュートリアルでは、「連絡先と写真を共有する」機能について説明し、ユーザーの連絡先を参照するためにアプリにパーミッションが必要であることをユーザーに知らせることができます。 その後、アプリは requestPermissions() を呼び出して、ユーザーにそのアクセスを求めることができます。 もちろん、すべてのユーザーがチュートリアルに従うわけではないため、アプリの通常操作中にパーミッションを確認して要求することも必要です。