【问题标题】:How to handle SYSTEM_ALERT_WINDOW permission not being auto-granted on some pre-Marshmallow devices如何处理未在某些预棉花糖设备上自动授予的 SYSTEM_ALERT_WINDOW 权限
【发布时间】:2015-10-16 14:01:45
【问题描述】:

我收到一些小米设备(例如,运行 API 级别 21 的小米 2)不显示叠加层的报告。我的应用面向 API 23。

关于这个有severalposts。似乎 MIUI 设备在安装时并未启用此权限(与其他 Marshmallow 之前的设备不同)。

很遗憾,Settings.canDrawOverlays() 仅适用于 Android 23+。

  1. 在 Marshmallow 之前检查此权限是否尚未启用的正确方法是什么?
  2. 是否有将用户带到相关 MUIU 设置页面的意图?也许:new Intent("android.settings.action.MANAGE_OVERLAY_PERMISSION", packageName) 但我没有办法对此进行测试。

【问题讨论】:

  • 您找到解决方案了吗?我面临着类似的问题。部分设备(小米、魅族)默认不支持“在其他应用上绘图”。
  • 我想我们永远不会知道

标签: android android-overlay


【解决方案1】:

1) 在 API 23 之前的版本中,已授予权限,因为用户在安装时授予了权限。

编辑:Android 6 上似乎存在一个错误(get fixed on 6.0.1),如果用户拒绝此权限,应用程序将因 SecurityException 而崩溃。不知道 Google 是如何修复它的。

2) 这样:

public static void requestSystemAlertPermission(Activity context, Fragment fragment, int requestCode) {
    if (VERSION.SDK_INT < VERSION_CODES.M)
        return;
    final String packageName = context == null ? fragment.getActivity().getPackageName() : context.getPackageName();
    final Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + packageName));
    if (fragment != null)
        fragment.startActivityForResult(intent, requestCode);
    else
        context.startActivityForResult(intent, requestCode);
}

然后,在onActivityResult中,你可以检查是否给了权限,例如:

@TargetApi(VERSION_CODES.M)
public static boolean isSystemAlertPermissionGranted(Context context) {
    final boolean result = VERSION.SDK_INT < VERSION_CODES.M || Settings.canDrawOverlays(context);
    return result;
}

编辑:目前,如果您将应用发布到 Play 商店,您的应用将自动获得此权限。你可以阅读它here。当我问到它时,我认为它是 Android 本身的一部分,因为我认为我们需要的只是为 targetSdkVersion 设定一个足够高的值。 Google 写信给我 (here) 是他们希望避免流行应用程序出现问题。

我建议正确处理此权限,即使您会自动授予它。

【讨论】:

  • 您的答案是针对一般情况的,这不是本问题的内容。部分小米和魅族设备不支持这种方式。
  • @MarkCarter 好吧,它应该是这样工作的。您应该与他们交谈并询问他们如何允许它以其他方式工作。
  • 正确。问题是如何针对许多设备上发生的情况应用解决方法 - 无论人们如何成功地说服小米和魅族修复问题,其中许多设备可能永远不会收到更新。
  • @MarkCarter 好的。对不起。你是对的。我不知道它在那里是如何工作的。您可能可以将 try-catch 用于尝试将内容放在这些情况下的内容。而且,对于意图本身,您可以查看日志以查看需要哪个意图。如果活动是公开的,您也可以自己找到它(也许可以尝试“设置”应用)。
  • android 6.0.1 SecurityException 错误的任何更新? targetSdk 25 仍然会发生这种情况
【解决方案2】:

检查你是否有drawOverlays权限使用这个更安全:

@SuppressLint("NewApi")
public static boolean canDrawOverlayViews(Context con){
    if(Build.VERSION.SDK_INT< Build.VERSION_CODES.LOLLIPOP){return true;}
    try { 
        return Settings.canDrawOverlays(con); 
    }
    catch(NoSuchMethodError e){ 
        return canDrawOverlaysUsingReflection(con); 
    }
}


