如何检查权限 SYSTEM_ALERT_WINDOW 是否授予 Android Lollipop?

How to check permission SYSTEM_ALERT_WINDOW is granted on Android Lollipop?

请注意,我说的是 Android Lollipop。对于 android 6.0,我们可以使用方法 canDrawOverlays() 来检查 SYSTEM_ALERT_WINDOW 是否被授予。

使用Android Lollipop,几乎所有设备都默认授予此权限。但是在小米、魅族的一些设备上..是不被允许的。用户需要转到应用程序信息以允许它。

我们如何以编程方式检查它以警告用户?

在 MIUI 中使用

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

反思是有风险的,因为你认为事情是理所当然的......在 Android 的未来版本中事情可能会改变。以下方法仅在正确方法失败时才使用反射。

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

 }