React Native for OpenHarmony 实战:三方库 react-native-url-polyfill 的鸿蒙化适配指南

本文记录把 react-native-url-polyfill(WHATWG URL 标准实现)适配到 HarmonyOS 的完整过程。

这个库有个特点:它不需要做原生适配 。但"不需要适配"本身就是个需要被证明的结论------而且证明的难点不在"它能不能跑",而在"它跑得对不对"。URL 解析有一份所有人都认的标准语料,这次就靠它把结论钉死了。


一、先说结论

项 结果
上游最新版 4.0.0(核对 npm registry 的 gitHead,与交付包 spec.json 记的基线 commit 完全一致)
是否需要原生适配 不需要 ------没有 harmony/、没有 android/、没有 ios/,也没有自己的原生模块
是否需要 HAR / 权限 / ohpm 接线 都不需要
依赖 无(上游 4.0.0 已把 URL 实现打包进 js/URL.js,20,008 字节)
与 npm 上游的差异 零内容改动(逐文件 SHA256 核对,唯一差异是 git checkout 的 CRLF)
自动链接信号 linked 9 libraries, skipped 1 libraries ------ 计数未增加,库被正确跳过
编译 assembleHap 6 分 34 秒;HAP 80,867,224 → 81,260,441 字节 (+393,217 ≈ 384 KB)
设备侧断言 ✅ 35 / 35 全部通过
WPT 官方一致性语料 1580 条用例,通过 1538,失败 42 ;42 条全部 是上游自己声明的已知偏差,未预期偏差 0
跨引擎一致性 ✅ 同一份测量代码跑 PC(V8)与设备(Hermes),失败集合差集为 0
同机对照 鸿蒙自带 URL 只过 234 / 1580,这个库过 1538 / 1580

一句话结论 :它可以直接用,不需要鸿蒙原生代码;它带来的是"从 234 条到 1538 条"的一致性提升 ------因为鸿蒙平台自带的 URL 是存在但残缺的。


二、判定过程:三步判断一个 RN 库要不要鸿蒙原生适配

判断一个库要不要做原生适配,我固定走三步:

步 做法 这个库的结果
① npm view <包名> harmony --json,看有没有 harmony.autolinking 没有
② 仓库里有没有 harmony/ 目录(以及 android/、ios/) 都没有
③ 代码里有没有 NativeModules / Platform.OS / requireNativeComponent ⚠️ 有,3 处

第 ① ② 步都指向"纯 JS 库",但第 ③ 步命中了。这时候不能直接下结论------第 ③ 步查到的是"信号",不是"判决"。要接着问一句:

它读的那些平台 API,鸿蒙侧有没有?

把三处平台引用摊开看:

文件 平台 API 用途 鸿蒙上是否可用
js/URL.js NativeModules.BlobModule 只为 URL.createObjectURL 拼 blob uri ✅ 存在(实测)
auto.js Platform.OS if (Platform.OS !== 'web') setupURLPolyfill() ✅ harmony
js/ios10Fix.js Platform.Version、Platform.OS 模块级副作用 :iOS 10 上补 ArrayBuffer.prototype.byteLength ✅ 不抛错

三个都用得上,三个鸿蒙侧都已经有。 所以结论是"不需要原生适配",而不是"它不碰平台"。

这个区分很重要:"纯 JS 库"不等于"零平台耦合"。 判据不是"有没有 platform 代码",而是"它依赖的平台能力鸿蒙侧是否具备"。前者会误判,后者才是真问题。

顺带一个细节:js/ios10Fix.js 是在 index.js 顶部被 import 的,也就是说只要 import 这个库,这段模块级代码就会执行 (读 Platform.Version 后判断 iOS 10)。它在鸿蒙上跑过、没抛错------这一点后来单独写成了断言。


三、这个交付包长什么样:与 npm 上游逐字节一致

既然不做原生适配,那"鸿蒙版"到底改了什么?答案是:实现文件一行没改。

