Android M以降、ストレージの使用や位置情報の使用など、ユーザに許可を求めるタイミングが、当該機能を実行する直前になりました(ランタイムパーミッション)。より文脈の中で問いかけすることを意識したフローに変更になったわけですが、どういうフローで許可を求めるべきなのか、改めてガイドラインを見てみました。
参考:https://developer.android.com/training/permissions/requesting.html
流れ
ざっくりとした流れは、このサイトが参考になるかもしれません。
http://sys1yagi.hatenablog.com/entry/2015/11/07/185539
一応、許可を求めて、権限を取得して実行する流れをおさらいしておくと、
- 権限を持っているか確認
- 要求に際して説明が必要かどうかを確認(初回の要求かをチェックして、2回目以降は説明が必要)。必要であればダイアログなどを表示して、権限の許可が必要な理由をユーザに説明する。
- 権限取得のダイアログを表示する。許可が出れば終了。拒否された場合は、さらに追加で説明を出すことができる。
こんな感じの流れでした。
実装
サンプルを見てみましょう。ここでは、最初に挙げたDeveloperサイトのサンプルに、実例を入れつつ書いてみたいと思います。
requestPermissions
// thisActivity: 現在のActivity
// 許可を持っているかどうかを確認する(必要な権限全て確認する)
// Android M 未満の端末にも対応するなら、PermissionCheckerを使うのが安全
if (PermissionChecker.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED
|| PermissionChecker.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
// 権限を要求する「根拠」を説明すべきかどうかを確認
if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity, Manifest.permission.CAMERA)
|| ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
// 必要があれば説明ダイアログを表示
AlertDialog.Builder builder = new AlertDialog.Builder(this);
...
// Dialogを表示したあと、再度、許可を求める(requestPermissionする)
...
builder.show();
} else {
// 説明が必要ない場合は、そのまま通常通り、requestPermissionする
ActivityCompat.requestPermissions(thisActivity,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA},
MY_PERMISSIONS_REQUEST_CAMERA_AND_STRAGE);
// MY_PERMISSIONS_REQUEST_CAMERA_AND_STRAGEは: intの定数, リクエストコード
}
}
// ここ以降は、権限を持っている場合の処理
onRequestPremissionsResult
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_CAMERA_AND_STRAGE: {
// リクエストがキャンセルされた場合、配列のサイズは0
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED
&& grantResults[1] == PackageManager.PERMISSION_GRANTED) {
// 許可されたので、処理を続行する
} else {
// 拒否されたため、フロー終了。
// 追加の説明をすることもできる(権限の要求はしない)
}
return;
}
// other 'case' lines to check for other
// permissions this app might request
}
}
ざっくり、以上のような実装になります。
ユーザがより詳細に、アプリの権限を設定できるようになった分、なおさら、
適切な(Googleポリシーに則った)フローで求めるようにしましょう。