Request Permissionの実装と、UX（ユーザー印象）に気をつけようねという話


[shibuya.apk #6](http://shibuya-apk.connpass.com/event/27811/)にて話した内容＋αの記事になります。
発表資料は[こちら](https://speakerdeck.com/yamacraft/request-permissiontoux)

ついに国内端末でも本格的にAndroid 6.0のアップデートが行われるようになりました。
そのためアプリのAPI23対応に本腰を入れるところも多いのではないでしょうか。
そしてAPI23対応の中で、おそらくもっとも注目されているのがRequest Permissionじゃないかと思っています。

![permission_calendar_mini.png](https://qiita-image-store.s3.amazonaws.com/0/4560/bca512db-e80e-99b0-069e-6617cd63d2cf.png "permission_calendar_mini.png")

こいつの話です。

# Request Permissionのおさらい

（そもそもこの機能、「Request Permission」と呼べばいいのか「Requesting Permission」なのか「Permission Runtime」なのか「パーミッション許可」なのか「アクセス許可」なのかよく分からない……）

Request Permissionは、以下の条件に当てはまる場合に必要となります。

- targetSdkVersion=23以上でビルドされたアプリ（compileSdkVersionではありません）
- Android 6.0以上の端末

上記の条件下に当てはまると、Request Permissionが必要なパーミッション（ややこしい）は **デフォルトでOFF** された状態になってしまいます。
これはAndroidの設定画面から許可をONにすることができますが、この操作をユーザーに期待するもの誘導するのも難しいことは明らかなので、アプリ側で明示的にアクセスの許可の確認（Request Permission）を実装する必要があります。

![settings_permissions_mini.png](https://qiita-image-store.s3.amazonaws.com/0/4560/db6f0b5a-d288-c62f-2575-8ebf6e8bed61.png "settings_permissions_mini.png")
ここから設定（他の画面からも設定できますが割愛）

ちなみにtargetSdkVersion=22以下であってもAndroid 6.0以上の端末の場合、同様に設定画面から許可をOFFにすることもできます。
が、この場合はユーザーが能動的に行っているものなので、正直ここはUXレベルでの「パーミッションの必要性を伝えることができていない」という問題に繋がるのかなという認識です。

# Request Permissionの実装方法

手っ取り早く対応したいのであれば、[PermissionsDispatcher](https://github.com/hotchemi/PermissionsDispatcher)を使うことをオススメします。そうでなくても、ネイティブで実装する場合は「許可されている場合」「許可されていない場合」「許可されていない＋確認表示を拒絶されている場合」の３パターンの動作をキチンと実装する必要もあるので、その辺りがアノテーションで見やすく記述できる分、安全パイとしての利用価値もあるかなと思います。

参考記事：[5分で対応するMパーミッション - Qiita](http://qiita.com/kazy/items/0ded30d80cef9df54c98)

対応策はこれで完了です。ですがもし「API23対応するからとりあえずRequest Permission入れなくちゃ」レベルの話であれば、以下のことを考慮すべきでしょう。

# Request Permission実装時の注意点

例えばREAD_PHONE_STATEのRequest Permissionを実装した場合、こんなダイアログが出てくるようになります（Nexusシリーズで確認）

![permission_phone_mini.png](https://qiita-image-store.s3.amazonaws.com/0/4560/a7b89d72-ead3-2300-d2bd-7adfc14c7e24.png "permission_phone_mini.png")


READ_PHONE_STATEだけでは通話の発信なんてできませんが、しっかり「通話の発信と管理」と表示されてしまいます。ユーザーへの誤解待ったなしです。

どうしてこんなことが起きてしまうのかというと、Request Permissionで表示される文言はパーミッションの単位でなく「Permission Groups」というグループ単位で決定されてしまうからです。

[System Permissions | Android Developers](http://developer.android.com/intl/ja/guide/topics/security/permissions.html#perm-groups)

こちらを参照すると、READ_PHONE_STATEはPHONEカテゴリに入っています。PHONEカテゴリにはCALL_PHONEなどが含まれているため、こういった表示がされてしまうのです。当然ですが、RequestPermissionsで表示される文言をアプリ側では制御できません。端末によっては文言にある程度の違いは出てくるかもしれませんが、PHONEカテゴリにある以上、ほぼ同内容のニュアンスが表示されることになるでしょう。

そのため、安易にRequest Permissionを設定することで、逆にユーザーへ誤解や不安を与えることになってしまいます。実装自体は当然するべきものですが、デベロッパーとしてどうすればユーザーに誤解なく「許可する」をタップしてもらえるかを考える必要があります（そういう意味でのUXの話でした）。

# 補足：GCMのGET_ACCOUNTSについて

CONTACTのパーミッショングループに入っているGET_ACCOUNTSは、GCMで必須のパーミッションだったはずですが、いつの間にか消えています。

[google-services/AndroidManifest.xml at master · googlesamples/google-services](https://github.com/googlesamples/google-services/blob/master/android/gcm/app/src/main/AndroidManifest.xml)

```AndroidManifest.xml
<!-- [START gcm_permission] -->
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!-- [END gcm_permission] -->
```

これはGET_ACCOUNTSが必要になるのはAndroid 4.0.3までで、それ以降は不要になっているためです。

[Why do Parse Push Notification still need "Get_Account" permission to work? · Issue #129 · ParsePlatform/Parse-SDK-Android](https://github.com/ParsePlatform/Parse-SDK-Android/issues/129)

Request Permissionが必要になるのはAndroid 6.0以上ですが、GCMの通信にGET_ACCOUNTSは不要なので、わざわざRequest Permissionを実装する必要はありません。

逆にGCM以外でGET_ACCOUNTSのみを必要とする場合、Request Permissionで表示されるのは「連絡先の取得」となるため、Request Permissionを表示するタイミングや、ユーザーへの通知方法はかなり意識する必要があるでしょう（正直、正解は自分もわかりません…）。