核对方法:拿交付仓库和 react-native-url-polyfill@4.0.0 的 npm tarball(12,696 字节,11 个文件)逐文件比 SHA256。

文件 与 npm 上游
js/URL.js(20,008 字节,SHA256 758313FF...) 逐字节一致
js/URLSearchParams.js 逐字节一致
index.js / auto.js / index.d.ts / js/ios10Fix.js / LICENSE 内容一致 ,差异仅 CRLF vs LF
package.json 交付方改过(加了 files、把 repository 指向 AtomGit 等)
spec.json / 两个 README / 代码检查报告 / __tests__ / tsconfig.json 交付方新增

第一次比 SHA256 时,index.js、auto.js、LICENSE 这几个哈希不一样 ,看起来像被改过。但把两边的行做 diff,一行都不差。真正的原因在字节层:

文件 本地 CR 计数 npm 包 CR 计数 文件行数
index.js 13 0 13
js/ios10Fix.js 24 0 24
LICENSE 21 0 21

差值恰好等于行数 ------是 git checkout 在 Windows 上把 LF 转成了 CRLF,不是内容改动。js/URL.js 是单行文件(19,998 字符一行),没有换行可转,所以它的哈希天然一致。

教训 :跨平台比对文件时,先排除换行符再下"被改过"的结论。SHA256 不一致只是"字节不同",不等于"内容不同";用"去掉 CR 后逐字符比较"才能确证。这次差点把 CRLF 误判成交付方改了上游代码。

交付仓库本身也是干净的(git status 无输出),TAG 4.0.0-ohos-1.0.0 就是唯一那个 commit。

3.1 交付包的工程质量

做得好的:

  • spec.json 里 upstream 和 upstreamCommit 两样都记了 ,而且 upstreamCommit 与 npm 4.0.0 的 gitHead 完全对得上------可追溯性是完整的;
  • spec.json 明写 implementation: pure JavaScript; no native module or HAR required,结论和实测一致;
  • 契约测试真的 import 了库并调用了方法(不是断言字面量那种怎么跑都会过的测试);
  • README 主动声明了限制:"主机名不支持非 ASCII Unicode 规范化"------这条后来被实测复现了。

发现一处缺陷(如实记录,未改库代码):

交付包声明的 npm test 在纯净检出下会直接失败。

package.json 里写的是 "test": "node --test __tests__/*.test.mjs",而测试文件 → js/URL.js → import {NativeModules} from 'react-native'。包里没有 dependencies ,react-native 只出现在 peerDependencies。纯净检出没有 node_modules,Node 直接报:

复制代码
Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'react-native'
  imported from ...\js\URL.js
✖ __tests__\url.test.mjs
ℹ pass 0   ℹ fail 1

也就是说:这份契约测试只在"宿主工程内"才跑得通。 我在 Node 侧放了一个只导出 NativeModules / Platform 的 shim 之后测试才通过------说明失败原因是解析不到 react-native,不是测试本身写错了。

修复方向三选一:① devDependencies 里加 react-native;② 测试前注入一个 NativeModules 桩;③ 让 js/URL.js 对 NativeModules 的读取失败降级(try/catch),使 createObjectURL 以外的功能不依赖它。

另有可补之处:交付包没有自带 WPT 语料 ,而上游 4.0.0 是自带的 (js/__tests__/wpt/)。它声明的契约测试是 2 个测试、约 10 条断言;上游自己那套是 1580 条。覆盖率差了几个量级------这个库恰恰是最适合用标准语料验的一类。


四、接入宿主:零原生接线,外加四处要注意的地方

纯 JS 库的接法比带原生实现的库简单得多,但有四处值得记。

1. 依赖用 file: 装

json 复制代码
"react-native-url-polyfill": "file:../react-native-url-polyfill"

2. metro.config.js 的 watchFolders 必须加它的真实目录

file: 装进来是junction,不是真目录 ,Metro 只跟着 watchFolders 找源码。少了这一行,编译能过、但 bundle 里根本没有这个库:

js 复制代码
watchFolders: [
  // ...
  path.resolve(__dirname, '../react-native-url-polyfill'),
],

