Android6.0 (M) からの許可ダイアログを表示するPermissionsへの対応方法

Android6.0(Android M)が発表されましたので、
Andorid6.0から新規に追加されたアプリの権限(Permissions)の対応方法をまとめます。

![許可ダイアログ.png](https://qiita-image-store.s3.amazonaws.com/0/34488/204f1b2c-b726-64fa-4b5f-694338eea167.png)

#Android6.0未対応のアプリの挙動
targetSDKを23にしていない場合、既存アプリの起動時に変化はありません。
また、Android5.1以下では従来通りアプリのインストール時にpermissionを求めます。

しかし、targetSDKを23にしていない場合でも、
Android6.0から設定画面に新規追加された「アプリの権限」画面から
permissionをOFFにできるようになっています。
（targetSDKが22以下の場合、デフォルトではONになっています。）

permissionがOFFになっている状態で許可が必要なメソッドにアクセスすると、
空のデータが返されたり、アプリが例外を返します。

![アプリの権限.png](https://qiita-image-store.s3.amazonaws.com/0/34488/d62c91b1-0385-22c8-0c7f-8d4365fe85a3.png)

#Android6.0でのPermissionへの対応方法

###1. AndroidManifest.xmlへの記述
これまで通りアプリが必要とするpermissionはAndroidManifest.xmlに記述する必要があります。
この時、インターネットの使用(android.permission.INTERNET)などの
"PROTECTION_NORMAL"に属するpermissionは
インストールやアップデート時に自動的に許可されます。

###2. 許可状態の確認
Permission Groupに属するpermissionやPROTECTION_DANGEROUSなpermissionを
必要とする機能を使用する前には、
事前にpermissionの許可状態を確認しなければいけません。
アプリ内で一度許可されていても設定からユーザーがオフにすることがあるため、
毎回確認する必要があります。
確認するには checkSelfPermission(String permission) のメソッドを使用します。
compileSDKを23にすることでAPI level 23の上記メソッドの使用は可能です。

###3. 許可を求める理由の説明
許可ダイアログに表示される文言はOSによって固定されており変更できません。
許可ダイアログを表示する前にUI上で許可を求める理由を説明する必要があります。

![許可ダイアログ2.png](https://qiita-image-store.s3.amazonaws.com/0/34488/55b762de-414d-d612-2b9a-0dcc0be24b67.png)

###4. 許可ダイアログの表示


許可されていなければAndroid標準の許可ダイアログを表示して、
ユーザに許可してもらう必要があります。
上の画像の許可ダイアログの表示には
requestPermissions (String[] permissions, int requestCode)を使用します。
第一引数が配列になっているため、複数のpermissionを一度に求めることが可能です。
複数のpermissionを指定した場合には、許可ダイアログが１つずつ複数表示されます。

```java
if (checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {

    // permissionが許可されていません
    if (shouldShowRequestPermissionRationale(Manifest.permission.READ_CONTACTS)) {
        // 許可ダイアログで今後表示しないにチェックされていない場合
    }

    // permissionを許可してほしい理由の表示など

    // 許可ダイアログの表示
    // MY_PERMISSIONS_REQUEST_READ_CONTACTSはアプリ内で独自定義したrequestCodeの値
    requestPermissions(new String[]{Manifest.permission.READ_CONTACTS},
            MY_PERMISSIONS_REQUEST_READ_CONTACTS);

    return;
}

```

###5. 許可ダイアログに対してユーザーが選択した結果の受け取り

```java
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
    switch (requestCode) {
        // 先ほどの独自定義したrequestCodeの結果確認
        case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // ユーザーが許可したとき
                // 許可が必要な機能を改めて実行する
            } else {
                // ユーザーが許可しなかったとき
                // 許可されなかったため機能が実行できないことを表示する
            }
            return;
        }
    }
}

```

##許可ダイアログを出さずに必要な機能を使用する方法
Googleは許可ダイアログを表示させずに必要な機能を使用する方法の１つとして
Intentによる機能の呼び出しを紹介しています。
例として、写真を撮ることをアプリが目的とする場合に
android.permission.CAMERAの許可を取得して
アプリ側でカメラ撮影機能を実装する手段もありますが、
MediaStore.ACTION_IMAGE_CAPTUREのIntentを使用して
カメラアプリを呼び出して撮影した結果をonActivityResultで受け取る方法を紹介しています。
この方法であれば自アプリはandroid.permission.CAMERAの許可を必要としません。

#Permission変更点まとめ

##Permisson Groupsの追加
既存のPermissionがいくつかのグループに分けられました。
設定に表示されているpermissionはグループで表示されており、
グループ単位でのpermissionの許可/非許可が選択できます。

Permission GroupのPermission一覧
https://developer.android.com/preview/features/runtime-permissions.html#permission-groups

##PROTECTION_NORMALのPermission一覧
PROTECTION_NORMALに属する以下のpermissionについて、
checkSelfPermission()やrequestPermissions()を行う必要はありません。

Normal Permisssions
https://developer.android.com/preview/features/runtime-permissions.html#normal


#まとめ
Android6.0から変更されたPermission Modelについてまとめました。
アプリが機能するために必要なpermissionを取得するために、
許可ダイアログの表示や説明の表示などの対応を行う必要があります。

#参考
公式Reference
https://developer.android.com/preview/features/runtime-permissions.html
公式Reference（日本語版）
（※情報が更新されていないようなので、最新情報は英語版を確認してください）
https://developer.android.com/intl/ja/preview/features/runtime-permissions.html
Googleによるサンプル
https://github.com/googlesamples/android-RuntimePermissionsBasic
PermissionのprotectionLevelについて
http://qiita.com/ShogoMizumoto/items/62b1d6fe76e577af75e6
shouldShowRequestPermissionRationaleメソッドの補足：
http://brightechno.com/blog/archives/355