Android M 版本以后的特殊权限问题分析
现象
桌面悬浮框在6.0以后,会因为SYSTEM_ALERT_WINDOW权限的问题,无法在最上层显示。
问题原因
- SYSTEM_ALERT_WINDOW,设置悬浮窗,进行一些黑科技
- WRITE_SETTINGS 修改系统设置
SYSTEM_ALERT_WINDOW 和 WRITE_SETTINGS, 这两个权限比较特殊,不能通过代码申请方式获取,必须得用户打开软件设置页手动打开,才能授权。
路径是:Settings -> Apps -> xxx -> Draw over other apps . 然后手动打开应用的此权限。
只靠Manifest申请该权限是无效的。
- 预置应用应该是可以默认使用该权限的(经验说:预置应用默认开启所需要的权限,就算在apps->permission中显示的权限默认是关闭的)。
- 通过Google Play Store(Version 6.05 or heigher is required)下载的需要该权限的应用,会被自动授予该权限
参考如下:
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 }
上述代码需要注意的是
- 使用Action
Settings.ACTION_MANAGE_WRITE_SETTINGS
启动隐式Intent - 使用
"package:" + getPackageName()
携带App的包名信息 - 使用
Settings.System.canWrite
方法检测授权结果
注意:关于这两个特殊权限,一般不建议应用申请。
安卓7.0项目问题
首先分析以下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” 中给应用添加默认权限,这个类只有在首次开机的时候才会被调用。
Android M 版本以后的特殊权限问题分析的更多相关文章
- android 开发 实现多个动态权限的方法(并且兼容6.0以下的版本权限授权)
android开发权限授权因为版本的不同有不同的授权方式,6.0以下的版本使用的是在注册表中添加权限的静态授权(这种授权权限提示只会出现在app安装的时候),而6.0以上(包含6.0)就需要动态授权的 ...
- Android 6.0的运行时权限
原文 http://droidyue.com/blog/2016/01/17/understanding-marshmallow-runtime-permission/ 主题 安卓开发 Andr ...
- 聊一聊 Android 6.0 的运行时权限
权限一刀切 棉花糖运行时权限 权限的分组 正常权限 正常权限列表 特殊权限危险权限 请求SYSTEM_ALERT_WINDOW 请求WRITE_SETTINGS 必须要支持运行时权限么 不支持运行时权 ...
- 聊一聊Android 6.0的运行时权限
Android 6.0,代号棉花糖,自发布伊始,其主要的特征运行时权限就很受关注.因为这一特征不仅改善了用户对于应用的使用体验,还使得应用开发者在实践开发中需要做出改变. 没有深入了解运行时权限的开发 ...
- Android USER 版本与ENG 版本的差异--MTK官方解释
分类: Android(4) Description]Android USER 版本与ENG 版本的差异 [Keyword]USER ENG user eng 用户版本 工程版本 差异 [Solu ...
- 基于MT6752/32平台 Android L版本驱动移植步骤
基于MT6752/32平台 Android L版本驱动移植步骤 根据MK官网所述,在Android L 版本上Turnkey ABS 架构将会phase out,而Mediatek Turnkey架构 ...
- Android各版本特性
此篇文章可以利用碎片化时间进行消化和了解,针对Android各个版本特性,并没有把所有列出,只是抽出了比较常用重要的特性作为提示,同时在面试中只要牢记重要的几个点即可,其他特性直接查找官方文档即可. ...
- 一篇文章让你了解Android各个版本的历程
2008年--至今 Android 1.5(Cupcake纸杯蛋糕): 智能虚拟键盘:使用widgets实现桌面个性化:在线文件夹(Live Folder)快速浏览在线数据:视频录制和分享:图片上传: ...
- Android 各个版本新特性
一.Android 4.x 新锁屏界面: Android4.0重新设计了锁屏幕UI,下方的解锁虚拟按键向周围发射出微光,轻轻拖动就可以解锁,比原来在UI上确实有很大的进步. 全新Widget排列: 主 ...
随机推荐
- LeetCode-107-二叉树的层序遍历 II
二叉树的层序遍历 II 题目描述:给定一个二叉树,返回其节点值自底向上的层序遍历. (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历) 示例说明请见LeetCode官网. 来源:力扣(Leet ...
- 矩池云安装gdal五种解决方案
1.最快最靠谱的是conda conda install gdal 命令行conda/pip search gdal查看版本,选择合适的版本,例如:conda search gdal 命令行conda ...
- MATLAB神经网络应用设计【1】
基于看到一个博客的大佬说自己学的东西太多了,很容易遗忘.我觉得我目前也出现这样的问题了,所以在这里开了博客,开始记录整理自己的学习之旅. 今天看了这本书的前几章,看这个书的目的是为了1个多月后的数 ...
- java实现上传图片并压缩图片大小功能
缩略图压缩文件jar包 <!-- 图片缩略图 --> <dependency> <groupId>net.coobird</groupId> <a ...
- Laravel 报错: Dotenv values containing spaces must be surrounded by quotes.
报错信息如下: 原因: .env文件配置中欧冠包含空格的配置信息,用双引号""引起来即可
- windows2008R2重建索引
windows索引服务 索引服务是一项系统服务(Indexing Service),使用文档筛选器读取整个文档,并提取文档和属性传递给索引程序,这个过程称为"索引".索引服务可以从 ...
- CVE-2021-3129:Laravel远程代码漏洞复现分析
摘要:本文主要为大家带来CVE-2021-3129漏洞复现分析,为大家在日常工作中提供帮助. 本文分享自华为云社区<CVE-2021-3129 分析>,作者:Xuuuu . CVE-202 ...
- Redis 大 key 问题总结
多大的 key 算大? 阿里云Redis 最佳实践中提到 合理的 Key 中 Value 的字节大小,推荐小于10 KB.过大的 Value 会引发数据倾斜.热点Key.实例流量或 CPU 性能被占满 ...
- 【基础】工作中常用的linux命令,经常会被面试官问到
前言 面试经常会问到一些Linux操作命令,下面就工作中常用的和面试问的频率较高的命令做详细描述. 常用命令 修改密码:passwd 用户名 切换用户名:su 用户名 查看当前路径:pwd 调整路径: ...
- 网站SQL注入防御实战
SQL注入作为直接威胁web业务的最严重攻击行为,已经被大多数的网站管理员所了解,这种通过HTTP标准端口,利用网页编码不严谨,提交精心构造的代码实现对数据库非授权访问的攻击方法,已经被越来越多的sc ...