OpenHarmony + React Native 中 Checkbox 状态绑定全解析 📅 发布时间:2026/9/10 19:12:44 👁 浏览次数: 刚接触 OpenHarmony 上跑 React Native 的时候我相信很多人跟我一样第一个想法都是“我 Web 前端那套写法搬过来就能跑”。结果真把项目跑起来一个看似再普通不过的 Checkbox 选中状态绑定就给你上了一课明明 JS 里 state 已经更新了界面上勾选状态却纹丝不动又或者第一次点击正常第二次点击就开始抽风。这篇文章我就围绕 OpenHarmony RN 场景下的 Checkbox 选中状态绑定把从组件原理到实际编码再到问题排查的完整链路拆开讲讲。先说清楚这篇文章适合谁。如果你正在做 OpenHarmony 应用又因为历史原因或团队技术栈原因选了 React Native 作为跨端方案接下来的内容可以直接帮你少走很多弯路如果你还没上 RN只是想了解 OpenHarmony 原生 ArkUI 和 RN 组件之间是怎么协同工作的也可以当一篇底层原理科普来读。我会把受控组件、事件链路、状态同步这些核心概念揉碎了讲尽量让不同基础的读者都能跟着落地。1. 先别急着写绑定逻辑搞清楚 OpenHarmony 上 Checkbox 的真面目写代码之前我习惯先搞清楚组件到底是怎么渲染出来的。很多问题看起来是“绑定没写好”实际上是对组件模型的理解有偏差。在 OpenHarmony 上使用 RN和你在 Android、iOS 上写 RN 有一个本质区别RN 的渲染层不是直接用系统原生控件而是通过一个叫“RNOH”React Native OpenHarmony的适配层把 JS 侧的组件声明映射到 OpenHarmony 的 ArkUI 组件上。这就导致你写一个Checkbox看到的却是 OpenHarmony 的Checkbox组件在底层帮你完成勾选和绘制。这个映射机制带来两个直接影响。第一Checkbox 的外观、交互行为在三个平台上可能不完全一致你不能想当然地认为“iOS 上什么样OpenHarmony 上就是什么样”。第二状态同步的链路变长了JS 侧的 state 发生变化要经过 RN 的 diff 算法、命令队列、Bridge 或 JSI 通道最终才让 ArkUI 侧的组件更新。任何一个环节出问题都会表现为“状态绑定失败”。1.1 看上去很简单的 Checkbox为什么一到 OpenHarmony 就翻车我最早踩的第一个坑是这样的在页面里写了类似value{this.state.checked}的受控写法然后通过onValueChange去更新 state。在 Android 上跑得好好的一搬到 HarmonyOS 模拟器上点击复选框后 UI 上的勾选会闪现一下又变回原样。当时第一反应是“RNOH 的这个组件 bug 太多了”但后来排查下来发现问题出在受控组件在事件回传和状态更新之间的时序上。在 RN 的标准模型里受控组件的正常运行依赖一套闭环原生组件触发事件 - 事件传给 JS - JS 更新 state - state 通过 diff 算法同步回原生组件。如果 JS 侧的 setState 是异步的或者原生侧在事件回调之后立刻做了组件状态的强制刷新就很容易出现“中间态覆盖”。OpenHarmony 的 ArkUI 组件本身也有自己的状态管理机制如果它在事件回调之后、JS 状态下达之前进行了内部重绘那 JS 这边把 state 传下去时已经晚了视觉上就是“闪一下又回去”。这个问题的本质是两套状态管理模型在同一个组件上发生了竞争。理解这一点很重要因为几乎所有 Checkbox 绑定相关的怪问题追根溯源都能落到这个竞争关系上。1.2 摸清 RN 的受控组件与非受控组件模型RN 的组件分为受控和非受控两种。受控组件的状态完全由 JS 侧管理UI 只是 state 的投影非受控组件则让原生侧自己维护状态JS 只在需要的时候通过 ref 去拿值。Checkbox 这里有个容易混淆的地方RN 官方的Checkbox组件android 专属早期是支持value属性作为受控值的但社区里很多基于 OpenHarmony 的 RN 实现包括react-native-oh-tpl/react-native这个仓库里的组件在行为上会有细微差异。有些版本你传了value它并不会像预期那样严格受控而是更像“半受控”状态有些版本则需要你同时处理onValueChange和内部状态的自动更新。我的建议是在 OpenHarmony 上写 Checkbox尽量明确走“完全受控”路线也就是使用valueonValueChange并且不要在onValueChange之外再修改原生组件的状态。这样做虽然代码多一点但状态流是单向的排查问题要容易得多。1.3 三方框架下原生状态和 JS 状态谁说了算这里我想多说一点“谁的代码在管状态”的问题。在纯 ArkUI 开发中你可以直接用State装饰器管理 Checkbox 的勾选状态框架会帮你做响应式更新。但在 RN 场景下ArkUI 组件只是一个“被渲染的壳”JS 侧才是状态管理的核心。如果你在原生侧写了自定义组件还试图用 ArkUI 的State去驱动同一个 Checkbox 的勾选状态那结果大概率是两边互相踩脚。我用一个生活化的类比来解释把组件想象成一个电灯开关。JS 侧 state 是“墙上的开关面板”ArkUI 的组件状态是“灯泡本身”。如果两条线路都能控制灯泡那迟早会出问题——你在面板上按了关灯泡那边又因自身逻辑开起来你根本分不清灯到底该亮还是该灭。所以原则就是状态只管一头要么 JS 管要么原生管不要搞多头管理。2. 核心实现Checkbox 选中状态的受控绑定方案代码层面的东西直接讲实现最实在。下面我按从简单到复杂的顺序给出几种 Checkbox 状态绑定的写法并解释每一步为什么这么写。2.1 最基础的绑定value onValueChange最基础的绑定写法就是这个样子import React, { useState } from react; import { Checkbox, View, Text } from react-native; export default function BasicCheckboxDemo() { const [isChecked, setIsChecked] useState(false); return ( View style{{ padding: 20 }} Checkbox value{isChecked} onValueChange{(newValue) { setIsChecked(newValue); }} / Text{isChecked ? 已选中 : 未选中}/Text /View ); }这段代码看起来没有任何问题但有几个细节值得注意。第一value属性在 OpenHarmony 的 RN 实现中一定要和onValueChange配套使用。只写value不写回调用户点击后组件会进入“不受控”状态状态不同步只写onValueChange不写value某些版本下会出现 UI 更新了但 JS 侧 state 没变或者 state 变了 UI 没变的诡异现象。第二onValueChange回调里的参数newValue在大多数实现里是一个 boolean但也有一些版本的 RNOH 会把它包成一个事件对象。建议你在回调开头打一条日志console.log(typeof newValue)确认一下类型。如果收到的是对象需要手动取出nativeEvent里的值。第三这个绑定的本质是“单向数据流”。你点击 Checkbox原生组件触发onValueChangeJS 收到后更新 statestate 变化再驱动 UI 刷新。你千万不要在回调里直接去操作 DOM 或者调用组件实例的方法来改选中态那会打破单向数据流后面排查会非常困难。2.2 初始化默认值真正回显时不生效怎么办实际项目中Checkbox 通常不是一开始就处于未选中状态而是需要根据接口数据或本地存储回显。比如一个“同意用户协议”的勾选框用户之前勾过重新进入页面就要默认勾上。这里我遇到过多次“回显不生效”的问题现象是state 的初始值明明是true界面上的 Checkbox 却仍然显示未选中。为什么因为 Checkbox 是一个“已经挂载到原生侧”的组件如果它在 JS 侧已经存在了一帧而你在第二帧才通过异步数据把value从false改成true在某些实现里 ArkUI 组件可能不会正确响应这个更新。更稳妥的做法是在拿到数据之前先不渲染 Checkbox或者给它一个 key 让它重新挂载。具体代码如下const [loading, setLoading] useState(true); const [agree, setAgree] useState(false); useEffect(() { fetchUserSetting().then((res) { setAgree(res.agree); setLoading(false); }); }, []); if (loading) { return ActivityIndicator /; } // 确保拿到初始值后再渲染避免状态回显失败 return ( Checkbox key{agree ? checked : unchecked} value{agree} onValueChange{(v) setAgree(v)} / );这里用key变化的技巧来强制组件重新创建是一个很实用的兜底方案。不过要注意key变来变去会让组件重新挂载如果 Checkbox 周围有动画或者联动效果可能会造成闪烁所以能用“先 loading 再渲染”解决的就优先用 loading 方案。2.3 state 批量更新时的坑setState 异步和合并RN 的setState是异步的也就是说你调用setAgree(true)之后立刻去读agree这个变量得到的还是旧值。这在普通场景下没什么影响但在做联动或提交时经常踩坑。比如用户勾选 Checkbox 的同时你要提交一份表单并判断用户是否已经同意协议如果代码写成这样onValueChange{(v) { setAgree(v); if (agree) { // 做一些操作 } }}你会发现agree永远都是旧值条件判断根本不按预期走。正确做法是用函数式更新或者把逻辑放到useEffect里监听agree变化后再执行联动。第二个坑是 state 合并。如果你在一个事件里同时更新多个 stateReact 会把这些更新批量合并只触发一次渲染。这在大多数情况下是性能优化但如果你的业务逻辑依赖“先更新 A 再更新 B”的顺序就可能出问题。好在 Checkbox 场景一般不会这么复杂但我在实现“勾选后置灰其他选项”时遇到过后面在进阶场景里我再细说。2.4 代码示例一个完整可跑的 Checkbox 示例为了让新手能直接抄我给出一个比较完整的页面示例包含 Checkbox 列表展示、状态绑定、动态联动以及模拟提交结果import React, { useState, useEffect } from react; import { View, Text, Checkbox, Button, StyleSheet, Alert } from react-native; const OPTIONS [ { id: frontend, label: 前端开发 }, { id: backend, label: 后端开发 }, { id: design, label: UI 设计 }, ]; export default function FormDemo() { const [selected, setSelected] useState([]); const [agree, setAgree] useState(false); const [isSubmitting, setIsSubmitting] useState(false); const toggleOption (id) { setSelected((prev) { if (prev.includes(id)) { return prev.filter((item) item ! id); } return [...prev, id]; }); }; const canSubmit agree selected.length 0; const handleSubmit () { if (!canSubmit) { Alert.alert(提示, 请先勾选同意协议并选择至少一项技能); return; } setIsSubmitting(true); // 模拟接口请求 setTimeout(() { Alert.alert(提交成功, 已选择${JSON.stringify(selected)}); setIsSubmitting(false); }, 1000); }; return ( View style{styles.container} Text style{styles.title}技能选择/Text {OPTIONS.map((opt) { const checked selected.includes(opt.id); return ( View key{opt.id} style{styles.row} Checkbox value{checked} onValueChange{() toggleOption(opt.id)} / Text style{styles.label}{opt.label}/Text /View ); })} View style{styles.divider} / View style{styles.row} Checkbox value{agree} onValueChange{(v) setAgree(v)} / Text style{styles.label}我已阅读并同意《用户协议》/Text /View Button title{isSubmitting ? 提交中... : 提交} onPress{handleSubmit} disabled{isSubmitting} / /View ); } const styles StyleSheet.create({ container: { flex: 1, padding: 16, backgroundColor: #fff }, title: { fontSize: 18, fontWeight: bold, marginBottom: 12 }, row: { flexDirection: row, alignItems: center, marginBottom: 12 }, label: { marginLeft: 8, fontSize: 15 }, divider: { height: 1, backgroundColor: #eee, marginVertical: 12 }, });这个示例可以看到函数式更新、状态派生和联动控制三个关键点。canSubmit这个变量不是独立的 state而是从agree和selected派生出来的这样写的好处是状态来源唯一不会出现“数据不同步”的问题。3. 进阶场景列表、表单里的 Checkbox 绑定单个 Checkbox 的绑定搞定了真正的挑战往往在列表和复杂表单里面。下面是几个我在实际项目里反复用到的高频场景。3.1 列表中的 Checkbox 状态管理列表里的每个 Checkbox 都有自己的选中状态很多人第一反应是给每条数据加一个checked字段然后修改对应项的字段值。这个思路没错但要注意别走“拷贝整个列表再赋值”的弯路那样不仅代码丑还容易因为引用地址没变化导致 UI 不刷新。我推荐两种做法。第一种是把选中状态维护在一个独立数组或者 Set 里用 id 作为唯一标识第二种是把数据项放到一个不可变对象里更新时用解构生成新数组。第二种写法更符合 React 的数据流习惯也方便做脏检查const [list, setList] useState([ { id: 1, name: 任务一, done: false }, { id: 2, name: 任务二, done: true }, { id: 3, name: 任务三, done: false }, ]); const toggleItem (id) { setList((prev) prev.map((item) item.id id ? { ...item, done: !item.done } : item ) ); };这里最关键的是必须用map生成一个新数组并且对目标项用展开运算符生成新对象。如果直接修改item.done再setListReact 会认为引用没变跳过渲染UI 就不会更新。这一点很多新手容易忽略。3.2 全选/反选/单选联动多选列表经常会配套“全选”和“反选”功能。全选逻辑很简单就是把所有项的选中状态设为同一个值然后 Checkbox 的全选框要显示“半选”或者“全选”状态这就需要一种特殊处理。在 ArkUI 原生组件中Checkbox 有indeterminate属性来表示半选但在 RN 的标准组件里不一定暴露。我在 OpenHarmony 实践时一般用全选框的value来判断当所有项都被选中时value为true当部分选中时value为false同时用自定义样式给半选状态一个视觉提示。必要时可以包一层原生自定义组件把 ArkUI 的半选状态暴露给 RN 端。联动逻辑我建议抽成纯函数方便测试和复用const getSelectAllState (list) { const doneCount list.filter((item) item.done).length; if (doneCount 0) return unchecked; if (doneCount list.length) return checked; return partial; }; const handleSelectAllChange (isChecked) { setList((prev) prev.map((item) ({ ...item, done: isChecked })) ); };注意getSelectAllState返回三个状态而不是一个 boolean。这个函数只依赖list所有调用侧保持一致就不用担心状态分散导致的不一致问题。3.3 表单提交时的状态获取表单提交时很多人喜欢在提交事件里去读this.state或者用 ref 访问 Checkbox 的值。其实受控组件下表单数据已经全部存在 state 里了提交时直接把 state 传出去就行。唯一要注意的是如果setState是异步的而你的提交按钮是在勾选之后马上点击可能会出现“勾选动作已触发但 state 还没更新”的竞态。这种情况下建议在提交函数里直接计算当前状态而不是从 state 里读。比如const handleSubmit () { // 不要在这里依赖 state 中的 agree改用最新值 const finalAgree agreeRef.current; if (!finalAgree) { Alert.alert(请先同意协议); return; } // 提交逻辑 };用useRef同步保存一份最新值是绕过setState异步问题的一个经验技巧。不过这是非主流写法只在特殊场景使用日常还是建议靠状态派生和useEffect来解决。3.4 绑定后联动其他控件Checkbox 的选中状态经常会联动按钮可用性、其他选项的置灰、动态展示区块等。联动的实现核心在于“状态派生”而不是把派生结果又存一份 state。举个例子用户勾选“使用收货地址”后地址输入框才显示出来未勾选时输入框隐藏并且不需要校验。我可以这样写const [useDefaultAddress, setUseDefaultAddress] useState(true); const [address, setAddress] useState(); // 地址是否必填取决于勾选状态 const isAddressRequired useDefaultAddress; const handleSubmit () { if (isAddressRequired !address.trim()) { Alert.alert(请输入收货地址); return; } // ... };这里isAddressRequired就是派生状态。如果把它存成另一个 state每次勾选时还得手动同步一旦漏同步就会出 bug。派生状态的好处就是“随时算出来”永远不会和源头状态失配。4. OpenHarmony 原生侧交互状态一致性问题的底层逻辑前面提到过RN 在 OpenHarmony 上是通过 RNOH 适配层把 JS 组件映射到 ArkUI 组件的。这个链路里的状态一致性是很多怪问题的根源。我单独用一节来讲底层逻辑不是为了凑篇幅而是因为你只有理解了这条链路才能在遇到问题时快速定位是 JS 的问题还是原生适配的问题。4.1 RN 到 OpenHarmony 的事件链路当用户点击屏幕上的 Checkbox 时事件并不是直接跑到 JS 侧的。它的完整路径是这样用户触摸 - OpenHarmony 侧 Checkbox 原生组件接收到触摸事件 - 触发组件的onChange回调 - RNOH 的绑定层把 ArkUI 的onChange事件包装成 RN 的onValueChange事件 - 事件通过 JSI/TurboModule 通道传递到 JS 侧 - JS 执行回调函数。这个链路里任何一个环节慢一拍都会影响交互的实时性。我在性能排查时经常看到某些低端设备上从点击到 JS 回调触发的延迟高达几百毫秒用户就会觉得“点了没反应”。这种情况通常不是绑定逻辑写错而是真机性能或适配层的问题。如果你需要降低延迟可以考虑用原生侧直接管理 UI 状态等页面提交时再去原生侧读取最终值。但这会牺牲受控组件的简洁性属于“性能优化与代码可维护性之间的权衡”要结合业务实际决定。4.2 原生侧如何保证状态同步在 RNOH 的实现中ArkUI 的 Checkbox 组件接收到 JS 传来的value属性更新时会调用原生组件的属性更新方法。如果这个过程失败或遗漏JS 和原生状态就会脱节。从我碰到的案例来看有几种情况最容易出现“原生侧状态的强制覆盖 JS 状态”第一ArkUI 组件在内部对 Checkbox 的选中状态做了状态管理如果它在渲染过程中自己改变了选中态却没有通过事件上报给 JS那 JS 侧的 state 和界面的实际显示就会不一致。修复方式一般需要修改原生适配层或者用key强制重挂载组件。第二RNOH 在处理组件属性时对一些基础类型boolean的更新可能有缓存优化。如果上一次的值和这一次的值完全相同它可能不会触发原生组件的更新方法。这在高频刷新时偶尔会遇到。处理方式是在更新前先强制置为相反值再置回目标值或者升级 RNOH 版本看看是否已有修复。第三多实例共享的组件可能发生状态污染。比如一个自定义的 Checkbox 封装在原生侧用了单例或静态变量保存选中状态那多个页面共用时就会出现“A 页面改了B 页面也跟着变”的问题。这个问题很难从 JS 层面排查只能在原生侧写代码时注意不要用共享可变状态。4.3 和“调用电话功能”这类原生能力混用的注意事项热词里有一个“rn调用电话功能”虽然和 Checkbox 绑定不是同一个主题但在我实际项目中它和状态绑定经常出现在同一个页面。比如一个客服页面有“同意隐私政策”Checkbox勾选后才能点击“拨打电话”按钮联系客服。电话功能在 RN 中可以通过react-native-communications或Linking.openURL(tel:xxx)来调用。在 OpenHarmony 上Linking的telscheme 支持情况需要单独验证因为 HarmonyOS 的应用沙箱和权限模型与 Android 有所不同。我建议在真机上用一个最简单的按钮直接测一下Linking.openURL(tel:10086)是否能正常唤起拨号盘而不是等联调时才发现。更稳妥的做法是通过自定义原生模块封装电话功能在 ArkUI 侧调用startAbility或者系统提供的 dial 能力然后通过 Promise 回传给 JS。这样既能复用原生的权限处理逻辑也能和 JS 侧的状态绑定解耦。不过要注意一点无论你用哪种方式调电话都应该在用户点击拨号前检查 Checkbox 的勾选状态。这个检查要放在“拨号按钮的点击事件里”而不是放在“Checkbox 的 onValueChange 里”避免状态异步更新导致瞬间误判。我的写法通常是const handleCall () { if (!agree) { Alert.alert(请先同意隐私政策); return; } Linking.openURL(tel:10086).catch((err) { console.warn(唤起拨号失败, err); }); };这样逻辑清晰也方便后续做埋点统计。5. 常见问题与排查技巧实录写代码没有不踩坑的尤其是跨端场景。我把过去在 OpenHarmony RN 的 Checkbox 绑定上遇到的典型问题整理成了一个速查表并附上我的排查思路希望能帮大家省点时间。5.1 Checkbox 点击没有反应现象点击 Checkbox 区域视觉上没有变化onValueChange回调没有触发或者触发了但 state 没更新。排查步骤先确认你点击的确实是 RN 的 Checkbox 组件而不是上层覆盖了一个挡住触摸的 View。我遇到过一次布局里有个绝对定位的 View 覆盖在 Checkbox 上导致怎么点都没反应。看onValueChange有没有被正确绑定。如果绑定的函数写成了onValueChange{handleChange()}多了括号那会在渲染时就执行一次而不是点击时执行。打印newValue的类型确认收到的是不是 boolean。检查 RN 版本和 RNOH 适配层的版本是否匹配。我带过一个项目RN 升级后没有同步升级 RNOH导致很多原生组件的事件无法正常回调。5.2 状态回显总是慢一拍现象进入页面时接口返回了勾选状态但 Checkbox 先是显示未选中过了一会儿才变成选中甚至一直不变化。这个问题的原因通常有两个。一是异步数据到达前Checkbox 已经渲染了第一帧而后续的属性更新没有被原生组件正确接收二是value属性在初始渲染时传了false后续改成true时RNOH 的属性 diff 认为值没变内部缓存问题。我的解决方案是在数据到达前不渲染 Checkbox用 loading 状态占位。如果必须显示使用key强制重新挂载。升级 RNOH 到最新版本很多属性更新的 bug 在新版中已修复。5.3 列表滑动后 Checkbox 状态错乱这是列表类页面的“经典问题”在 RN 的 FlatList 中尤其容易出现。原因是 FlatList 会回收离屏的 item如果你直接用了数组索引作为 key或者没有正确维护数据状态就会出现“一项勾选另外一项也变勾选”的鬼畜情况。解决办法分两步给 FlatList 的每个 item 设置稳定的 key优先使用数据 id不要用索引。状态管理不要放在 item 子组件内部而是放在父组件统一维护。子组件只负责展示value并透传onValueChange。我见过有人为了省事直接在 item 里写useState(false)来管理勾选结果每次 item 被回收再渲染状态就重置了列表滚动后一片混乱。正确做法是“状态提升”所有勾选状态都放到list数据里。5.4 性能问题渲染卡顿如果在列表页里放了几十个 Checkbox每次勾选都导致整个列表重新渲染页面就会明显卡顿。这个问题的根源是状态变化引发了大范围的重渲染。优化思路有三个用React.memo包裹 item 子组件让它只在value或onValueChange引用变化时才重新渲染。useCallback包裹onValueChange避免每次父组件渲染都生成新的函数引用。如果列表非常长考虑用useSelector之类的局部订阅方案或者只把变化的那一项状态提升到单独的 context 中。下面是一个简单的 memo 示例const ListItem React.memo(({ item, onToggle }) { return ( View style{styles.row} Checkbox value{item.done} onValueChange{() onToggle(item.id)} / Text{item.name}/Text /View ); });父组件里用useCallback保证onToggle引用稳定const handleToggle useCallback((id) { setList((prev) prev.map((item) item.id id ? { ...item, done: !item.done } : item ) ); }, []);这样优化之后勾选一个 Checkbox 只会重渲染对应的 item而不是整个列表。6. 一些工程化建议和体会到这里核心内容基本讲完了。最后我想从工程实践角度再补充几点自己的体会不一定每条都和技术有关但对实际项目帮助很大。先说组件封装。我建议把 Checkbox 的绑定逻辑封装成一个通用的自定义组件对外暴露label、checked、onChange等属性内部屏蔽掉 OpenHarmony 和 Web 端的差异。这样业务层不需要关心底层用的是哪个平台的 Checkbox换端的时候只需要改一个文件。其次是测试。RN 的组件逻辑可以用 Jest 做单元测试但绑定 OpenHarmony 原生组件后很多行为没法在纯 JS 环境里模拟。我的经验是“核心逻辑抽纯函数、UI 层保持薄层”。比如全选状态的计算、列表勾选数组的增删这些逻辑可以放到纯函数里然后用常规的测试用例覆盖。UI 层哪怕出问题也可以通过人工测试快速定位。最后说一下版本管理。OpenHarmony 生态发展快RNOH 的版本更新也很频繁。我强烈建议锁定依赖版本并记录升级日志。很多时候“昨天还好好的今天就不行了”就是依赖被自动升级导致的。锁定版本后每次升级都做一次回归测试尤其是 Checkbox 这类基础组件稳定比炫技重要。从我个人的实战感受来看OpenHarmony RN 的这套组合还在快速演进中遇到这类组件绑定问题很正常不用慌。关键还是要理解状态管理的本质清楚数据是从哪里来、到哪里去、谁在控制 UI只要这几个问题想明白了大部分所谓的“疑难杂症”都能迎刃而解。后面如果大家有兴趣我可以继续分享 OpenHarmony 上其他 RN 组件比如 TextInput、Modal的适配问题和实战方案或者聊聊如何在 OpenHarmony 上用自定义原生模块封装系统能力。这篇就先到这儿。