You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 03:37:43