深入 Android 源码:react-native-keep-awake 如何用 FLAG_KEEP_SCREEN_ON 实现屏幕常亮(完整指南)
【免费下载链接】react-native-keep-awakeKeep the screen from going to sleep. iOS and Android.项目地址: https://gitcode.com/gh_mirrors/re/react-native-keep-awake
react-native-keep-awake是一个轻量级的 React Native 屏幕常亮组件,它通过 Android 系统的FLAG_KEEP_SCREEN_ON窗口标志位,防止应用在前台时屏幕自动熄灭。这篇文章带你深入源码,看懂它从 JS 层到 Android 原生的完整实现链路,适合想理解 React Native 桥接机制的初学者 📱
一、为什么需要"屏幕常亮"?
在实际开发中,有一类场景用户会长时间盯着屏幕但不频繁触摸:
- 🗺️ 导航应用:开车导航时,屏幕熄灭等于"路痴模式"
- 🎬 视频播放:播放器界面不希望系统打断观看
- 🏭 工业/展示终端:设备常开常显,无人值守
Android 系统默认会根据"用户空闲时长"自动熄屏以省电。要突破这个限制,最正统的方式就是设置窗口标志位——这正是 react-native-keep-awake 的核心。
二、整体架构:一个 JS 文件 + 一个 Java 文件
这个库的代码结构极其精简,全部核心逻辑只有两个文件:
| 层级 | 文件路径 | 职责 |
|---|---|---|
| JS 层 | index.js | 封装 React 组件,桥接到原生模块 |
| Android 层 | android/src/main/java/com/corbt/keepawake/KCKeepAwake.java | 调用系统 API 设置屏幕常亮 |
| Android 注册层 | android/src/main/java/com/corbt/keepawake/KCKeepAwakePackage.java | 向 React Native 注册原生模块 |
| iOS 层 | ios/KCKeepAwake.m | 对应 iOS 端的常亮实现 |
整个项目就是一个"最小可运行的原生模块"范例,非常适合学习 React Native 混合开发的套路。
三、JS 层:index.js 是怎么调用原生的?
index.js里定义了一个KeepAwake组件,它有两种使用方式:
// 方式一:作为组件渲染 <KeepAwake /> // 方式二:显式调用静态方法 KeepAwake.activate(); // 屏幕常亮 KeepAwake.deactivate(); // 恢复自动熄屏关键源码是这样的:
static activate() { NativeModules.KCKeepAwake.activate(); }这里用到的NativeModules是 React Native 内置的桥接对象。它会把 JS 端对activate()的调用,跨语言转发到 Android 端同名的@ReactMethod方法上。
还有一个巧妙的引用计数设计:
componentDidMount() { mounted++; KeepAwake.activate(); } componentWillUnmount() { mounted--; if (!mounted) { KeepAwake.deactivate(); } }也就是说:页面上渲染了几个<KeepAwake />,mounted就加几;只有当最后一个组件卸载时,才会真正调用deactivate()关闭常亮。这样多个页面组件共用时不会互相"抢开关",是个很实用的细节 💡
四、核心源码逐行解读:FLAG_KEEP_SCREEN_ON 登场
现在进入主角——KCKeepAwake.java的activate()方法:
@ReactMethod public void activate() { final Activity activity = getCurrentActivity(); if (activity != null) { activity.runOnUiThread(new Runnable() { @Override public void run() { activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); } }); } }这 10 行代码里藏着4 个 Android 开发的关键知识点:
1. 为什么要runOnUiThread?
@ReactMethod方法运行在 React Native 的Native 模块线程,而不是 UI 主线程。而 Android 的Window对象只能在主线程上操作,直接调用会抛CalledFromWrongThreadException。所以必须用runOnUiThread()把操作切回主线程再执行。
2. FLAG_KEEP_SCREEN_ON 到底做了什么?
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON是 Android 系统级的窗口标志位,它告诉窗口管理器:"这个窗口可见期间,不要启动熄屏计时器"。
它的作用范围是窗口级而非全局的——只影响当前 Activity 的屏幕常亮策略,不会干扰系统其他部分,是官方推荐的省电友好的方案(相比获取WAKE_LOCK权限更轻量)。
3. addFlags 与 clearFlags 是一对
deactivate()方法与之完全对称:
activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);一增一删,保证离开页面后屏幕恢复正常的熄屏行为,不给用户"偷电"。
4. 空指针防御
if (activity != null)保护了边界情况:如果 JS 调用发生在 Activity 尚未就绪时,直接静默跳过,不会崩溃。
📌 顺带一提,iOS 端
ios/KCKeepAwake.m用的是[[UIApplication sharedApplication] setIdleTimerDisabled:YES],同样是官方 API,双端思路完全一致。
五、模块注册:KCKeepAwakePackage 如何接入 React Native
JS 层能找到NativeModules.KCKeepAwake,靠的是KCKeepAwakePackage.java这个注册类:
public class KCKeepAwakePackage implements ReactPackage { @Override public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) { List<NativeModule> modules = new ArrayList<>(); modules.add(new KCKeepAwake(reactContext)); return modules; } }React Native 启动时会收集所有ReactPackage,并调用createNativeModules()把原生模块注册进模块表。模块名由getName()返回"KCKeepAwake",恰好与 JS 端的NativeModules.KCKeepAwake对上——名字必须一致,这是桥接能否通的关键。
六、安装与快速上手
获取源码:
git clone https://gitcode.com/gh_mirrors/re/react-native-keep-awake在 React Native 项目中使用:
npm install --save react-native-keep-awake然后在android/settings.gradle和android/app/build.gradle中引入模块(详见 README.md 中的 Manual install 章节,也可用react-native link自动链接)。
使用示例:
import KeepAwake from 'react-native-keep-awake'; // 播放视频时保持屏幕常亮 function PlayerScreen() { const startPlayback = () => KeepAwake.activate(); const stopPlayback = () => KeepAwake.deactivate(); // ... }七、实用建议与版本提醒
- ⚠️版本提醒:
package.json显示当前版本为 v4.0.0,README 顶部已标注该包处于**弃用(deprecated)**状态,官方推荐转向 Expo 团队维护的expo-keep-awake或社区维护的 fork@sayem314/react-native-keep-awake。新项目选型时建议优先考虑后者。 - ⏱️用完记得关:常亮会显著增加耗电,务必在页面卸载或任务结束时调用
deactivate()。 - 🧵理解线程模型:本库演示的"桥接线程 → 主线程"切换模式,是所有 React Native 原生模块的通用写法,吃透它收益很大。
八、总结
react-native-keep-awake 用不到 100 行代码,完整展示了 React Native 跨平台开发的经典链路:
JS 组件 → NativeModules 桥接 → @ReactMethod 原生方法 → 主线程执行系统 API
其中真正"干活"的只有一行:给窗口加上FLAG_KEEP_SCREEN_ON标志位。麻雀虽小,五脏俱全——如果你想深入 Android 源码或学习 React Native 原生模块开发,这个项目值得逐行读完 👏
【免费下载链接】react-native-keep-awakeKeep the screen from going to sleep. iOS and Android.项目地址: https://gitcode.com/gh_mirrors/re/react-native-keep-awake
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考