ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

React Native for OpenHarmony 三方库 expo-screen-orientation 57.0.2 适配实战:四向锁定、策略映射与事件清理

React Native for OpenHarmony 三方库 expo-screen-orientation 57.0.2 适配实战:四向锁定、策略映射与事件清理 React Native for OpenHarmony 三方库 expo-screen-orientation 57.0.2 适配实战四向锁定、策略映射与事件清理屏幕方向适配最容易被“手机转了”这件事骗过。窗口策略、系统实际方向和事件回调使用的是三套枚举。本篇面向新手从这些概念开始逐步说明如何改源码、构建 HAR、接入宿主并在真机恢复用户原设置。适配仓库oh-react-native/expo-screen-orientation交付分支main适配 TAG57.0.2-ohos-1.0.0受测提交20846fea3cd1d8e74c54ff55466c1961b496204b上游基线c300d2cc60c9e684e64f48d9bc90ea18a571d01d对应 57.0.2 发布源码配套源码expo-screen-orientation一、这个库是做什么的expo-screen-orientation 用来控制和观察应用窗口方向。阅读器可以锁定竖屏横向表格可以锁定横屏游戏可以读取当前方向并在方向变化时调整布局。公开 API 包括 lockAsync、unlockAsync、getOrientationAsync、getOrientationLockAsync、getPlatformOrientationLockAsync、supportsOrientationLockAsync、addOrientationChangeListener、removeOrientationChangeListener 和 removeOrientationChangeListeners。新手常见的误解是“把 PORTRAIT 翻译成系统的 1把 LANDSCAPE 翻译成系统的 2”就完成了。实际上这里至少有三套值第一套是应用请求的窗口策略例如 PORTRAIT_UP第二套是显示对象当前的实际方向第三套是系统 RotationChangeInfo 事件里的旋转编码。它们的数值和命名都不能凭直觉共用。此次适配最大的工作量不是写一个 setPreferredOrientation而是把这三套语义分别验证清楚。适配前在 oh-react-native 组织、CPF-RN 组织 和活动中心清单中按包名、去 scope 名和 rntpc 前缀去重没有发现同上游的有效适配。上游 57.0.2 为 MIT最终仓库只保留该库自己的源码、HAR 和说明。图 1测试开始时为正向竖屏窗口原策略为 0八种通用策略能力检查通过原策略先保存结束后恢复。二、环境和交付身份受测组合为 React Native 0.84.1、React 19.2.3、RNOH 0.84.3、DevEco Studio 26.0.0 Release、HarmonyOS SDK 26.0.0ROM OpenHarmony-7.0.0.105。受测源码锁定在文首提交和 TAG文章中的截图来自同一精简包和签名 HAP不是后来改过代码的旧截图。仓库保留 src/index.ts、ExpoScreenOrientationTurboModule.ts、Spec、harmony/screen_orientation/Index.ets、ExpoScreenOrientationPackage.cpp、ExpoScreenOrientationPackage.ets、CMake、HAR、双语 README、测试、spec.json 和许可证。完整宿主和测试探针属于验证工程不作为三方库的一部分上传。三、从 JS 到窗口系统的调用链React 页面 - expo-screen-orientation 的 JS API - ExpoScreenOrientationTurboModule Spec - C Package methodMap_ - ArkTS TurboModule - UIAbility 主窗口 - Window.setPreferredOrientationWithResult / getPreferredOrientation锁定接口使用 Promise因为系统设置可能返回 ACCEPT、PENDING 或 IGNORED。查询接口也保留 Promise监听接口返回订阅对象。鸿蒙专属字段 screenOrientationConstantHarmony 用于记录窗口策略原值不能把 Android、iOS 和 Web 的枚举数字混到同一个比较里。本次锁映射为DEFAULT 使用系统未指定策略PORTRAIT_UP 和 PORTRAIT_DOWN 分别对应正向、倒置竖屏LANDSCAPE_LEFT 对应窗口 LANDSCAPE_INVERTEDLANDSCAPE_RIGHT 对应窗口 LANDSCAPE。固定左右横屏的名字与显示对象方向恰好不是同一顺序这是后面真机探针发现的关键差异。四、为什么不能照搬方向枚举第一版按 display.Orientation 的名字直接映射左右横屏导致 getter 与旋转事件不一致。最终让独立 ArkTS 探针绕过被测库对四种窗口策略逐一设置并读回窗口策略display.orientation公开 OrientationPORTRAIT10PORTRAIT_UP1PORTRAIT_INVERTED32PORTRAIT_DOWN2LANDSCAPE23LANDSCAPE_RIGHT4LANDSCAPE_INVERTED41LANDSCAPE_LEFT3监听又采用 RotationChangeInfo 的实际编码并且只在横竖类别变化时派发。也就是说竖屏正向转倒置竖屏可能改变 getter却不一定产生一次业务方向类别事件同类 180 度旋转没有被错误地重复通知。图 2固定竖屏与倒置竖屏分别读回公开方向 1 和 2两个监听已订阅。图 3转到左横屏时收到方向 3、锁 6再转到右横屏getter 为 4而事件仍遵守“只跨横竖类别通知”的契约。五、具体源码修改src/index.ts 保留 Expo 原 API增加 HarmonyOS 平台选择和鸿蒙专属策略字段。ExpoScreenOrientationTurboModule.ts 把每个公开函数转到同名原生方法统一 Promise、参数校验和错误传播。harmony/screen_orientation/Index.ets 和 ExpoScreenOrientationPackage.ets 注册 Package 工厂模块名与 C methodMap_ 一致。ArkTS 通过当前 RN 所在 UIAbility 的主窗口设置策略、查询策略和实际方向不使用缺失的 TYPE_MAIN 枚举而是比较真实 window ID。监听首订阅启动原生观察器最后一个订阅移除时取消每轮订阅有世代标识旧回调不能污染新订阅。销毁或恢复时先查询当前策略如果目标策略已经生效就视为幂等完成不把系统返回 IGNORED 的同值请求误报为失败。恢复逻辑可以概括为const before target.getPreferredOrientation(); if (before policy) { return; } const result await target.setPreferredOrientationWithResult(policy); if (result.executionResult ORIENTATION_IGNORED) { throw new Error(ERR_SCREEN_ORIENTATION_IGNORED); }只有同值已生效时才提前返回不同策略被系统忽略仍然拒绝 Promise调用者可以重试或提示用户。六、用最终 tgz 接入宿主受测使用与文首 TAG 对应的 expo-screen-orientation-57.0.2.tgz。把 tgz 放入独立宿主后按顺序执行export RNOH_HOST$HOME/rnoh-qa export EVIDENCE_DIR$RNOH_HOST/evidence/expo-screen-orientation mkdir -p $EVIDENCE_DIR cd $RNOH_HOST npm install $HOME/Downloads/expo-screen-orientation-57.0.2.tgz --save-exact ./node_modules/.bin/react-native link-harmony cd harmony ohpm install --all cd .. ./node_modules/.bin/react-native bundle-harmony --dev false --sourcemap-output $EVIDENCE_DIR/bundle.map hvigorw assembleHap --mode module -p productdefault --no-daemon等待 npm 完成后使用宿主本地 CLI检查 bundle source map 来自安装包。–dev false 是 JS bundle 选项不等于 release HAP本轮使用签名 debug HAP。只有从 tgz 重新构建并安装后面的真机截图才和文章中的提交、TAG 有关联。真机操作前先确认目标设备并设置临时常亮hdc list targets export DEVICE_ID$(hdc list targets | awk NF {print $1; exit}) hdc -t $DEVICE_ID install $RNOH_HOST/output/tested.hap hdc -t $DEVICE_ID shell power-shell wakeup hdc -t $DEVICE_ID shell power-shell timeout -o 2147483647 hdc -t $DEVICE_ID shell aa start -a EntryAbility -b com.example.rnqa hdc -t $DEVICE_ID shell uitest screenCap -p /data/local/tmp/orientation.png hdc -t $DEVICE_ID file recv /data/local/tmp/orientation.png $EVIDENCE_DIR/orientation.png结束后恢复原超时并确认最终策略回到验证前保存的值不能因为截图完成就跳过恢复。七、业务侧调用和监听import * as ScreenOrientation from expo-screen-orientation; const before await ScreenOrientation.getOrientationLockAsync(); try { await ScreenOrientation.lockAsync( ScreenOrientation.OrientationLock.PORTRAIT_UP ); const actual await ScreenOrientation.getOrientationAsync(); console.log(实际方向, actual); } finally { await ScreenOrientation.unlockAsync(); // 真实业务可在这里恢复 before 对应的策略 } const subscription ScreenOrientation.addOrientationChangeListener(event { console.log(event.orientationInfo.orientation); }); // 组件卸载时调用 ScreenOrientation.removeOrientationChangeListener(subscription);锁定完成只表示系统接受策略不表示旋转动画已经结束。需要读取实际方向并等待页面布局稳定再更新业务状态。事件监听要在组件卸载时删除不能只把回调置空否则原生观察器仍可能持有上下文。图 4通用传感器、受限策略、当前方向锁定和默认策略均由系统读回鸿蒙没有通用等价项的策略返回 OTHER。八、真机验证过程验证开始先保存原策略 0。随后依次测试四种方向锁、十种系统策略查询、能力检查、单个监听移除、全部监听移除、重新订阅和八种非法参数。每次 lock 后都等待系统读回不把 Promise resolve 当作屏幕已经转完。结束时 unlock再把原策略恢复如果原策略本来就是 0第二次设置 0 会被识别为同值幂等而不是失败。图 5监听 A 重复移除后B 仍收到变化全部移除后原生观察器没有继续派发重新订阅又能收到新的类别变化。图 6八种非法请求被拒绝OTHER 无操作unlock 恢复默认最后由独立入口核对原策略。本轮还进行了两次不同进程的资源 bundle 冷启动。mock 覆盖系统拒绝、PENDING、缺少传感器和模块销毁真机覆盖四向映射、读回、事件生命周期、恢复和冷启动。发布文章只保留仓库和官方文档链接读者复现时应以自己的设备截图、日志、HAP 和包哈希为准。九、踩坑、限制和结论窗口主类型是一个版本差异点。SDK 声明 TYPE_MAIN但本机对象没有该属性实际 windowType 为 32最终用 RN 窗口和 Stage 主窗口的真实 ID 判断避免依赖缺失枚举。另一个问题是 unlock 后再次设置同一个默认策略时系统返回 IGNORED这不是业务失败只有目标策略与当前不同且被忽略才应拒绝。本次没有人工物理转动手机或切换用户旋转开关也没有覆盖外接屏、自由窗口、平板和其他 ROM。方向事件只承诺本次实现的横竖类别变化语义不承诺每次 180 度姿态变化都触发回调。应用应在页面布局层同时使用实际方向查询和监听结果。十、参考链接上游 expo-screen-orientation 文档适配仓库首页main 分支57.0.2-ohos-1.0.0 TAGOpenHarmony Window APIOpenHarmony 屏幕方向 API欢迎加入 RN for OpenHarmony 社区。
返回列表