読者です 読者をやめる 読者になる 読者になる

アナログ金木犀

つれづれなるまままにつれづれする

Android Mのパーミッション個別設定について調べた

こんにちは。@kgmyshinです。

Mからは「Permissionが個別設定できる」とIOで発表されました。これ、実際のところインパクトでかいと思うんですよね。

なので、今回はPermissionsの個別設定ってどこまでできるのかとか、何かすることはないのかとか等々調べてみました。

すべてのPermissionが対象というわけではない。

パーミッションの設定の方法はいつもと同じです。AndroidManifest.xmlにいつも通り設定します。

たとえば下記のように設定してみましょう。

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_CALENDAR" />
<uses-permission android:name="android.permission.WRITE_CALENDAR" />
<uses-permission android:name="android.permission.READ_CONTACTS" />

そして、アプリを立ち上げて Settings -> App -> 該当アプリ -> Permissionsを選択してみるとこのような画面が出てきます。これがPermissionの個別設定ページです。

f:id:kgmyshin:20150616233047p:plain

画面を見てわかる通り、INTERNETやSTORAGEといった文言はありませんし、また上の画像ではわかりませんが通信は問題なくできています。 つまるところ、これらは個別設定の対象ではありません。

あるのはContactsとCalendarだけ。さらに、READ_CALENDARとWRITE_CALENDARを指定していますが、この二つはまとめられています。

該当するパーミッションはこれら

developerページに書いてある該当するpermissionはこれらです。

Permission Group Permissions
android.permission-group.CALENDAR
  • android.permission.WRITE_CALENDAR
android.permission-group.CAMERA
android.permission-group.CONTACTS
android.permission-group.LOCATION
android.permission-group.MICROPHONE
android.permission-group.PHONE
  • android.permission.READ_PHONE_STATE
  • android.permission.CALL_PHONE
  • android.permission.READ_CALL_LOG
  • android.permission.WRITE_CALL_LOG
  • com.android.voicemail.permission.ADD_VOICEMAIL
  • android.permission.USE_SIP
  • android.permission.PROCESS_OUTGOING_CALLS
android.permission-group.SENSORS
  • android.permission.USE_FINGERPRINT
android.permission-group.SMS

Permissionの個別設定はGroup単位でしかできません。そのため、READ_CALENDARはオンにしたいけど、WRITE_CALENDARはオフにしたいなどはできません。

インストールからの流れ

今までと違って、アプリインストール時にユーザに権限の許可のダイアログはないそうです

(INTERNETとか上記にはないような権限は自動で承認されます。)

そのため、初回起動した時は上記のPermissionは軒並みOFFになっているので、プログラムにPermissionをチェックして、OFFであればONにすることを促すようなコードを書く必要があります

そのコードについて説明する前に。

このままだとすでにある、たとえばカメラアプリとかはそのようなコードがもちろんないために、Security Exceptionかなにかが発生して死にそうに見えます。しかし実際はTargetがAndroid Mでないものは、以前のようにインストール時に権限をONにすることをユーザにきくダイアログが出るようです。とはいえ、Mよりまえのバージョンでも個別設定はできるみたいです。(ここらへんは試せてないのでそのままdeveloperサイトの情報です。)

パーミッションのON/OFFをチェックしてONを促すダイアログを出す

これが許可を促すコード。

        if (Build.VERSION.CODENAME.equals("MNC")) {
            if (checkSelfPermission(Manifest.permission.WRITE_CALENDAR)
                    != PackageManager.PERMISSION_GRANTED) {
                requestPermissions(
                        new String[]{Manifest.permission.WRITE_CALENDAR},
                        PERMISSION_REQUEST_CALENDAR);
                return;
            }
        }

まずはAndroid Mかどうかの確認を忘れずに。

そのあとに、checkSelfPermissionで許可済みかどうかを調べます。許可されている場合はPackageManager.PERMISSION_GRANTEDが返ってきます。

そして、許可が必要な場合は 欲しい権限(複数可)をStringの配列に入れてrequestPermissionsを呼び出すことで、下記のようなダイアログが出てきます。(ここ、複数可能なのはいいのだけど、PermissionGroupじゃなくてPermission単位ってのは解せない。。)

f:id:kgmyshin:20150616233058p:plain

複数指定した時は、下記のように 1 of 2 みたいなのが出て、答えたら次形式になります。

f:id:kgmyshin:20150616233103p:plain

ユーザの解答は下記のようにして受け取ることができます。

    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        switch (requestCode) {
            case PERMISSION_REQUEST_CALENDAR:
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    // OK
                } else {
                    // だが断る
                }
                break;
            default:
                break;
        }
    }

requestCodeはrequestPermissionsで指定したもの、そしてpermissionsに渡したpermissionの配列、grantResultsに解答が配列で返ってきます。

あとはよしなに料理しましょう。

こういう風に組むと考えるといいらしい

Googleは許可ダイアログを開くタイミングについて言及しています。一言で言うと、適切なタイミングで出しましょうと言ってます。

たとえばカメラを使う直前に聞きましょうとか。他にもアプリをインストールしてはじめにチュートリアルがあるならば、そのチュートリアル終わったあとに一括で全部のパーミッションについて聞くのもありと言ってます。 (パーミッションの要求をする前に、その理由を示しておくと良いとも言ってるのでチュートリアルの後ってのは理にかなってますね。)

余談

Mだけで使いたいパーミッションがあるなら

Mだけで使いたいパーミッションがあるなら uses-permission でなく uses-permission-sdk-mを使うといいそうです。

コマンド

コマンドも幾つか追加されてます。

初回から全権限許可でインストール。

$ adb install -g <path_to_apk>

あるアプリのあるパーミッションを許可する。(developerサイトはshellが抜けてるし、そして実際何度叩いてもこのコマンド全く動かない、、)

$ adb shell pm grant <package_name> <permission_name>

あるアプリのあるパーミッションを許可を取りけす。(こちらもgrant同様、僕の環境では動きませんでした。)

$ adb shell pm revoke <package_name> <permission_name>
これも気になる。

Restrict app background data」ってことは、バックグラウンドで結構重要な通信してたら即アウトっぽいような。

まとめ

それなりに真面目に画面フローにパーミッションのリクエストを入れないと後々クラッシュしまくりな未来がみえないこともないなと思いました。