3. 不要 动 harmony/entry/oh-package.json5

纯 JS 库不需要 HAR。这次刻意没碰它,而且专门确认了自动链接的计数没有增加:

复制代码
info updated 4 file(s), linked 9 libraries, skipped 1 libraries

"linked 的计数不因纯 JS 库增加"是判断它真的不需要原生接线的信号。 如果计数涨了,说明要么库不是纯 JS,要么接线方式有问题。

另外,Metro 重定向清单(Redirected imports to N harmony-specific third-party package(s))里也不该出现纯 JS 库------那个清单是"鸿蒙变体重定向",纯 JS 库没有变体可重定向。

4. 本页额外加了一行 sourceExts

为了让 PC 端和设备端跑同一份测量代码 ,把测量模块写成了 .mjs。Metro 默认把 mjs 放在 additionalExts 而不是 sourceExts 里,所以显式加了一次:

js 复制代码
resolver: {
  sourceExts: ['js', 'jsx', 'json', 'ts', 'tsx', 'cjs', 'mjs'],
  // ...
}

这一行只跟本次的测量方式有关,业务接入不需要。


五、构建与运行

bash 复制代码
npm install
node_modules\.bin\react-native link-harmony        # linked 9 libraries, skipped 1 libraries
cd harmony && ohpm install --all && cd ..
npm run dev                                        # bundle
cd harmony && hvigorw --mode module -p product=default -p module=entry@default assembleHap --no-daemon
项 数值
首次 assembleHap 6 分 34 秒
二次重编(改了一条断言) 6 分 28 秒
HAP 变化 80,867,224 → 81,260,441 字节 (+393,217 ≈ 384 KB)
bundle 产物 bundle.harmony.js 6,248,387 字节
Metro 重定向 清单里没有这个库(纯 JS,符合预期)
原生注册日志 无 (它没有原生模块,不该有 TM created 这种日志)

384 KB 的构成要拆开说 :库本身只有约 21 KB;剩下约 360 KB 是我为了让验证可信而打进 bundle 的 WPT 官方语料 (urltestdata.json 228 KB + setters_tests.json 82 KB + 豁免清单与 PC 基线约 9 KB)。业务接入不会带这些。别把测试语料的体积算到这个库头上。

这里还有个对比值得留意:这个库的编译耗时和之前那些带原生实现的库是同一个量级(6 分多) 。也就是说这 6 分钟几乎全是 RNOH 工程本身的 ABI / CMake 开销,跟接进来的是纯 JS 库还是原生库基本无关。加一个纯 JS 库省下的是"原生接线与调试"的时间,不是编译时间。


六、验证设计:URL 一致性怎么验才可信

URL 解析是确定性输出------同样的输入必须得到同样的输出。这类库不能只验"调用没报错",要上已知值断言。这次的三层设计如下。

6.1 第一层:找到标准语料,而不是自己编用例

react-native-url-polyfill 的上游 4.0.0 仓库自带 WPT 官方语料 (js/__tests__/wpt/)。WPT(Web Platform Tests)是浏览器 URL 实现共同遵守的一致性测试集,属于最高一档的"标准文档向量"------任何人都能拿去核对。语料构成:

文件 内容 计入用例
urltestdata.json 1004 项(含字符串注释行),其中 891 项带输入:267 条期望失败 + 624 条期望成功 构造器用例 891 + origin 用例 411 = 1302
setters_tests.json 顶层 11 个键,其中 comment 键是 20 行前言文本(不是用例),其余 10 个键共 278 条 278
合计 1580

用多少条自造用例都换不来"这 1580 条是标准"的分量。

6.2 第二层:把"上游已声明的偏差"和"未预期偏差"分开

这一层才是关键。 上游仓库里有一份 exceptions.json------上游自己承认"这些 WPT 用例我不合规",共 42 条。

如果没有这份清单,我跑出"42 条失败"就只能写"有 42 条不符合标准",读者没法判断严重程度。有了它,结论可以精确到:

