Android使用TYPE_ACCESSIBILITY_OVERLAY添加悬浮窗报BadTokenException异常
问题根源
TYPE_ACCESSIBILITY_OVERLAY 仅允许已授权激活的无障碍服务(AccessibilityService) 使用,普通Service、Activity均无权限调用该窗口类型,你之前修改Context的尝试完全不对症,问题和Context来源无关,是窗口类型的权限要求不匹配。
解决步骤
1. 将HUD逻辑迁移到无障碍服务中
你不能用普通Service承载TYPE_ACCESSIBILITY_OVERLAY类型的窗口,需要创建继承自AccessibilityService的类,把窗口创建逻辑放到服务授权激活后的onServiceConnected()回调中,不要放在onCreate()中,避免权限不足报错。
示例代码如下:
public class HUDService extends AccessibilityService { private WindowManager windowManager; private View filter; @Override protected void onServiceConnected() { super.onServiceConnected(); windowManager = (WindowManager) getSystemService(WINDOW_SERVICE); filter = new View(this); filter.setBackgroundColor(Color.RED); filter.getBackground().setAlpha(80); WindowManager.LayoutParams params = new WindowManager.LayoutParams( WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY, WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT); params.gravity = Gravity.TOP; params.y = 100; windowManager.addView(filter, params); } @Override public void onAccessibilityEvent(AccessibilityEvent event) { // 不需要处理无障碍事件可空实现 } @Override public void onInterrupt() { } @Override public void onDestroy() { super.onDestroy(); if (filter != null && windowManager != null) { windowManager.removeView(filter); } } }
2. 在AndroidManifest.xml中声明无障碍服务
添加对应权限和配置:
<service android:name=".HUDService" android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"> <intent-filter> <action android:name="android.accessibilityservice.AccessibilityService" /> </intent-filter> <meta-data android:name="android.accessibilityservice" android:resource="@xml/accessibility_service_config" /> </service>
在res/xml目录下创建accessibility_service_config.xml配置文件:
<?xml version="1.0" encoding="utf-8"?> <accessibility-service xmlns:android="http://schemas.android.com/apk/res/android" android:accessibilityFeedbackType="feedbackGeneric" android:accessibilityFlags="flagDefault" android:canPerformGestures="false" android:canRetrieveWindowContent="false" android:description="@string/accessibility_service_desc" />
需要在strings.xml中添加对应的服务描述文本,告知用户该无障碍服务的用途是显示HUD覆盖层,用户在系统设置中激活服务时会看到该描述。
3. 引导用户激活无障碍服务
应用无法自动激活无障碍服务,你需要在交互页面引导用户跳转到系统无障碍设置页面手动开启你的服务:
Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS); startActivity(intent);
用户激活服务后,onServiceConnected()会自动回调,此时创建TYPE_ACCESSIBILITY_OVERLAY窗口就不会再抛出异常。
额外注意事项
- 你之前代码中
filter.setAlpha(0.8f)和filter.getBackground().setAlpha(80)会叠加透明度,不需要同时设置,选其一即可避免透明度不符合预期。 TYPE_ACCESSIBILITY_OVERLAY不需要申请SYSTEM_ALERT_WINDOW权限,只要无障碍服务激活即可正常使用。
内容的提问来源于stack exchange,提问作者xRobinHoodx
相关产品推荐
相关产品推荐

