桌面悬浮框在6.0以后,会因为SYSTEM_ALERT_WINDOW权限的问题,无法在最上层显示。
SYSTEM_ALERT_WINDOW 和 WRITE_SETTINGS, 这两个权限比较特殊,不能通过代码申请方式获取,必须得用户打开软件设置页手动打开,才能授权。
路径是:Settings -> Apps -> xxx -> Draw over other apps . 然后手动打开应用的此权限。
只靠Manifest申请该权限是无效的。
注意:
参考如下:
It is a new behaviour introduced in Marshmallow 6.0.1.
Every
app that requests the SYSTEM_ALERT_WINDOW permission and that is
installed through the Play Store (version 6.0.5 or higher is required),
will have granted the permission automatically.
If instead the app is
sideloaded, the permission is not automatically granted. You can try to
download and install the Evernote APK from apkmirror.com. As you can
see you need to manually grant the permission in Settings -> Apps
-> Draw over other apps.
These are the commits [1] [2] that allow the Play Store to give the automatic grant of the SYSTEM_ALERT_WINDOW permission.
From: SYSTEM_ALERT_WINDOW - How to get this permission automatically on Android 6.0 and targetSdkVersion 23
以及源码中对该部分的修改说明。注:在MTK 平台上目前未合入此条记录。
对于SYSTEM_ALERT_WINDOW,官方建议需要申请该权限时引导用户跳转到Setting中自己去开启权限开关
//参考自http://stackoverflow.com/questions/32061934/permission-from-manifest-doesnt-work-in-android-6
1 public static int OVERLAY_PERMISSION_REQ_CODE = 1234;
2
3 @TargetApi(Build.VERSION_CODES.M)
4 public void requestAlertWindowPermission
() {
5 if (!Settings.canDrawOverlays(MainActivity.this)) {
6 Toast.makeText(this, "can not DrawOverlays", Toast.LENGTH_SHORT).show();
7 Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + MainActivity.this.getPackageName()));
8 startActivityForResult(intent, OVERLAY_PERMISSION_REQ_CODE);
9 } else {
10 // Already hold the SYSTEM_ALERT_WINDOW permission, do addview or something.
11 }
12 }
13
14 @TargetApi(Build.VERSION_CODES.M)
15 @Override
16 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
17 if (requestCode == OVERLAY_PERMISSION_REQ_CODE) {
18 if (!Settings.canDrawOverlays(this)) {
19 // SYSTEM_ALERT_WINDOW permission not granted…
20 Toast.makeText(this, "Permission Denieddd by user.Please Check it in Settings", Toast.LENGTH_SHORT).show();
21 } else {
22 Toast.makeText(this, "Permission Allowed", Toast.LENGTH_SHORT).show();
23 // Already hold the SYSTEM_ALERT_WINDOW permission, do addview or something.
24 }
25 }
26 }
上述代码需要注意的是
使用Action Settings.ACTION_MANAGE_OVERLAY_PERMISSION
启动隐式Intent
使用"package:" + getPackageName()
携带App的包名信息
使用Settings.canDrawOverlays
方法判断授权结果
对于WRITE_SETTINGS,官方建议相同的方案:
1 private static final int REQUEST_CODE_WRITE_SETTINGS = 2;
2 private void requestWriteSettings() {
3 Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS);
4 intent.setData(Uri.parse("package:" + getPackageName()));
5 startActivityForResult(intent, REQUEST_CODE_WRITE_SETTINGS );
6 }
7 @Override
8 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
9 super.onActivityResult(requestCode, resultCode, data);
10 if (requestCode == REQUEST_CODE_WRITE_SETTINGS) {
11 if (Settings.System.canWrite(this)) {
12 Log.i(LOGTAG, "onActivityResult write settings granted" );
13 }
14 }
15 }
上述代码需要注意的是
Settings.ACTION_MANAGE_WRITE_SETTINGS
启动隐式Intent"package:" + getPackageName()
携带App的包名信息Settings.System.canWrite
方法检测授权结果注意:关于这两个特殊权限,一般不建议应用申请。
首先分析以下log:
10-13 00:36:21.425979 5368 5368 E AndroidRuntime: FATAL EXCEPTION: main
10-13 00:36:21.425979 5368 5368 E AndroidRuntime: Process: com.android.settings, PID: 5368
10-13 00:36:21.425979 5368 5368 E AndroidRuntime: java.lang.RuntimeException: Unable to resume activity
{com.android.settings/com.android.settings.DeviceAdminAdd}: java.lang.SecurityException:
com.google.android.gms from uid 10012 not allowed to perform SYSTEM_ALERT_WINDOW
10-13 00:36:21.425979 5368 5368 E AndroidRuntime: at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3506)
10-13 00:36:21.425979 5368 5368 E AndroidRuntime: at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3546)
10-13 00:36:21.425979 5368 5368 E AndroidRuntime: at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2795)
10-13 00:36:21.425979 5368 5368 E AndroidRuntime: at android.app.ActivityThread.-wrap12(ActivityThread.java)
10-13 00:36:21.425979 5368 5368 E AndroidRuntime: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1527)
10-13 00:36:21.425979 5368 5368 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:110)
10-13 00:36:21.425979 5368 5368 E AndroidRuntime: at android.os.Looper.loop(Looper.java:203)
10-13 00:36:21.425979 5368 5368 E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:6251)
10-13 00:36:21.425979 5368 5368 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
10-13 00:36:21.425979 5368 5368 E AndroidRuntime: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1063)
10-13 00:36:21.425979 5368 5368 E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:924)
10-13 00:36:21.425979 5368 5368 E AndroidRuntime: Caused by: java.lang.SecurityException:
com.google.android.gms from uid 10012 not allowed to perform SYSTEM_ALERT_WINDOW
10-13 00:36:21.425979 5368 5368 E AndroidRuntime: at android.app.AppOpsManager.checkOp(AppOpsManager.java:1719)
10-13 00:36:21.425979 5368 5368 E AndroidRuntime: at com.android.settings.DeviceAdminAdd.onResume(DeviceAdminAdd.java:454)
10-13 00:36:21.425979 5368 5368 E AndroidRuntime: at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1269)
10-13 00:36:21.425979 5368 5368 E AndroidRuntime: at android.app.Activity.performResume(Activity.java:6770)
10-13 00:36:21.425979 5368 5368 E AndroidRuntime: at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3477)
10-13 00:36:21.425979 5368 5368 E AndroidRuntime: … 10 more
com.google.android.gms 是google的 “Play商店” 的包名,和 “Google Play Music” 应用一起预置在手机中。
在 “com.android.settings.applications.InstalledAppDetails#hasPermission” 中打log,获取到每个应用申请的所有权限;
“Google Play Music”有以下几个权限:
25562:01-01 16:56:35.079 19048 19048 D Neo : per == android.permission.ACCESS_FINE_LOCATION
25563:01-01 16:56:35.079 19048 19048 D Neo : per == android.permission.WRITE_SETTINGS
25564:01-01 16:56:35.079 19048 19048 D Neo : per == android.permission.SYSTEM_ALERT_WINDOW
25565:01-01 16:56:35.079 19048 19048 D Neo : per == android.permission.ACCESS_FINE_LOCATION
25566:01-01 16:56:35.079 19048 19048 D Neo : per == android.permission.WRITE_SETTINGS
申请了 android.permission.WRITE_SETTINGS 和 android.permission.SYSTEM_ALERT_WINDOW 两个权限,所以在 Settings --> App --> 相应的app中,就能找到对应的 “在其他应用上层显示” 和 “修改系统设置” 的相关配置。
“Play商店” 没有申请 android.permission.WRITE_SETTINGS 和 android.permission.SYSTEM_ALERT_WINDOW 两个权限,所以Settings中也不会给这个应用修改权限的机会。
因为在 “com.android.settings.applications.InstalledAppDetails#addDynamicPrefs” 中,会首先判断应用是否在AndroidManifest.xml中声明了特殊权限,如果有,则显示出“在其他应用上层显示” 和 “修改系统设置” 的相关配置控件,否则就隐藏。
因此,虽然不建议主动应用申请,但是如果报出这样的问题,应该首先在应用内部申请权限,然后如上所示,引导用户去Settings中手动开启权限。
或者,在 “com.android.server.pm.DefaultPermissionGrantPolicy” 中给应用添加默认权限,这个类只有在首次开机的时候才会被调用。
手机扫一扫
移动阅读更方便
你可能感兴趣的文章