复制代码
上游 exceptions.json 声明 42 条已知偏差
  ├ 本次确实失败且已被上游声明:42
  ├ 未预期失败              :0
  └ 声明了但本次通过(过时)  :0

零未预期、零过时 ------意思是:这个实现的偏差恰好就是它自己声明的那些,不多不少。这比"通过率 97.3%"这种数字有力得多。

而且这个分类要求用例命名精确对齐 WPT 的测试名,所以我把测量代码按 WPT 的文件划分来组织:url-constructor 的字段(不含 origin)和 url-origin 的 origin 分成两个独立用例------否则一个因 href 失败的用例会"吃掉"它的 origin 失败,分类就错了。

6.3 第三层:独立 oracle ------ 但不能当基准

我用 Node 原生 WHATWG URL 跑了同一份语料。它是与这份 JS 完全不同的实现(V8 / Ada 原生),本意是"确认 WPT 的期望值本身可达成的"。

结果出了一个反转,值得单独讲。


七、PC 端与设备端跑同一份测量代码:跨引擎一致性

纯 JS 库在鸿蒙上最大的风险不是"跑不起来",而是"在 Hermes 上跑得跟别处不一样"。要证明这件事,光在设备上跑一遍不够------得有个对照。

做法是让 PC 和设备用同一个文件:

  • 测量模块 wptUrlCorpus.mjs 是纯 ESM、不依赖 React 也不依赖 RN;
  • PC :node wpt/pc-run.mjs → import 上游的 js/URL.js 跑语料(Node 需要能解析 react-native,故加了一个只导出 NativeModules / Platform 的 shim,库文件保持逐字节不变);
  • 设备 :测试页 import {runUrlWpt} from './wptUrlCorpus.mjs',用同一份语料跑同一个实现。

两边结果:

实现 环境 用例总数 通过 失败
被测实现 鸿蒙 / Hermes 1580 1538 42
同一份代码 PC / Node v24.14.0 V8 1580 1538 42
Node 原生 WHATWG URL PC / V8 1580 1563 17
鸿蒙平台自带 URL 鸿蒙 / Hermes 1580 234 1346

通过数、失败数、失败集合全都一致,差集为 0 ------而且这个断言是在设备上直接算的(把 PC 端基线里的失败清单打进 bundle,设备端跑完做集合差)。

"测量代码同源"比"测量结果相同"更重要。 如果 PC 和设备各写一套测量代码,那"结果一致"可能只是两套代码碰巧都对,无法归因到被测实现。为此值得付出让 Metro 支持 .mjs 的那一行配置。

耗时对照(同一份 1580 条语料):

引擎 耗时
PC / V8 33 ms
设备 / Hermes 133 ms(约 4 倍)

Hermes 比 V8 慢是预期内的(Hermes 优先启动速度与内存,不追求极致吞吐)。这里要说明的是:4 倍的差距没有带来任何行为差异------这才是鸿蒙侧真正要确认的事。

7.1 那个反转:不能拿原生实现当基准

Node 原生 URL 只过了 1563 / 1580 ,有 17 条不符合 WPT ;而这 17 条被测实现反而全部通过:

复制代码
只有被测实现失败、原生通过的:42 条(= 该实现相对原生实现的能力缺口)
只有原生失败、被测实现通过的:17 条
  Parsing: <http://a.b.c.xn--pokxncvks> without base
      不应抛错:Invalid URL
  Parsing: <http://10.0.0.xn--pokxncvks> without base
      不应抛错:Invalid URL
  Parsing: <http://a.b.c.XN--pokxncvks> without base
      不应抛错:Invalid URL
  ...(6 条输入,各产生 constructor + origin 两条)

