如何在安卓系统中以编程的方式授予“悬浮窗显示于其他应用之上”的权限?

27

如何在 Android 中以编程方式授予 设置 -> 应用程序 -> 在其他应用程序上方绘制 权限?我想使用系统警报窗口,但在 Android Marshmallow 中无法使用,除非强制用户首先通过设置应用程序来授予权限。


请说明您的问题。 - Kunu
尊敬的先生,当使用system.alert.window权限时,会打开一个授权窗口。我想以编程方式实现此操作,而不想打开该窗口。 - Anil Ranga
请发布您的代码。您目前尝试了什么? - Davit Mumladze
这是一个好问题。人们毫无理由地不断标记有用的好问题。看看我的答案,我也在stackoverflow上找到了它,并且对我很有效。 - Curious Mind
4个回答

44

您可以使用此功能检查并请求覆盖其他应用程序的绘制权限

if (!Settings.canDrawOverlays(this)) {
    Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName()));
    startActivityForResult(intent, 0);
}

1
我想要以编程方式实现,无需用户控制。 - Anil Ranga
3
此代码检查您的应用程序是否具有悬浮窗权限。如果没有,它将重定向用户到“设置”>“应用程序”>“绘制悬浮窗应用程序”页面,以便让用户授予权限。在Android Marasmellow中,没有办法通过编程方式授予自己权限。 - Shashank Udupa
2
我不会那么肯定地说有一种方法可以做到这一点。有一个名为XOutOf10的应用程序可以在没有用户交互的情况下启用此权限。 - portfoliobuilder
3
如果您查看他们在应用商店中的说明,它会说:“Android 6.0+用户:在第一次运行时,请确保您“允许在应用程序上方绘制”。”,这需要用户手动启用。在Marshmallow版本之前是可能的,但之后就不行了。 - Shashank Udupa
1
每个请求SYSTEM_ALERT_WINDOW权限并通过Play商店安装的应用程序(需要版本6.0.5或更高版本),将自动授予权限。 - Curious Mind
显示剩余2条评论

20
if (!Settings.canDrawOverlays(this)) {
    Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, 
    Uri.parse("package:" + getPackageName()));
    startActivityForResult(intent, 0);
}
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

3
请添加一些解释,以避免将此帖子归类为低质量帖子。 - Harsha Biyani

10

以下是自动授予SYSTEM_ALERT_WINDOW权限给包的代码。要运行此代码,您的Android应用程序必须是系统级别(由平台密钥签署)。

该方法基于以下Android源代码文件:AppOpsManager.javaDrawOverlayDetails.java,请参见方法DrawOverlayDetails.setCanDrawOverlay(boolean newState)

@TargetApi(Build.VERSION_CODES.KITKAT)
public static void autoSetOverlayPermission(Context context, String packageName) {
    PackageManager packageManager = context.getPackageManager();
    int uid = 0;
    try {
        ApplicationInfo applicationInfo = packageManager.getApplicationInfo(packageName, 0);
        uid = applicationInfo.uid;
    } catch (PackageManager.NameNotFoundException e) {
        e.printStackTrace();
        return;
    }

    AppOpsManager appOpsManager = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
    final int OP_SYSTEM_ALERT_WINDOW = 24;
    try {
        Class clazz = AppOpsManager.class;
        Method method = clazz.getDeclaredMethod("setMode", int.class, int.class, String.class, int.class);
        method.invoke(appOpsManager, OP_SYSTEM_ALERT_WINDOW, uid, packageName, AppOpsManager.MODE_ALLOWED);
        Log.d(Const.LOG_TAG, "Overlay permission granted to " + packageName);
    } catch (Exception e) {
        Log.e(Const.LOG_TAG, Log.getStackTraceString(e));
    }
}

该代码已经在Headwind MDM项目中进行了测试,成功地授予“在其他应用程序上方绘制”权限给Headwind Remote应用程序(免责声明:我是Headwind MDM和Headwind Remote的项目所有者),当Headwind MDM应用程序使用平台密钥签名时。该代码已经在Android 10(LineageOS 17)上进行了测试。


你好。我尝试了你的代码,但是出现了以下异常:Caused by: java.lang.SecurityException: uid 10182 does not have android.permission.UPDATE_APP_OPS_STATS。 我的应用程序是DeviceOwner...这不够吗? - Alessandro Caliaro
2
很遗憾,设备所有者权限不足以运行此代码。您需要使用平台密钥签署您的应用,并使用共享用户android.uid.system。 - vmayorow
一个由平台密钥签名的应用程序能否使用此代码授予其他应用程序权限?(不是它自己)。 - Yeung
我认为这段代码也可以用于授予其他应用程序权限(尚未测试)。只需使用需要权限的应用程序的软件包ID替换packageName即可。 - vmayorow

1

2
不,对我来说没有发生。我已经尝试使用<uses-permission ... SYSTEM_ALERT_WINDOW>和<permission ... SYSTEM_ALERT_WINDOW>与protectionLevel上传到Playstore,但用户仍然需要手动启用它。我不知道Facebook Messenger是如何默认执行的。 - Kzaf
你是通过 Play 商店安装它的吗? - Curious Mind
1
请查看此答案:https://dev59.com/7VoV5IYBdhLWcg3wnf7r#60005258 - Kzaf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接