Requesting Permissions at Run Time 翻訳
Android Developersサイトにあるトレーニングページの翻訳です。今回は、Android6.0で導入されたRun Time Permissionの解説そのものになります。
Requesting Permissions at Run Time
URL: http://developer.android.com/intl/ja/training/permissions/requesting.htmlアンドロイド6.0(API Level23)からアプリケーションのインストール時ではなく、実行時にパミッションを付与するようになりました。
このアプローチは、インストール、アップデート時にパミッションを付与する必要がないので、アプリのインストールプロセスが合理化されました。
また、これにより、ユーザはアプリケーションの機能をより詳細に制御できます。例えばカメラアプリに対して、位置情報の権限は与えずにカメラ機能へのアクセスのみ与えるといった事ができます。
また、ユーザは、アンドロイドの設定画面に移動して、任意のタイミングで、アプリに付与したパミッションを取り消す事ができます。
システムパミッションは、「Normal」「Dangerous」の二つのカテゴリ(Protection level)に分類されます。
- Normal Permissionは、ユーザのプライバシーに直接危険がない物です。アプリのマニュフェストファイルに、ノーマルパミッションの利用宣言をした時、システムは自動的にそれらのパミッションの権限を付与します。
- Dangerous Permissionは、ユーザの機密データにアクセス権を与える事ができます。アプリのマニュフェストファイルにノーマルパミッションの利用宣言をした時、システムは自動的にそれらのパミッションの権限を付与します。デンジャラスパミッションは、ユーザが明示的にアプリに許可を与えます。
アンドロイドの全てのバージョンで、アプリケーションは、アプリケーションで使用するNormal,Dangerous両方のタイプのパミッションをマニュフェスト上に利用宣言する必要があります。(「Declaring Permissions」で説明したように)
しかしながら、その宣言の効果は、システムのバージョンとアプリケーションのtarget SDKレベルに応じて異なります。
Android5.1以下の場合か、アプリのTargetSDKが22以下の時:
マニュフェストに記載されたDangerousパミッションは、ユーザがアプリをインストール時に権限を付与する必要があります。権限を付与したくない場合、システムはアプリをインストールしません。(訳注:アップデートインストール時も考慮した説明になっている)
Android 6.0以上の場合、かつアプリのTargetSDKが23以上の時
アプリは、マニュフェストにパミッションの記載をしており、アプリケーションが動作中に必要な時にDangerousパミッションの利用許可も求めます。ユーザはそれぞれのパミッションに対して、許可・不許可がする事が可能で、ユーザがパミッションを不許可にした場合でも、限られた範囲の中で動作し続けるようにします。NOTE:このレッスンでは、アンドロイドのサポートライブラリを用いて、パミッションのチェック、要求する方法について説明します。アンドロイドのフレームワークは、Android6.0(API Level23)と同様のメソッドを提供します。アプリケーションは、実行しているアンドロイドのバージョンをチェックする必要はありませんので、サポートライブラリを利用すると簡単になります。
このレッスンでは、API Level23以上での新しいパミッション要求の実装をし、アンドロイド6.0(API Level23)以上のデバイスで実行している場合の方法について説明します。デバイス、アプリ、tartgetSdkVersionが22以下の場合、システムはインストール時及びアップデート時に、全てのDangerousパミッションの権限の付与をユーザに要求します。
Check For Permissions
あなたのアプリがDangerousパミッションを必要とする時、そのパミッションを必要とする操作を実行するたびに、その権限を持っているかを確認する必要があります。
これは、ユーザは何時でも自由に権限を取り消す事が出来るからです。アプリは昨日カメラ機能を使ったとしても、今日そのカメラパミッションを持っているとは限りません。
(訳注:システム設定で、アプリケーションからパミッションの許可を取り消すことが可能。アプリケーションが動作している時でも、タスク切り替えによりパミッションの許可を取り消す事が可能な事に注意する事)
パミッションを持っているかのチェックは、ContextCompat.checkSelfPermission()メソッドを使用します。
例えば以下のスニペットは、アクティビティがカレンダーへの書き込みのパミッションを持っているかをどのようにチェックしているかを表しています。
// Assume thisActivity is the current activity int permissionCheck = ContextCompat.checkSelfPermission(thisActivity, Manifest.permission.WRITE_CALENDAR);
アプリケーションがWRITE_CALENDARパミッションを持っている場合、このメソッドはPackageManager.PERMISSION_GRANTEDを返し、アプリはカレンダーへの書き込み処理を続行できます。
アプリケーションがWRITE_CALENDAR権限を持っていない場合は、メソッドは、PERMISSION_DENIEDを返し、アプリは、ユーザに明示的にパミッションの使用許可を求めていきます。
Request Permissions
マニュフェストに記載したDangerousパミッションが必要な時は、ユーザに許可を依頼する必要があります。アンドロイドにはパミッションのリクエストをするためのいくつかのメソッドが用意されています。
これらのメソッドを呼び出すと、標準のアンドロイドダイアログが表示されます。これらのダイアログはカスタマイズをする事ができません。
Explain why the app needs permissions
いくつかの状況では、あなたのアプリがパミッションを何故必要とするのかをユーザが理解するさせたい事があります。例えば、ユーザが写真撮影アプリを起動した時、そのアプリがカメラパミッションを要求したとしても驚かないでしょう。しかし、場所や連絡先データへのアクセスを要求した時、その理由はユーザにはわからない場合があります。
従って、権限を要求する前に、ユーザへの説明を提供する事を検討すべきです。
ユーザを圧倒するほど説明をしないように注意してください。あまりに多くの説明を提供している場合、ユーザはアンインストールして別のアプリにしてしまう事があります
説明を提供する一つの手法としては、ユーザが一度パミッションの使用を拒否した時にのみ説明を提供する事です。
ユーザが許可要求を拒否し、チェックボックス「今後は使用しない(Never Ask Again)」にチェックをしていない時は、おそらくアプリがそのパミッションを必要とする理由をユーザが理解していない事を示しています。
そのような状況で、説明を表示する事をお勧めします。
このような、ユーザが説明を必要としているかもしれない状況を見つけるために、アンドロイドはユーティリティメソッドshouldShowRequestPermissionRationale()を用意しています。
このメソッドは、以前にこの権限を要求し、ユーザが要求を拒否した場合、trueを返します。
NOTE:
ユーザがパミッションの要求を拒否し、チェックボックス「今後は使用しない(Never Ask Again)」にチェックを入れたとき、このメソッドはfalseを返します。
このメソッドは、デバイスポリシによりアプリがこのパミッションを持つのを禁止している場合falseを返します
Request the permissions you need
アプリが必要な権限を持っていない場合。アプリケーションは、適切なパミッションを要求するためにrequestPermissions()メソッドを呼び出す必要があります。requestPermissions()メソッドには、取得したいパミッション(複数可)と許可要求を識別するための「リクエストコード」と呼ばれるIntegerの値を渡します。
このメソッドは非同期です:このメソッドはユーザが、ダイアログボックスに応答した後すぐに帰ってきます。システムはアプリケーションのコールバックメソッドを結果と、requestPermissions()メソッドに渡したリクエストコードを付けて呼び出します。
以下のコードは、アプリは、ユーザの連絡先の読み取り権限を持っているかをチェックし、必要であれば読み取り権限を取得します
// Here, thisActivity is the current activity if (ContextCompat.checkSelfPermission(thisActivity, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { // Should we show an explanation? if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity, Manifest.permission.READ_CONTACTS)) { // Show an expanation to the user *asynchronously* -- don't block // this thread waiting for the user's response! After the user // sees the explanation, try again to request the permission. } else { // No explanation needed, we can request the permission. ActivityCompat.requestPermissions(thisActivity, new String[]{Manifest.permission.READ_CONTACTS}, MY_PERMISSIONS_REQUEST_READ_CONTACTS); // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an // app-defined int constant. The callback method gets the // result of the request. } }
NOTE:
アプリがrequestPermissions()を呼び出した時、システムはユーザに標準のダイアログボックスを表示します。
あなたのアプリは、このダイアログボックスを変更したり、他の物に変える事はできません。
もし、ユーザに(パミッションについての)情報や説明を提供する必要があれば、requestPermissions()を呼ぶ前に何故アプリがパミッションを必要とする理由を説明してください。
Handle the permissions request response
アプリがパミッションを要求すると、システムはユーザにダイアログボックスを表示します。ユーザがダイアログボックスに応答(許可・不許可等)すると、システムは、ユーザの応答結果と共にアプリケーションのonRequestPermissionsResult()メソッドを呼び出します。
アプリは権限が付与されたかどうかを確認するために、onRequestPermissionsResult()をオーバーライドする必要があります。
コールバックには、requestPermissions()に渡された同じ「リクエストコード」が渡されます。
例えばアプリがREAD_CONTACTSへのアクセスを要求する場合。以下のようなコールバックメソッドを実装する必要があります。
@Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { switch (requestCode) { case MY_PERMISSIONS_REQUEST_READ_CONTACTS: { // If request is cancelled, the result arrays are empty. if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // permission was granted, yay! Do the // contacts-related task you need to do. } else { // permission denied, boo! Disable the // functionality that depends on this permission. } return; } // other 'case' lines to check for other // permissions this app might request } }システムによって表示されるダイアログボックスは、アプリケーションが必要とするパミッショングループを表示します。(訳注:パミッションを指定するが、パミッショングループが表示されます)
指定したパミッションは表示されません。例えばREAD_CONTACTSパミッションを要求した時、システムダイアログは、「連絡先へのアクセスの許可を付与しますか?と表示します。
ユーザは、各パミッショングループに1度だけアクセス許可を与える必要があります。
あなたのアプリが、パミッショングループ内の他のパミッションを要求し許可された場合(もちろんアプリのマニュフェストには記載済の事)、システムは自動的にアクセス権限を付与します。
パミッションを要求すると、システムはアプリのonRequestPermissionsResult()コールバックメソッドにPERMISSION_GRANTEDを渡して呼び出します。これはユーザがあなたのリクエストに応じてシステムダイアログで許可を与えた事を表します。
NOTE:例えば、アプリケーションのマニュフェストファイルにREAD_CONTACTSとWRITE_CONTACTSが記載されているとします。
アプリは同じグループに所属している場合であっても、全てのパミッションを要求する必要があります。
パミッションのグループ化は、将来のアンドロイドのリリースで変更される事があります。
あなたのコードは、特定のパミッションが同じグループに所属しているか、いないかの前提に依存すべきではありません。
(訳注:同じグループに所属しているので、requestPermissions()にREAD_CONTACTSだけ指定すれば良いといった方針は間違いで、将来WRITE_CONTACTSがコンタクトグループの所属から外れる事も考えられるので(例ですが)ちゃんと全てリクエストするようにしてくださいという事)
READ_CONTACTSのパミッションを要求し、ユーザがその許可を与え、次にWRITE_CONTACTSのパミッションを要求した場合、ユーザによる許可は必要とせずにすぐにその権限を付与します。
ユーザがパミッションの要求を拒否した場合も想定して、アプリケーションは適切な処理をする必要があります。
例えば、何故ユーザが要求した機能を実行できないのか理由を説明するダイアログを表示する事もあるでしょう
システムがユーザにパミッションの許可を求める時、「今後は使用しない(Never Ask Again)」チェックボックスをオプション表示します。チェックされた時、requestPermissions()を使用してパミッションを再度要求しても、システムはその要求を拒否します。その後システムによって呼ばれるonRequestPermissionsResult()メソッドにPERMISSION_DENIEDが渡されます。この値はユーザが明示的にUI上で拒否した時の値と同じです。
これは、requestPermissions()した時に、ユーザが直接明示的にUI上で拒否をしたのか、「今後は使用しない(Never Ask Again)」チェックが付いているためにUI表示されず拒否されたのか区別がつかない事を表します。
Working with Permissionチュートリアル
Declaring Permissions(パミッションの宣言) 原文Declaring Permissions(パミッションの宣言) 翻訳
Requesting Permissions at Run Time(実行時のパミッション要求 原文
Requesting Permissions at Run Time(実行時のパミッション要求 翻訳
Permissions Best Practices(ベストプラクティス)原文
Permissions Best Practices(ベストプラクティス)翻訳