android6系からは、アプリのインストール者が自らアプリに必要な権限の有効・無効を設定することができるようになりました。
権限が無効なまま権限が必要な操作をされてしまうと、アプリが落ちてしまうなどしてしまうので、
必要な権限をonにすることをアプリ側で知らせないといけなくなりました。
これらを実装するときに、その場で必要なものだけをinputして組んでいたので、
よくまとまっていたgoogleのandroid-Cemera2Videoを例に一度まとめていみたいと思います。
必要な権限を知らせるタイミング
sampleでは、cameraを開くタイミングでカメラを使用するのに必要な
権限チェックをしています。
まずは、必要な権限がonになっているかをチェックします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
private static final String[] VIDEO_PERMISSIONS = { Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO, Manifest.permission.WRITE_EXTERNAL_STORAGE }; private boolean hasPermissionsGranted(String[] permissions) { for (String permission : permissions) { if (ActivityCompat.checkSelfPermission(getActivity(), permission) != PackageManager.PERMISSION_GRANTED) { return false; } } return true; } |
必要な権限のチェックは、ActivityCompat.checkSelfPermission関数で判定します。
Fragmentの場合もFragmentCompat.checkSelfPermission関数が定義されています。
また、supportLibraryのクラスとして、PermissionChecker classも使用することができます。
権限が有効でない場合、権限を有効にするようユーザに要求します。
1 2 3 4 5 6 7 8 9 10 |
/** * Requests permissions needed for recording video. */ private void requestVideoPermissions() { if (shouldShowRequestPermissionRationale(VIDEO_PERMISSIONS)) { new ConfirmationDialog().show(getChildFragmentManager(), FRAGMENT_DIALOG); } else { FragmentCompat.requestPermissions(this, VIDEO_PERMISSIONS, REQUEST_VIDEO_PERMISSIONS); } } |
ここで、以前ユーザに権限チェックを要求したときに、拒否された場合はtrueを返す
shoulShowRequestPermissionRationaleを呼んでいます。
trueの場合は権限確認ダイアログを出します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
public static class ConfirmationDialog extends DialogFragment { @Override public Dialog onCreateDialog(Bundle savedInstanceState) { final Fragment parent = getParentFragment(); return new AlertDialog.Builder(getActivity()) .setMessage(R.string.permission_request) .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { FragmentCompat.requestPermissions(parent, VIDEO_PERMISSIONS, REQUEST_VIDEO_PERMISSIONS); } }) .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { parent.getActivity().finish(); } }) .create(); } } |
権限有効化okの場合権限を有効にするかを設定できるダイアログを出現させる
requestPermissions関数を呼び出します
第2引数に必要なpermissionの文字列を第3引数にcallback関数として呼ばれる
onRequestPermissionResult関数のrequestCodeにあたる数値をいれます。
では、onRequestPermissionResult関数の中身です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { Log.d(TAG, "onRequestPermissionsResult"); if (requestCode == REQUEST_VIDEO_PERMISSIONS) { if (grantResults.length == VIDEO_PERMISSIONS.length) { for (int result : grantResults) { if (result != PackageManager.PERMISSION_GRANTED) { ErrorDialog.newInstance(getString(R.string.permission_request)) .show(getChildFragmentManager(), FRAGMENT_DIALOG); break; } } } else { ErrorDialog.newInstance(getString(R.string.permission_request)) .show(getChildFragmentManager(), FRAGMENT_DIALOG); } } else { super.onRequestPermissionsResult(requestCode, permissions, grantResults); } } |
permissionを要求した結果がint[] grantResults内に返却されます。
sampleでは、権限要求に応じなかった場合はErrorDialogを出しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
public static class ErrorDialog extends DialogFragment { private static final String ARG_MESSAGE = "message"; public static ErrorDialog newInstance(String message) { ErrorDialog dialog = new ErrorDialog(); Bundle args = new Bundle(); args.putString(ARG_MESSAGE, message); dialog.setArguments(args); return dialog; } @Override public Dialog onCreateDialog(Bundle savedInstanceState) { final Activity activity = getActivity(); return new AlertDialog.Builder(activity) .setMessage(getArguments().getString(ARG_MESSAGE)) .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { activity.finish(); } }) .create(); } } |
sampleでは、こんな感じで実装されていました。
android developerページでもtutotiralが日本語で上がっています。
いざ既存のアプリで対応する場合処理ごとにまとまっていれば、対応するものそう大変そうではないですが、
そうじゃないと大変そうですね。