Android 13(一加设备)禁用通知栏及前台锁定方案求助
解决方案:Android 13(一加)下前台锁定应用并禁用通知栏
一、解决WindowManager$BadTokenException权限问题
你遇到的错误是因为使用了已废弃的窗口类型TYPE_SYSTEM_ALERT(值2010),Android 10(API 29)起官方废弃该类型,且targetSdk 33下直接调用会触发权限拒绝。替代方案如下:
- 声明必要权限
在AndroidManifest.xml中添加权限:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <!-- Android 13+ 前台服务必选 -->
- 动态申请悬浮窗权限
SYSTEM_ALERT_WINDOW无法通过普通权限申请流程获取,需跳转系统设置页面:
private const val OVERLAY_PERMISSION_REQUEST = 1001 if (!Settings.canDrawOverlays(this)) { val intent = Intent( Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:${packageName}") ) startActivityForResult(intent, OVERLAY_PERMISSION_REQUEST) }
- 替换窗口类型
将原有的TYPE_SYSTEM_ALERT替换为TYPE_APPLICATION_OVERLAY(API 26+支持):
val layoutParams = WindowManager.LayoutParams( WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT, if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY } else { WindowManager.LayoutParams.TYPE_SYSTEM_ALERT // 兼容低版本 }, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN, PixelFormat.TRANSLUCENT )
二、实现应用前台锁定
使用系统lockTaskMode实现前台锁定,需配合前台服务保持稳定性:
- 声明权限
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" /> <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" /> <!-- 可选,防止后台被杀死 -->
- 创建前台服务
Android 8.0+必须通过前台服务维持锁定状态:
class LockTaskService : Service() { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { // 创建前台通知(Android 8.0+ 必填) val channel = NotificationChannel( "LOCK_TASK_CHANNEL", "锁定服务通知", NotificationManager.IMPORTANCE_LOW ) getSystemService(NotificationManager::class.java).createNotificationChannel(channel) val notification = NotificationCompat.Builder(this, "LOCK_TASK_CHANNEL") .setContentTitle("应用锁定中") .setContentText("当前应用已锁定在前台") .setSmallIcon(R.drawable.ic_lock) .build() startForeground(1, notification) return START_STICKY } override fun onBind(intent: Intent?): IBinder? = null }
记得在AndroidManifest.xml注册服务:
<service android:name=".LockTaskService" />
- 进入/退出锁定模式
val activityManager = getSystemService(ACTIVITY_SERVICE) as ActivityManager // 进入锁定模式 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (activityManager.isLockTaskPermitted(packageName)) { startService(Intent(this, LockTaskService::class.java)) startLockTask() } } // 退出锁定模式 stopLockTask() stopService(Intent(this, LockTaskService::class.java))
三、禁用通知栏(含来电通知栏)
结合全屏沉浸模式+悬浮窗拦截实现通知栏禁用:
- 设置全屏沉浸模式
在Activity的onCreate或onResume中添加:
window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)
- 添加全屏悬浮窗拦截触摸
创建透明全屏View覆盖屏幕,拦截所有触摸事件(包括下拉通知栏的操作):
val overlayView = View(this) overlayView.setBackgroundColor(Color.TRANSPARENT) overlayView.setOnTouchListener { _, _ -> true } // 拦截触摸事件 val windowManager = getSystemService(WINDOW_SERVICE) as WindowManager windowManager.addView(overlayView, layoutParams) // 使用前面定义的TYPE_APPLICATION_OVERLAY参数
注意:退出锁定时需移除该View:
windowManager.removeView(overlayView)
- 一加ColorOS特殊处理
手动在系统设置中开启应用权限:
- 设置 → 应用 → 你的应用 → 权限 → 悬浮窗(确保开启)
- 设置 → 应用 → 你的应用 → 特殊权限 → 显示在其他应用上层(确保开启)
四、关键注意事项
- Android 13+必须先申请
POST_NOTIFICATIONS权限,否则前台服务无法启动 - 锁定模式下,用户仅能操作当前应用,需提供退出锁定的入口(如密码验证)
- 测试时确保应用处于前台状态再启动锁定流程
内容的提问来源于stack exchange,提问作者Pratheeja
相关产品推荐
相关产品推荐