语料对这 6 条输入要求解析成功 (期望 href: http://a.b.c.xn--pokxncvks/),而 Node 原生直接抛 Invalid URL。node:url.domainToUnicode('xn--pokxncvks') 返回的串里带不可见字符,说明这类标签涉及不可见码点的映射------两边对规范的理解在这一角落上不一致,而按这份 WPT 快照,是原生这边不合规。

结论:如果我把"Node 原生 URL"当成唯一基准去做逐字段比对,我会把 17 条"实现比原生更合规"误判成缺陷。

所以基准的顺序必须是:

  1. 标准语料是基准(WPT);
  2. 原生实现只是参考实现之一 ,它可以帮你发现差异,但不能替标准下判决。

这条经验对所有"跨平台有原生对应物"的库都成立------平台自带的实现不一定是对的,甚至不一定比第三方库更接近标准。


八、同机对照:鸿蒙自带 URL 与 polyfill 差多少

上一节说明了"要跟标准比"。但还有一类问题只有同一台设备上的并排对照 能回答:鸿蒙平台自带的 URL 到底行不行?

平台自带 URL 是存在的:

复制代码
鸿蒙自带 URL 是否存在 = true
鸿蒙自带 URLSearchParams 是否存在 = true

但用同一份语料一量:

实现 通过 / 总数 耗时
鸿蒙平台自带 URL 234 / 1580 24 ms
react-native-url-polyfill 1538 / 1580 133 ms

自带 URL 的首个失败样例就很说明问题:

复制代码
用例:Parsing: <http://example\t.\norg> against <http://example.org/foo/bar>
期望:http://example.org/
实际:http://example.org/foo/bar/http://example\t.\norg

它把 base 当字符串拼接 ,根本没有相对 URL 解析------注意实际结果里,base 和 input 被直接连在了一起。这类"存在但残缺"的实现,比"完全不存在"更危险:typeof URL === 'function' 会让调用方以为可以放心用。

这也正面回答了这个库在鸿蒙上的价值:它不是"补一个缺失的东西",而是"把一个 234 分的实现换成 1538 分的实现"。 在端上拼 URL、解析 query、处理相对路径、做签名拼接这些场景里,这个差别是实打实的。


九、实测发现与已知限制

9.1 平台耦合点实测

观测项 实测值
Platform.OS harmony
Platform.Version OpenHarmony-7.0.0.32(Beta2)
JS 引擎 typeof HermesInternal === 'object'
NativeModules.BlobModule 是否存在 true
BlobModule.getConstants() 的键 BLOB_URI_HOST, BLOB_URI_SCHEME
BLOB_URI_SCHEME / BLOB_URI_HOST blob / null
URL.createObjectURL({data:{blobId:'demo',offset:0,size:3},size:3}) blob:demo?offset=0&size=3
URL.revokeObjectURL('blob:x') undefined(空实现,与上游一致)
URL.canParse / URL.parse / URLSearchParams.prototype.size 都存在

NativeModules.BlobModule 在鸿蒙上存在 ,所以 createObjectURL 走的是正常分支。我另外在 PC 端用不提供 BlobModule 的 shim 验证了另一条分支:那时 createObjectURL 会直接抛 Cannot create URL for blob!。

9.2 已声明的限制被实测复现:中文域名不转 punycode

上游为压体积把 URL 实现换成了"去掉 Unicode 映射表"的版本,代价是主机名不做非 ASCII Unicode 规范化。实测:

表达式 这个库给出 Node 原生给出
new URL('https://百度.中国/').host 百度.中国 xn--wkd006a.xn--fiqs8s
new URL('https://例え.テスト/').host 例え.テスト xn--r8jz45g.xn--zckzah
new URL('https://Go.com/').host Go.com go.com

这 42 条 WPT 偏差全部属于这一类原因(Unicode 主机名的 IDNA / UTS46 映射)。

业务上的实际影响 :如果用中文域名做请求,一定要自己先转 punycode------否则送出去的就是原始 Unicode 主机名,DNS 层解析不了。反过来,路径、查询值、片段里的非 ASCII 字符是正常百分号编码 的,不受这条限制影响(E 组验过:中文查询值 鸿蒙 编码为 %E9%B8%BF%E8%92%99,读回不变)。

9.3 已知限制清单

  1. 主机名不做非 ASCII Unicode 规范化(上游已声明,实测复现)------这是本库相对原生实现唯一的 42 条能力缺口,也是它换取体积的方式。
  2. createObjectURL 端到端未验证 :只确认了它返回 blob:demo?offset=0&size=3 这样的 uri,没有真的把 blob uri 喂给 fetch / Image 验证能取到内容。
  3. 只在一台模拟器上验证 (Pura X View,ohos-x64),没有真机。
  4. js/ios10Fix.js 的 iOS 10 分支永远不执行:鸿蒙上只验证了"这段模块级代码不抛错",无法验证它的功能正确性。
  5. WPT 语料用的是上游仓库的快照 (urltestdata.json + setters_tests.json),上游还有 urlencoded-parser / idlharness 等测试文件未纳入;hermes.json 里上游也排除了一项(FormData 相关,与本库无关)。
  6. 未做真实的业务吞吐对比:只测了语料跑完耗时(Hermes 133 ms vs V8 33 ms)。
  7. 交付包缺陷 :npm test 在纯净检出下失败(解析不到 react-native),见 3.1 节。与设备运行无关,未改库代码。

未发现实现层面的缺陷。 42 条偏差不是缺陷,是上游公开声明并写进 README 的取舍。


十、常见问题

Q1:这个库需要 HAR、权限或 ohpm 接线吗?

都不需要。它没有原生模块,harmony/entry/oh-package.json5 不用动,module.json5 也不用加权限。判断信号是:link-harmony 的 linked 计数不因它增加 (本次输出 linked 9 libraries, skipped 1 libraries)。

Q2:react-native-url-polyfill 和 react-native-url-polyfill/auto 有什么区别?

  • auto 入口 :import 'react-native-url-polyfill/auto' → 在 Platform.OS !== 'web' 时自动调用 setupURLPolyfill() ,把实现装到全局 globalThis.URL / URLSearchParams。适合"想让全项目透明用上标准 URL"。
  • 库入口 :import {URL} from 'react-native-url-polyfill' → 只导出实现,不动全局(ponyfill 用法)。适合"只想在局部用,不想改变全局行为"。

两种可以共存;setupURLPolyfill() 也可以手动调用。

Q3:装了之后怎么确认装上了?

调用 setupURLPolyfill() 会留一个版本标记:

js 复制代码
import {setupURLPolyfill} from 'react-native-url-polyfill';
setupURLPolyfill();
console.log(globalThis.REACT_NATIVE_URL_POLYFILL);   // react-native-url-polyfill@4.0.0

Q4:平台自带的 URL 不是已经能用了?

能用,但只过 234 / 1580 条标准用例。最典型的问题是不支持相对 URL 解析:

js 复制代码
new URL('/search?q=1', 'https://example.com/base')
// 平台自带:把 base 当字符串拼在后面 → https://example.com/base/search?q=1 ✗
// 这个库  :https://example.com/search?q=1                         ✓

Q5:中文域名为什么没有换成 punycode?

上游为压体积去掉了 Unicode 映射表,这是它公开声明的限制。需要中文域名时,请求前自己转一次:

js 复制代码
// 先转 punycode 再交给 URL
const host = punycode.toASCII('百度.中国');   // xn--wkd006a.xn--fiqs8s

路径、查询值、片段里的中文不受影响,会正常做百分号编码。

Q6:既然有 42 条不符合 WPT,能不能算"适配不通过"?

不算。这 42 条正好等于上游 exceptions.json 自己声明的 42 条,零未预期、零过时------也就是说这个实现的偏差范围是被作者完整掌握并公开的,而且同类原因(Unicode 主机名)在 README 里也写了。

真正需要警惕的是"未预期偏差":如果跑出 43 条,那一条才是要查的。

Q7:URL.createObjectURL 在鸿蒙上能用吗?

它依赖 NativeModules.BlobModule。实测鸿蒙上 BlobModule 存在 (BLOB_URI_SCHEME = blob),所以能返回 blob: 开头的 uri。但我没有做端到端验证(没真的用这个 uri 去取 Blob 内容),涉及 Blob 下载的场景建议自己补一轮。

Q8:这个库会跟别的库抢全局 URL 吗?

用 auto 入口或手动 setupURLPolyfill() 时,它会覆盖全局 URL / URLSearchParams。如果项目里还有别的库也改全局 URL,就有顺序问题------这时建议改用库入口(ponyfill),只在需要的地方 import。

Q9:怎么自己把这一轮验证跑一遍?

bash 复制代码
# PC 端复算(同一份测量代码)
node wpt/pc-run.mjs

# 设备端
hdc shell aa force-stop com.rnoh084.demo
hdc shell aa start -b com.rnoh084.demo -a EntryAbility --ps rnAppKey UrlPolyfillTestApp
# 界面上点「跑全部」
hdc shell "hilog -x | grep urlpolyfill-test" | Select-String '汇总|✗'

小结

react-native-url-polyfill 是个不需要原生适配的库:没有 harmony/ 目录,实现文件与 npm 上游逐字节一致 ,接进宿主只需要改 package.json、metro.config.js、index.js 三处,自动链接的计数都不会增加。

但这次真正花时间的不是"接进来",而是"证明它是对的"。几点体会:

  1. "不需要适配"要证明,而且证明的落点是"对不对",不是"能不能跑"。 代码量小、接口简单,都不等于验证简单。

  2. 找标准语料,别自己编用例。 WPT 那 1580 条是浏览器共同遵守的一致性测试集,用它是把"我觉得对"换成"标准认为对"。而且上游自己带了这份语料,先翻仓库再动手写测试。

  3. "上游自己声明的偏差"是一份礼物。 有了 exceptions.json,42 条失败才能被精确切成"已知 42 / 未预期 0";没有它,这个数字既没法解释也不可信。遇到带豁免清单的交付包或上游,一定要拿来用。

  4. 不能拿原生实现当基准。 Node 原生 URL 有 17 条不符合 WPT,反倒被测实现全过。用原生做 oracle 会把"更合规"误判成"有缺陷"。基准只能是标准;原生只是参考实现之一。

  5. 测量代码同源,比测量结果相同更重要。 PC 与设备共用同一个 .mjs,"结果一致"才能归因到被测实现,而不是"两套测量代码碰巧都对"。

  6. "存在但残缺"比"不存在"更危险。 鸿蒙自带 URL 是存在的、typeof 是 function------只断言"存在"就通过了,实际只过 234/1580。同机对照能一刀切开这种假象,而这台设备上唯一能跟它对量的,就是同一份标准语料。

关于交付包:它的可追溯性做得不错 (upstream 与 upstreamCommit 都在,且与 npm 的 gitHead 对得上),契约测试也是真的在调用库 。不足有两点:npm test 在纯净检出下会失败 (解析不到 react-native),以及没有把上游自带的 WPT 语料收进来------对这类"有标准可依"的库,这是最值得补的一块。


本篇用到的库

项 内容
三方库 react-native-volume-control(上游 1.0.1 的鸿蒙适配版)
适配仓库 https://atomgit.com/oh-react-native/react-native-volume-control
适配 TAG 1.0.1-ohos-1.0.0
ohpm 包名 @react-native-ohos/react-native-volume-control
HAR harmony/volume_control.har(3,756 字节)
原生模块名 VolumeControl(ArkTS TurboModule,日志标签 #RNOH_ARK)
是否需要权限 不需要(媒体音量读写不要求声明权限)
上游仓库 https://github.com/rtmalone/react-native-volume-control(基线 commit 2915b27068fe67c7a835da2f136fa58d9b7c6cae;npm 元数据声明 ISC,随包 LICENSE 为 MIT)
宿主工程 RNOH084Demo(测试页 rnAppKey = VolumeControlTestApp)

接入方式(纯 JS,零原生接线):

json 复制代码
// package.json
"react-native-url-polyfill": "file:../react-native-url-polyfill"
js 复制代码
// metro.config.js ------ file: 装进来是 junction,必须让 Metro 找得到源码
watchFolders: [
  path.resolve(__dirname, '../react-native-url-polyfill'),
],
ts 复制代码
// 用法一:ponyfill,不动全局
import {URL, URLSearchParams} from 'react-native-url-polyfill';

// 用法二:装到全局(auto 入口)
import 'react-native-url-polyfill/auto';

// 用法三:手动装到全局
import {setupURLPolyfill} from 'react-native-url-polyfill';
setupURLPolyfill();
console.log(globalThis.REACT_NATIVE_URL_POLYFILL);   // react-native-url-polyfill@4.0.0

// 典型用法:相对 URL + 中文查询值
const u = new URL('/search?q=鸿蒙', 'https://example.com/base');
u.toString();               // https://example.com/search?q=%E9%B8%BF%E8%92%99
u.origin;                   // https://example.com
u.searchParams.get('q');    // 鸿蒙
u.searchParams.append('page', '2');

// 安全解析用户输入
URL.canParse('https://example.com');   // true
URL.canParse('not a URL');             // false
bash 复制代码
# 换页启动测试页(force-stop 不能省,换页参数只在冷启动生效)
hdc shell aa force-stop com.rnoh084.demo
hdc shell aa start -b com.rnoh084.demo -a EntryAbility --ps rnAppKey UrlPolyfillTestApp

验证环境

项 版本
React Native 0.84.1
React 19.2.3
RNOH(npm / ohpm) @react-native-oh/react-native-harmony / @rnoh/react-native-openharmony 0.84.3
Node.js v24.14.0(PC 端复算用)
DevEco Studio 26.0.0.621
HarmonyOS SDK API 26(26.0.0.32)
设备 HarmonyOS 7.0.0(26.0.0) Beta2 模拟器 Pura X View(ohos-x64),Platform.Version 报 OpenHarmony-7.0.0.32(Beta2)
JS 引擎 Hermes
宿主 HAP 产物 entry-default-signed.hap(81.26 MB)
本次增量构建 assembleHap 6 分 34 秒,HAP +393,217 字节(≈384 KB,其中约 360 KB 是测试语料)
验证规模 设备侧 35 / 35 断言全部通过 ;WPT 官方语料 1580 条:通过 1538,失败 42(全部为上游声明项) ;与 PC 端失败集合差集为 0

欢迎加入 CPF-RN 鸿蒙社区:https://atomgit.com/CPF-RN

React Native for OpenHarmony 组织:https://atomgit.com/oh-react-native

RN 三方库鸿蒙适配清单:https://atomgit.com/oh-react-native/rn-ohos-adaptation-overview

相关推荐
不可能片场1 小时前
内容运营自动化 用相似度拦住撞车选题
前端·electron
米多科技1 小时前
让 AI 走进我的 3D 世界:一个 MCP server 的完整实现
javascript
asong2 小时前
从写代码到部署上线,Cloudflare 给 AI 配了一把新钥匙
前端·javascript·后端
lerhxx2 小时前
从 Markdown 到生成式 UI:AI 应用中的流式渲染实践
前端·javascript
HLAIA光子2 小时前
RAG Chunks 切分优化后成本骤降 86%
后端·性能优化·架构
传奇开心果编程2 小时前
【现代声明式UI学与练】第9课 性能优化——渲染优化、列表优化、内存优化、启动优化
学习·flutter·react native·ui·性能优化·swiftui·android jetpack
可乐鸡翅yeah_3 小时前
新手梳理:HLS 线上问题,哪些该提给 CDN,哪些该找后端切片服务
开发语言·前端·javascript·vue.js·网络协议·http·m3u8在线
এ慕ོ冬℘゜3 小时前
es6基础
前端·javascript·es6
熊猫钓鱼>_>4 小时前
从2D平铺到3D沉浸:我用HarmonyOS 7端侧AI做了一个全程数据不出设备的空间化私密相册
前端·人工智能·3d·华为·华为云·harmonyos·鸿蒙