Android Mの厄介な機能としてRuntime Permissionsが入りますよね。
詳しくは公式のドキュメントを見れば、だいたいどんな機能なのかわかります。
開発者的には、これに対応させるのってすげー大変なのですよ。。。
Permissionの許可・非許可ってアプリの設定画面からユーザが自由に操作できるんですよね。
例えば、標準のカメラアプリのPermission設定画面がこれ。
んで今回、この**Permission設定画面にアプリ内からIntentを作って遷移することができるのか?**という検証をしてみた。
Permission設定画面にアプリ内からIntentを作って遷移することができるのか?
Permission設定画面に遷移するために、調べて見たことをまとめてみた。
- 遷移するIntentのActionは、android.intent.action.MANAGE_APP_PERMISSIONS
- 起動するActivityは、com.google.android.packageinstaller/com.android.packageinstaller.permission.ui.ManagePermissionsActivity
- ManagePermissionsActivityにAppPermissionsFragmentというFragmentがAttachされている
- IntentのデータにKeyがandroid.intent.extra.PACKAGE_NAMEで、値にアプリのパッケージ名が入ってるっぽい
adb shell amでPermission設定画面を開けるか試してみた
以下のadb shell am
でPermission設定画面を開けるか試してみた。
adb shell am start -a android.intent.action.MANAGE_APP_PERMISSIONS -e android.intent.extra.PACKAGE_NAME <Package Name>
e.g.)
adb shell am start -a android.intent.action.MANAGE_APP_PERMISSIONS -e android.intent.extra.PACKAGE_NAME com.kouzoh.mercari
結果(Permission設定画面 開いた)
android.intent.extra.PACKAGE_NAMEに指定したパッケージ名のアプリのPermission設定画面が開いた。
うん、開いた!
どうやらadb shell am
からなら開けるっぽい。
では、お次は目的のアプリ内から開けるかどうか。
アプリ内からIntentでPermission設定画面に遷移することができるのか試してみた
adb shell am
の結果から、以下のようなコードでアプリ内からPermission設定画面に遷移できるのではないかと考えた。
Intent i = new Intent();
i.setAction("android.intent.action.MANAGE_APP_PERMISSIONS");
i.putExtra("android.intent.extra.PACKAGE_NAME", getPackageName());
startActivity(i);
結果 (SecurityExceptionが起きて遷移できない)
startActivityを実行したところ、SecurityExceptionが起きてPermission設定画面に遷移できなかった。
Process: com.mercariapp.mercari, PID: 23142
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.mercariapp.mercari/com.kouzoh.mercari.activity.TestActivity}: java.lang.SecurityException: Permission Denial: starting Intent { act=android.intent.action.MANAGE_APP_PERMISSIONS cmp=com.google.android.packageinstaller/com.android.packageinstaller.permission.ui.ManagePermissionsActivity (has extras) } from ProcessRecord{1573c3 23142:com.mercariapp.mercari/u0a102} (pid=23142, uid=10102) requires android.permission.GRANT_RUNTIME_PERMISSIONS
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2416)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
at android.app.ActivityThread.-wrap11(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Caused by: java.lang.SecurityException: Permission Denial: starting Intent { act=android.intent.action.MANAGE_APP_PERMISSIONS cmp=com.google.android.packageinstaller/com.android.packageinstaller.permission.ui.ManagePermissionsActivity (has extras) } from ProcessRecord{1573c3 23142:com.mercariapp.mercari/u0a102} (pid=23142, uid=10102) requires android.permission.GRANT_RUNTIME_PERMISSIONS
at android.os.Parcel.readException(Parcel.java:1599)
at android.os.Parcel.readException(Parcel.java:1552)
at android.app.ActivityManagerProxy.startActivity(ActivityManagerNative.java:2658)
at android.app.Instrumentation.execStartActivity(Instrumentation.java:1507)
at android.app.Activity.startActivityForResult(Activity.java:3917)
at android.app.Activity.startActivityForResult(Activity.java:3877)
at android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java:820)
at android.app.Activity.startActivity(Activity.java:4200)
at android.app.Activity.startActivity(Activity.java:4168)
at com.kouzoh.mercari.activity.TestActivity.onCreate(TestActivity.java:60)
at android.app.Activity.performCreate(Activity.java:6237)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1107)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2369)
メッセージを見る感じandroid.permission.GRANT_RUNTIME_PERMISSIONSのPermissionが必要そう。
GRANT_RUNTIME_PERMISSIONSを詳しく調べてないのでわからないですが、System Process関連しか使えないPermission系かもしれない。
とりあえずアプリ内から直接特定アプリのPermission設定画面には遷移できなさそう。(今のところは)
結論
- adb shell amコマンドからなら特定アプリのPermission設定画面に遷移できる
- アプリ内で作ったIntentで遷移しようとするとSecurityExceptionが起きて遷移できない
- 遷移するには何かしたら権限が必要みたい
- android.permission.GRANT_RUNTIME_PERMISSIONS?
おまけ
今回、アプリ内からPermission設定画面に遷移させるために使ったコードのActionとかKeyがベタ書きで書かれているけど、SDK 23のIntentクラスにこれらは定義されています。
Intent i = new Intent();
i.setAction("android.intent.action.MANAGE_APP_PERMISSIONS");
i.putExtra("android.intent.extra.PACKAGE_NAME", getPackageName());
startActivity(i);
こんな感じで定義されている。けど、hideなので直接使えないんだよね。リフレクションしたくないし・・・。
Intent.java(SDK 23から一部抜粋)
/**
* Intent extra: An app package name.
* <p>
* Type: String
* </p>
*
* @hide
*/
@SystemApi
public static final String EXTRA_PACKAGE_NAME = "android.intent.extra.PACKAGE_NAME";
**
* Activity action: Launch UI to manage the permissions of an app.
* <p>
* Input: {@link #EXTRA_PACKAGE_NAME} specifies the package whose permissions
* will be managed by the launched UI.
* </p>
* <p>
* Output: Nothing.
* </p>
*
* @see #EXTRA_PACKAGE_NAME
*
* @hide
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_MANAGE_APP_PERMISSIONS =
"android.intent.action.MANAGE_APP_PERMISSIONS";
まとめ
何かいい情報や「こうやれば遷移できた!」って情報あればフィードバックもらえると嬉しいです!
引き続きPermission周りの調査続けてみる。