如何处理SYSTEM_ALERT_WINDOW权限未在某些Marshmallow设备上自动授予

时间:2015-10-16 14:01:46

标签: android android-overlay

我一直在收到一些小米设备(例如Mi 2,运行API级别21)没有显示叠加层的报告。我的应用针对API 23。

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

不幸的是,Settings.canDrawOverlays()仅适用于Android 23 +。

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

5 个答案:

答案 0 :(得分:21)

1)在API 23之前,已经给出了权限,因为用户在安装时授予了权限。

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

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),他们希望避免热门应用上的问题。

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

答案 1 :(得分:8)

使用以下方法检查您是否具有drawOverlays权限更安全:

@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);

}

自定义ROM可以更改操作系统,以便Settings.canDrawOverlays()不可用。小米设备和应用程序崩溃后发生了这种情况。

请求许可:

index.html

答案 2 :(得分: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()

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

答案 3 :(得分:1)

为了寻找关于小米的问题,魅族我找到了这个。它工作得很好..

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

答案 4 :(得分:0)

您可以这样检查权限:

boolean granted = activity.checkSelfPermission("android.permission.SYSTEM_ALERT_WINDOW") == PackageManager.PERMISSION_GRANTED;
相关问题