Flutter如何实现类似SlideJoy的亮屏后解锁前显示自定义页面
Flutter实现类SlideJoy锁屏前置自定义页方案
受系统沙箱机制约束,该功能仅可在安卓端实现,iOS端无公开API支持覆盖系统解锁前界面。
整个实现的核心逻辑不是替换系统锁屏,而是在系统解锁界面上层叠加一层可关闭的自定义窗口,用户左滑关闭窗口后即可看到原生解锁界面,和SlideJoy的交互逻辑完全一致。
第一步:安卓端原生配置与桥接
Flutter本身作为UI渲染框架不具备系统级窗口操作能力,需要先在安卓宿主层完成核心配置:
- 清单文件权限声明,在
android/app/src/main/AndroidManifest.xml中添加以下权限:
<!-- 悬浮窗权限,用于在所有应用/锁屏上层显示页面 --> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> <!-- 亮屏/锁屏状态监听 --> <uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <!-- 安卓12+ 全屏意图权限,支持锁屏状态拉起页面 --> <uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
- 自定义Flutter承载Activity,给对应的Activity节点添加锁屏显示属性:
<activity android:name=".CustomLockActivity" android:exported="true" android:showOnLockScreen="true" android:turnScreenOn="true" android:launchMode="singleInstance" android:excludeFromRecents="true"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity>
- 注册屏幕状态广播接收器:监听系统
ACTION_SCREEN_ON(屏幕点亮)广播,收到广播后直接拉起上面配置的CustomLockActivity,保证用户亮屏后第一时间看到自定义页面。 - 配置窗口参数:在
CustomLockActivity的onCreate生命周期中添加窗口flag,让页面显示在锁屏层之上:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) { setShowWhenLocked(true) setTurnScreenOn(true) } window.addFlags( WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON or WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD ) // 注册MethodChannel,接收Flutter侧发来的关闭页面指令 MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "lock_screen_channel").setMethodCallHandler { call, result -> if (call.method == "dismissLockPage") { // 关闭当前自定义锁屏页,底层原生解锁界面自动露出 finish() result.success(null) } }
- 国产ROM适配:针对小米、华为、OPPO、vivo等定制系统,需要额外引导用户开启「锁屏显示」「后台弹出页面」权限,否则亮屏时无法正常拉起自定义页面。
第二步:Flutter侧交互与UI实现
编写自定义锁屏页,使用GestureDetector监听横向左滑手势,配合跟手动画实现和SlideJoy一致的交互:
import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; class LockScreenPage extends StatefulWidget { const LockScreenPage({super.key}); @override State<LockScreenPage> createState() => _LockScreenPageState(); } class _LockScreenPageState extends State<LockScreenPage> { double _dragOffset = 0; static const _channel = MethodChannel('lock_screen_channel'); @override Widget build(BuildContext context) { final screenWidth = MediaQuery.of(context).size.width; return Scaffold( body: GestureDetector( onHorizontalDragUpdate: (details) { // 仅响应向左滑动的手势 if (details.delta.dx < 0) { setState(() { _dragOffset += details.delta.dx.abs(); }); } }, onHorizontalDragEnd: (details) { // 滑动距离超过屏幕1/3则触发关闭 if (_dragOffset > screenWidth * 0.3) { _channel.invokeMethod('dismissLockPage'); } else { // 未达阈值则回弹复位 setState(() { _dragOffset = 0; }); } }, child: AnimatedContainer( duration: const Duration(milliseconds: 200), curve: Curves.easeOut, transform: Matrix4.translationValues(-_dragOffset, 0, 0), width: double.infinity, height: double.infinity, color: Colors.white, // 替换为你需要展示的自定义内容,比如资讯、广告、快捷功能入口 child: const Center( child: Text("自定义锁屏页面,左滑进入解锁界面", style: TextStyle(fontSize: 18)), ), ), ), ); } }
关键注意事项
- 该方案不会修改、绕过系统原生解锁逻辑,自定义页面仅为悬浮在解锁层上方的普通窗口,关闭后用户仍需通过指纹、密码、人脸等系统校验才能进入桌面,不会触发应用商店安全合规风险。
- 需要额外处理特殊场景中断:检测到来电、闹钟响铃等系统级事件时,主动关闭自定义锁屏页,避免遮挡系统关键界面。
- 首次启动应用时需要引导用户手动开启悬浮窗、锁屏显示等必要权限,否则功能无法正常运行。
内容的提问来源于stack exchange,提问作者Dennis Washira
相关产品推荐
相关产品推荐

