Flutter开发应用锁:悬浮层无法覆盖指定应用的问题解决及插件推荐
应用锁解锁界面不显示的问题排查与解决方案
一、先排查现有插件的问题
- 确认权限真的生效:别光依赖用户手动开启权限,用permission_handler的
checkPermissionStatus方法,每次要显示悬浮窗前都校验Permission.systemAlertWindow是否为PermissionStatus.granted——有些系统手动开启后仍需要代码层面确认权限状态。 - 检查应用启动监听是否触发:你用device apps拿到了应用列表,但得确保能精准抓到目标应用启动的时机。可以在监听逻辑里加日志,看看目标应用启动时,代码有没有走到显示悬浮窗的步骤。如果Flutter层面的监听不好使,就得靠原生代码来监听前台应用变化。
- 调整悬浮窗的层级和显示时机:Flutter Overlay Apps创建的悬浮窗可能层级不够,或者显示得太晚。试试在监听到应用启动的瞬间就调用显示方法,同时确保Android端设置的窗口类型是
TYPE_APPLICATION_OVERLAY(8.0及以上),这个层级才能覆盖普通应用。 - 排除目标应用的特殊性:先拿普通第三方应用(比如微信、淘宝)测试,有些系统应用、全屏应用或者开了隐私保护的应用会屏蔽悬浮窗,别一开始就拿特殊应用试。
二、关键实现步骤补全
1. 精准监听前台应用变化
Flutter本身没法直接监听前台应用,得通过MethodChannel调用Android原生代码:
- 原生端写个后台服务,用
ActivityManager实时获取当前前台应用的包名,每隔1秒检查一次。 - 监听到包名是你锁定的应用时,通知Flutter端显示解锁界面;不是的话就关掉悬浮窗。
示例原生Kotlin代码:
class ForegroundMonitorService : Service() { private lateinit var activityManager: ActivityManager private var checkTimer: Timer? = null override fun onCreate() { super.onCreate() activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { checkTimer = Timer() checkTimer?.scheduleAtFixedRate(object : TimerTask() { override fun run() { val runningTasks = activityManager.getRunningTasks(1) if (runningTasks.isNotEmpty()) { val currentPackage = runningTasks[0].topActivity?.packageName // 通过MethodChannel把包名传给Flutter MethodChannel(flutterEngine?.dartExecutor?.binaryMessenger, "app_monitor") .invokeMethod("onForegroundAppChanged", currentPackage) } } }, 0, 1000) return START_STICKY } override fun onBind(intent: Intent?): IBinder? = null override fun onDestroy() { checkTimer?.cancel() super.onDestroy() } }
Flutter端接收回调并处理:
final MethodChannel _appMonitorChannel = MethodChannel('app_monitor'); @override void initState() { super.initState(); _appMonitorChannel.setMethodCallHandler((call) async { if (call.method == 'onForegroundAppChanged') { String? packageName = call.arguments; if (packageName != null && _lockedPackages.contains(packageName)) { // 显示解锁界面,铺满整个屏幕 await OverlayApps.showOverlay( builder: (context) => UnlockScreen(targetPackage: packageName), height: MediaQuery.of(context).size.height, width: MediaQuery.of(context).size.width, ); } else { // 非锁定应用,关闭悬浮窗 await OverlayApps.closeOverlay(); } } }); // 启动原生监听服务 _appMonitorChannel.invokeMethod('startMonitor'); }
2. 确保悬浮窗层级足够
在AndroidManifest.xml里给悬浮窗权限声明,同时确保插件使用的窗口类型正确:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> <uses-permission android:name="android.permission.REORDER_TASKS" />
三、替代插件推荐
如果现有组合不好用,可以换这些插件试试:
- flutter_windowmanager:能精细控制窗口层级、透明度,配合自定义悬浮窗,灵活性比Flutter Overlay Apps高。
- applocker:专门做应用锁的插件,自带应用监听、解锁界面逻辑,不用自己搭基础框架,但要注意兼容性。
- flutter_background_service:用来保活后台监听服务,避免系统把监听进程杀掉,提升稳定性。
四、额外要注意的点
- 后台保活:Android系统会杀后台服务,得给应用申请「后台运行权限」,还要把监听服务设为前台服务,不然监听逻辑很容易失效。
- 版本适配:不同Android版本权限规则不一样,比如10+对后台活动限制更严,得对应调整权限申请和监听逻辑。
- 真机测试:模拟器的权限和应用监听逻辑和真机差异大,一定要在真机上测。
内容的提问来源于stack exchange,提问作者Saurabh Kumar
相关产品推荐
相关产品推荐