public static boolean canDrawOverlaysUsingReflection(Context context) {

    try {

        AppOpsManager manager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
        Class clazz = AppOpsManager.class;
        Method dispatchMethod = clazz.getMethod("checkOp", new Class[] { int.class, int.class, String.class });
        //AppOpsManager.OP_SYSTEM_ALERT_WINDOW = 24
        int mode = (Integer) dispatchMethod.invoke(manager, new Object[] { 24, Binder.getCallingUid(), context.getApplicationContext().getPackageName() });

        return AppOpsManager.MODE_ALLOWED == mode;

    } catch (Exception e) {  return false;  }

}

自定义 ROM 可以更改操作系统,因此 Settings.canDrawOverlays() 不可用。小米设备发生在我身上,应用程序崩溃了。

请求许可:

@SuppressLint("InlinedApi")
public static void requestOverlayDrawPermission(Activity act, int requestCode){
    Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + act.getPackageName()));
    act.startActivityForResult(intent, requestCode);

}

【讨论】:

    【解决方案3】:

    以下是如何处理此问题的分步说明:

    首先在清单文件中给予以下权限:

    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
    

    或者

    <uses-permission-sdk-23 android:name="android.permission.SYSTEM_ALERT_WINDOW" />
    

    然后使用下面的代码处理其余的事情:

     public final static int REQUEST_CODE = 65635;
    
        public void checkDrawOverlayPermission() {
            /** check if we already  have permission to draw over other apps */
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                if (!Settings.canDrawOverlays(this)) {
                    /** if not construct intent to request permission */
                    Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                            Uri.parse("package:" + getPackageName()));
                    /** request permission via start activity for result */
                    startActivityForResult(intent, REQUEST_CODE);
                }
            }
        }
    
        @Override
        protected void onActivityResult(int requestCode, int resultCode,  Intent data) {
            /** check if received result code
             is equal our requested code for draw permission  */
            if (requestCode == REQUEST_CODE) {
                // ** if so check once again if we have permission */
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    if (Settings.canDrawOverlays(this)) {
                        // continue here - permission was granted
                        goYourActivity();
                    }
                }
            }
        }
    

    只需从您的 LauncherActivity 或根据您的要求在任何地方调用 checkDrawOverlayPermission()

    当您执行项目时,您将看到一个窗口并要求您启用权限。获得许可后,您将可以对此做任何事情。

    【讨论】:

    • 你没有理解这个问题,所以你的回答没有帮助。
    【解决方案4】:

    在找小米、魅族这个问题的时候找到了这个。它工作得很好..

    public static boolean isMiuiFloatWindowOpAllowed(@NonNull Context context) {
        final int version = Build.VERSION.SDK_INT;
    
        if (version >= 19) {
            return checkOp(context, OP_SYSTEM_ALERT_WINDOW); //See AppOpsManager.OP_SYSTEM_ALERT_WINDOW=24 /*@hide/
        } else {
            return (context.getApplicationInfo().flags & 1<<27) == 1;
        }
    }
    
    public static boolean checkOp(Context context, int op, String packageName, int uid) {
        final int version = Build.VERSION.SDK_INT;
    
        if (version >= 19) {
            AppOpsManager manager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
            try {
                return (AppOpsManager.MODE_ALLOWED == (Integer) ReflectUtils.invokeMethod(manager, "checkOp", op, uid, packageName));
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            Flog.e("Below API 19 cannot invoke!");
        }
        return false;
    }
    

    ReflectUtils.java

    public static Object invokeMethod(@NonNull Object receiver, String methodName, Object... methodArgs) throws Exception {
    Class<?>[] argsClass = null;
        if (methodArgs != null && methodArgs.length != 0) {
            int length = methodArgs.length;
            argsClass = new Class[length];
            for (int i=0; i<length; i++) {
                argsClass[i] = getBaseTypeClass(methodArgs[i].getClass());
            }
        }
    
        Method method = receiver.getClass().getMethod(methodName, argsClass);
        return method.invoke(receiver, methodArgs);
    }
    

    Reference

    【讨论】:

    • @Manifest,如何检测小米、魅族等运行miui的设备??
    • getBaseTypeClass 不编译,我做错了什么?
    【解决方案5】:

    您可以像这样检查权限:

    boolean granted = activity.checkSelfPermission("android.permission.SYSTEM_ALERT_WINDOW") == PackageManager.PERMISSION_GRANTED;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-13
      相关资源
      最近更新 更多