首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么安卓8中的Settings.canDrawOverlays()方法在用户授予绘制覆盖并返回到应用程序的权限时返回"false“?

为什么安卓8中的Settings.canDrawOverlays()方法在用户授予绘制覆盖并返回到应用程序的权限时返回"false“?
EN

Stack Overflow用户
提问于 2017-09-12 10:00:46
回答 8查看 16.4K关注 0票数 29

我正在为家长开发MDM应用程序来控制孩子的设备,如果执行了禁止的操作,它将使用权限SYSTEM_ALERT_WINDOW在设备上显示警告。在安装过程中,在使用SDK 23+ (Android6.0)的设备上,应用程序使用以下方法检查权限:

代码语言:javascript
运行
复制
Settings.canDrawOverlays(getApplicationContext()) 

如果此方法返回false,则应用程序将打开系统对话框,用户可以在该对话框中授予权限:

代码语言:javascript
运行
复制
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                    Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, REQUEST_CODE);

但是在使用SDK 26 (Android8.0)的设备上,当用户成功地授予许可并按下“后退”按钮返回到应用程序时,方法canDrawOverlays()仍然返回false,直到用户不关闭该应用程序并再次启动它,或者只是在最近的“应用程序”对话框中选择它。我在Android中用Android 8在最新版本的虚拟设备上测试了它,因为我没有真正的设备。

我做了一些研究,另外还检查了AppOpsManager的权限:

代码语言:javascript
运行
复制
AppOpsManager appOpsMgr = (AppOpsManager) getSystemService(Context.APP_OPS_SERVICE);
int mode = appOpsMgr.checkOpNoThrow("android:system_alert_window", android.os.Process.myUid(), getPackageName());
Log.d(TAG, "android:system_alert_window: mode=" + mode);

因此:

  • 当应用程序没有此权限时,用户的模式为"2“(MODE_ERRORED) (canDrawOverlays()返回false)
  • 授予权限并返回到应用程序时,模式为"1“(MODE_IGNORED) (canDrawOverlays()返回false)
  • 如果现在重新启动应用程序,模式为"0“(MODE_ALLOWED) (canDrawOverlays()返回true)

拜托,有人能跟我解释一下这种行为吗?我可以依赖mode == 1的操作"android:system_alert_window"并假设用户已经授予了权限吗?

EN

Stack Overflow用户

发布于 2017-09-12 11:09:09

我也遇到了同样的问题。我使用了一个解决方法,试图添加一个不可见的覆盖。如果抛出异常,则不授予权限。这可能不是最好的解决办法,但有效。我不能告诉您任何关于AppOps解决方案的信息,但是它看起来是可靠的。

编辑2020年10月:正如注释中提到的那样,当抛出WindowManager时,可能会在SecurityException中出现内存泄漏,导致解决方案视图不会被删除(即使是对removeView的显式调用)。对于正常使用来说,这不是什么大问题,但是要避免在同一个应用程序会话中运行太多的检查(如果不对其进行测试,我认为任何低于100的都可以)。

代码语言:javascript
运行
复制
/**
 * Workaround for Android O
 */
public static boolean canDrawOverlays(Context context) {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return true;
    else if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
        return Settings.canDrawOverlays(context);
    } else {
        if (Settings.canDrawOverlays(context)) return true;
        try {
            WindowManager mgr = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
            if (mgr == null) return false; //getSystemService might return null
            View viewToAdd = new View(context);
            WindowManager.LayoutParams params = new WindowManager.LayoutParams(0, 0, android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O ?
                    WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY : WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
                    WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSPARENT);
            viewToAdd.setLayoutParams(params);
            mgr.addView(viewToAdd, params);
            mgr.removeView(viewToAdd);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }
}
票数 21
EN
查看全部 8 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46173460

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档