做移动端开发这些年,Flutter 生态里的链上交互方案用过不少,但鸿蒙系统一出来,几乎所有第三方库都要过一遍“能不能用”的关卡。on_chain 算是我在 Flutter 侧做链上交互用得比较顺手的一个三方库,交易构建、私钥签名、多链资产查询都有现成的封装,原本在 Android 和 iOS 上跑得挺稳。一到鸿蒙,问题就来了:它底层依赖的平台通道,服务的还是 Android 和 iOS 的接口,换到鸿蒙的 ArkTS 环境里,Native 侧全要重来。这篇文章就把我摸索出来的 on_chain 鸿蒙化适配思路和实操细节掰开揉碎讲清楚,覆盖链上交互的完整链路、私钥签名的高性能实现,以及多链资产治理的统一建模,给正好在把 Flutter 链上库往鸿蒙上搬的同学提供一个可以直接参考的路线。
1. 先拆透 on_chain 在链上到底干了哪些活
1.1 标题关键词和真实开发任务的对应关系
先说结论:标题里那串词并不是营销话术,每一个都对应着明确的开发任务。“顶级区块链链上交互”落到代码层面,指的是交易构建、RPC 调用、事件监听、gas 估算这些链路;“高性能私钥签名”说的是私钥的存储隔离、签名算法的调用效率、批量签名时的吞吐量;“极致多链资产治理”则是把不同链系的地址格式、交易结构、资产查询协议统一成一套抽象接口,让上层业务不用关心底层链的差异。
我们团队当时拿到 on_chain 这个库,第一反应是“鸿蒙跑不起来就换方案”,但评估下来发现,这个库在 Dart 侧已经把绝大多数链上逻辑都封装好了。所谓“不可篡改的数字化底座”,本质上就是链上交易的数据可信性与可验证性——每笔交易签名后上链,任何人无法篡改,应用层拿到的是经过密码学验证的状态。这种能力对于钱包类应用、溯源应用、存证类业务都很有价值,而鸿蒙生态里原生可用的链上开发框架还很少,把 Flutter 生态里成熟的三方库移植过去,投入产出比远高于重新做一套。
换句话说,on_chain 的鸿蒙化不是重写,而是“搬家”:把原本依赖 Android/iOS 原生能力的部分,换成鸿蒙的 ArkTS 与 Native 能力;把 Dart 侧已经写好的交易协议、地址推导、签名编排逻辑原样保留。这里的关键在于,Flutter 框架本身就是跨端的,Dart 代码不依赖操作系统 API,所以真正需要处理的,是平台通道那一层。
1.2 鸿蒙化适配的真正边界在哪里
一开始容易犯的错误是把“鸿蒙化”理解成“在鸿蒙上重新实现一遍所有功能”。实际上,鸿蒙适配可以划分为三个层次,我们得先分清哪些层要动、哪些层不能动:
第一层是 Dart 侧的业务逻辑与协议实现,包括交易序列化、网络通信接口的抽象、多链地址推导、签名数据的组织。这一层理论上和操作系统无关,on_chain 中绝大部分代码都在这里,不需要修改。
第二层是 Flutter Engine 与鸿蒙系统的桥接层,也就是 Platform Channel。Flutter 官方对鸿蒙的支持已经逐步完善,但三方库自己注册的 MethodChannel 需要重新对接鸿蒙侧的 MethodChannel 实现。
第三层是鸿蒙原生能力,包括安全存储、密码学算法、生物识别、网络请求。on_chain 在 Android 上可能调用 Android Keystore、java.security 里的签名算法,在鸿蒙上需要换成系统的通用密钥库组件与加密算法框架。
明确了边界之后,工作量就清晰了:平台层的接口数量通常不超过二十个,真正难啃的只有密签和安全存储两个模块。把开源库的对接层改成可插拔设计,鸿蒙化就变成了“插上鸿蒙适配器”的动作,而不是另起炉灶。
2. 适配策略选型:为什么最终选了“换底座”而不是“全重写”
2.1 三条路线摆在面前,怎么选
当时团队评估了三条路线。第一条是在原生代码里通过 WebView 加载链上交互的网页版方案,用 JS SDK 跟链通信。这个方案看起来省事,但性能和体验都跟不上,签名私钥落在 WebView 里更是安全灾难,直接放弃。
第二条是用鸿蒙原生语言从零实现一套链上交互库,把交易构建、私钥管理、多链协议全部重写。这个路线最“鸿蒙”,但工程量巨大,而且多链支持意味着每条链的协议细节都要重新实现,团队半年做不完,维护成本也高。
第三条就是最终选定的“平台适配层替换”方案:保留 on_chain 的 Dart 侧业务逻辑,把平台通道的 Android/iOS 实现替换为鸿蒙实现。为什么选它?因为 Flutter 的架构天然支持这种替换。Dart 侧调用平台通道时,传的通道名称、方法名、参数结构都是约定好的,鸿蒙侧只要实现同一份约定,就能无缝对接。这样既不用重写链上协议,又能在原生侧使用鸿蒙的密钥库和加密框架,兼顾兼容性与安全性。
选型时还有一个隐藏的考量点:后续鸿蒙如果升级系统接口,只需要改鸿蒙侧的适配层,Dart 侧的 on_chain 版本升级不会影响适配效果。反过来,on_chain 上游更新了新链支持,我们也不需要动鸿蒙代码。这种“双向解耦”的维护模型,对长期跟进开源库很有价值。
2.2 平台层接口清单:鸿蒙侧要把哪些能力补齐
经过梳理,on_chain 在运行时会调用如下几类原生能力,这也是鸿蒙适配层需要逐一实现的接口清单:
| 能力类型 | 典型用途 | Android 原有实现 | 鸿蒙替代方案 |
|---|---|---|---|
| 安全存储 | 保存私钥、助记词密文 | Android Keystore、EncryptedSharedPreferences | 通用密钥库组件、安全存储服务 |
| 熵源 | 生成助记词、随机 nonce | SecureRandom | 安全随机数生成接口 |
| 摘要算法 | 计算交易哈希、消息哈希 | MessageDigest | 加密算法框架的摘要接口 |
| 签名算法 | ECDSA、EdDSA 签名 | java.security.Signature | 加密算法框架的签名接口 |
| 生物识别 | 签名前用户授权 | BiometricPrompt | 系统生物识别认证弹窗 |
| 网络请求 | RPC 调用、节点通信 | OkHttp | 网络能力或自研 HTTP 工具 |
| 事件监听 | 新区块、交易状态回调 | BroadcastReceiver 或 WebSocket | 系统消息机制或 WebSocket 封装 |
这张表基本就是鸿蒙适配的“施工图”。我建议拿到任何 Flutter 三方库做鸿蒙化时,都先做一遍这样的能力盘点,而不是上来就写代码。盘点清楚了,工作量估算、排期、风险点全都能提前暴露。
2.3 Dart 侧的 80% 代码为什么可以原样保留
很多人会怀疑:Dart 侧代码真的一点不用改吗?其实不完全,但不是因为逻辑要重写,而是因为 on_chain 在 Dart 侧已经做了很好的依赖抽象。它通过接口定义了对平台能力的需求,比如KeyStoreProvider、Signer、HttpClientProvider,具体实现是在初始化时注入进来的。
在 Android/iOS 上,注入的是各自平台的实现;在鸿蒙上,注入的是我们新写的鸿蒙实现。这意味着 Dart 侧的交易构建流程、地址推导算法、多链协议解析,从头到尾就没有依赖过具体平台,自然不需要动。
但有一个点必须提醒:Dart 侧某些代码可能用了dart:io里的HttpClient、Platform等类,这些类在鸿蒙的 Flutter 引擎上如果支持不完整,需要在初始化阶段就替换成自定义的 HTTP 实现。on_chain 的早期版本里,网络层是直接 new 一个HttpClient,后来官方把网络层也抽象成了可注入接口,适配鸿蒙时才没有卡住。如果你要适配的 Flutter 库没做这层抽象,就需要在 Dart 侧打一个补丁,把硬编码的平台依赖替换成注入式调用,这也是鸿蒙化适配里最常见的“隐性工作量”。
3. 签名链路适配:私钥安全与高性能签名的实现细节
3.1 密码学底座从哪来
签名是整个适配里最敏感的环节,因为私钥一旦泄露,整个应用的可信度就清零。鸿蒙系统本身提供了完整的密码学能力,包括通用密钥库组件和加密算法框架,它们的关系有点像 Android 里 Keystore 和加密库的分工。
通用密钥库负责密钥的生成、存储和使用授权,私钥一旦写入,应用层无法直接读取明文,只能通过授权会话调用签名或解密操作。这跟 on_chain 原本在 Android 上的行为模式是一致的,所以适配的关键不是重新设计密钥管理,而是把 on_chain 对 Android Keystore 的调用,逐条映射到鸿蒙密钥库的对应接口上。
映射过程中要注意一个差异:Android 的 KeyStore 对密钥别名的管理比较随性,鸿蒙则要求更严格的访问控制级别设置。创建密钥时,要明确指定该密钥是否支持生物识别解锁、是否允许在设备锁屏后使用。on_chain 原本没有暴露这些参数,鸿蒙化时我在适配层加了一个初始化配置项,让宿主应用可以决定私钥的解锁策略。这种“补丁级改动”比改 Dart 侧源码要稳妥得多。
3.2 私钥签名完整链路
把私钥签名从触发到完成拆开看,整个链路由五个节点组成:获取签名授权、加载私钥句柄、构造待签名数据、执行签名运算、返回签名结果并做格式封装。
在鸿蒙侧,第一步是调用系统安全组件申请解锁。如果应用设置了生物识别解锁,这里会弹起系统的指纹或人脸验证界面,验证通过后拿到一个临时授权令牌。第二步是用这个令牌在密钥库中打开指定别名的密钥会话,注意此时拿到的不是私钥本身,而是一个不透明的句柄,签名操作都通过这个句柄完成,这个过程就是“计算在安全环境内,私钥永不出库”的核心设计。
第三步比较容易被忽略:on_chain 传入的待签名数据往往是交易摘要或消息原文,而鸿蒙的签名接口通常要求输入原始消息或摘要,并指定签名算法的哈希方式。这里必须严格对齐 on_chain 对每条链定义的签名输入格式。以常见的 ECDSA 签名为例,有的链要求对交易哈希的原始字节签名,有的链则要求对哈希再做一次双哈希后才签。适配前我专门写了一个测试矩阵,把 on_chain 在 Android 上的签名结果和鸿蒙侧的实现跑对比,确保同一私钥、同一消息在两边产生完全一致的输出。这一步极其重要,如果签名结果不一致,上链就会被节点直接拒绝,而且很难排查。
第四步执行签名运算,第五步将签名结果按各链要求的编码格式封装。比特币系的脚本签名和 EVM 系的 RLP 编码签名格式完全不同,但这些逻辑 on_chain 的 Dart 侧已经处理好了,鸿蒙侧只需要把原始的 RS 值返回给 Dart,不要做任何额外的格式加工。
3.3 摘要计算的字节序陷阱
这里展开讲一个我踩了好久的坑。链上交易的摘要计算,本质上是把交易数据做两次 SHA-256 或 Keccak-256 哈希。Dart 侧算一遍、鸿蒙侧算一遍,看起来应该一样,实际上经常因为字节序处理不同而得出完全不同的结果。
有一个典型场景:交易数据在 RLP 编码后是一串字节流,计算摘要时要严格按字节流输入。可 Flutter 的Uint8List和鸿蒙侧接收到的ArrayBuffer,相互转换时如果直接按 16 进制字符串传递,就会出现大端小端不一致的问题。我在适配层里统一规定:所有二进制数据一律以Uint8List的原始字节数组跨通道传输,禁止转成 hex 字符串再传递。这个约定看起来简单,但能避免 90% 的数据不一致问题。
此外,区块高度、nonce 这类整数在 RLP 编码里有专门规则,小于 128 的整数和大于 128 的整数编码长度不同。on_chain 的 Dart 侧已经实现了这套规则,鸿蒙侧不需要重复实现,但签名时传回的 R、S 值必须是无符号大整数格式,不能带上符号位。如果签名输出的 S 值超过 128 位且高位为 1,有些链会认为签名无效,需要做低 S 值规范化处理。这一点我推荐在 Dart 侧统一处理,因为各链的规范化规则不完全一致,放在 Dart 层更容易维护。
3.4 生物识别触发签名怎么接
on_chain 在移动端有一个常见使用场景:用户发起转账,应用弹出生物识别验证,验证通过后自动用私钥签名并广播交易。在 Android 上,这个流程依赖系统生物识别提示框;鸿蒙上也有对应的系统级认证组件,但调用方式和回调模型不同。
鸿蒙的生物识别认证接口返回的是一个 promise 或回调,在认证成功后会给出一个解锁凭据,把这个凭据传给密钥库接口,才能在受控状态下使用受生物识别保护的密钥。适配时需要注意时序问题:不要在页面销毁或应用退到后台时执行签名,否则凭据会失效。最好在认证弹窗弹出前就把待签名数据准备好,认证成功的回调里只做签名和广播,不要做耗时操作。
另外,有些用户会在系统设置里关闭生物识别,只使用锁屏密码。适配层要处理这种情况:检测到设备没有录入生物信息时,自动降级为锁屏密码验证,或者直接提示用户输入应用级 PIN 码。on_chain 本身不管理应用级 PIN,这个能力通常由宿主的业务层实现,我们的适配层只需要提供一个“认证方式选择”的回调接口,让宿主决定走哪条验证路径。
4. 多链资产治理的鸿蒙化建模
4.1 多链抽象层的设计思路
多链资产治理是 on_chain 最吸引人的特性,也是鸿蒙化过程中最容易做“表面功夫”的部分。所谓多链,指的是同一套私钥或助记词可以管理不同链系上的资产,比如 UTXO 系链和 EVM 系链在地址生成规则、交易结构、签名算法上差异很大,但如果抽象得当,上层业务可以用一套统一的“钱包账户”概念来操作所有链。
on_chain 在 Dart 侧已经建立了一套链描述符(ChainDescriptor)体系,每条链有独立的地址编码器、交易构建器和签名适配器。鸿蒙化适配时,不要试图在 ArkTS 侧重新实现这些链差异,鸿蒙侧只需要做到两件事:一是提供统一的密钥派生接口,从助记词或主私钥推导出各链的地址;二是提供统一的签名回调,让 Dart 侧按链类型装配好待签名数据后,交给原生侧执行密码学运算。
这样设计的好处是:新增一条链的支持时,Dart 侧扩展链描述符,鸿蒙侧完全不用改。我们做适配的时候,比特币系、EVM 系、以及其他几条主流公链的代码路径都走同一套平台通道,只是传入的方法参数里带有链标识,鸿蒙侧根据标识选择对应的算法标识和密钥派生路径。
4.2 链上交互与交易广播
链上交互除了本地签名,还需要跟节点通信。on_chain 的网络层封装了 JSON-RPC 调用、区块监听、交易广播等能力。鸿蒙侧需要提供一个可用的 HTTP 客户端,以及 WebSocket 长连支持,用来监听新区块和交易确认事件。
这里有一个体验层面的问题:鸿蒙应用如果直接使用系统网络能力,线程模型跟 Flutter 的事件循环不太一样,容易出现网络回调丢失的情况。我在适配层里做了一层缓冲:原生侧发出的网络请求,回调时统一投递到 Flutter 侧的事件队列,由 Dart 侧再分发到 on_chain 的事件处理器。简单说就是“原生只负责发请求和收响应,业务逻辑全在 Dart 侧跑”。
交易广播时最容易遇到“已广播但未被确认”的状态。on_chain 会返回一个交易哈希,但链上可能因为 gas 设置过低或者 mempool 拥堵导致交易迟迟不进块。适配层不需要处理这类业务状态,但要在网络接口的异常类型里保留原始错误码,方便 Dart 侧判断是节点连接失败、nonce 冲突、还是余额不足。鸿蒙侧的网络错误类型跟 Android 不一样,异常码的映射也要在适配层做一张对照表。
4.3 资产查询的批量优化
多链资产治理的场景里,最影响体验的是批量查询。用户打开钱包首页,往往同时要显示多个链上的余额和资产列表。如果每条链逐个发起 RPC 请求,体验会很差,尤其在国内网络环境下,节点延迟不稳定,容易造成界面长时间白屏。
优化思路是并发聚合:Dart 侧把同一时间窗口内的多个链查询请求合并,通过平台通道一次性下发到鸿蒙侧,鸿蒙侧用并发请求池同时发起多个节点的 RPC 调用,全部返回后再统一回传。这个优化在适配层实现,不需要改动 on_chain 核心代码。
还有一类资产是链上代币余额,通常需要调用合约的balanceOf方法。EVM 系链可以批量调用多合约地址,但 UTXO 系链没有合约概念,只能扫描地址上的交易记录。on_chain 对这两类链采用了不同的资产扫描策略,适配层要保证网络层能同时支持 JSON-RPC 和索引器查询。我在鸿蒙适配层里为索引器请求单独开了缓存通道,避免每次打开钱包都拉全量交易历史,实测下来首页加载速度能快一倍以上。
5. 实操记录:把 on_chain 跑在鸿蒙上的完整过程
5.1 工程准备与插件层搭建
手把手过一遍实操。前提是你手上已经有一个能运行鸿蒙应用的 Flutter 工程,并且 DevEco Studio 和 Flutter 鸿蒙 SDK 的环境变量都配好了。
第一步,在 Flutter 工程里用命令行创建一个鸿蒙插件目录,专门放置鸿蒙侧的源码。目录结构不用太纠结,只要保证插件能被主工程识别即可,重点在于pubspec.yaml里要声明该插件支持鸿蒙平台。这里贴一个核心配置片段,注意hooks和platforms里的声明,少了任何一个,鸿蒙侧的动态库都不会被打进应用:
flutter: plugin: platforms: android: package: com.example.onchain_android pluginClass: OnchainPlugin ios: pluginClass: OnchainPlugin ohos: package: com.example.onchain_ohos pluginClass: OnchainPluginOhos hooks: - name: ohos_plugin_hook第二步,在鸿蒙侧的模块的Index.ets文件里注册插件类,将 Dart 侧发来的 MethodChannel 请求分发到对应的能力实现模块。这里我建议把能力拆成几个独立的 Service:SecurityService管密钥和安全存储,CryptoService管摘要和签名,NetworkService管 RPC 和 WebSocket。不要把所有逻辑堆在一个类里,后续排查问题会很痛苦。
第三步,配置鸿蒙工程的签名和权限。链上交互需要网络权限,安全存储需要申请相应的数据访问权限。在module.json5里加上必要的权限声明,同时注意设置native库的 so 架构。实测中经常遇到真机能跑通、模拟器上签名算法库加载失败的情况,就是因为 abiFilters 没有把对应的架构加进去。
5.2 平台通道的数据转换规范
平台通道是 Dart 和鸿蒙侧通信的桥梁,但它的类型映射是有限的几个基础类型。on_chain 里大量使用Uint8List(二进制字节)和BigInt(大整数),这两种类型在通道里不能直接映射,要么转成 List 要么转成 String。
我在适配层订了三条铁律:第一,二进制数据一律用Uint8List转换成List<int>传递,不经手字符串编解码;第二,大整数统一转成十进制字符串传递,避免 JavaScriptCore 侧精度丢失;第三,回调结果统一封装成 Map,带success和error两个字段,Dart 侧只用一种模式解析返回。
这里给一个 Dart 侧调用鸿蒙签名的示例,方便直观理解协议格式:
final result = await _channel.invokeMethod('signTransaction', { 'chainId': 'ethereum', 'keyAlias': 'wallet_main_key', 'txHash': txHashBytes, 'algorithm': 'ecdsa_secp256k1', 'unlockToken': unlockToken, }); final signature = result['signature'] as List<int>;鸿蒙侧拿到txHash时,要注意它已经被 Flutter 引擎转成了ArrayBuffer,转换成字节数组后,下一步就是调用加密算法框架。整个链路里最容易出错的地方是对keyAlias的处理,鸿蒙侧必须确保这个别名跟密钥库创建时一致,否则签名会报“密钥不存在”或“会话无效”的错误。
5.3 测试与验收的关键动作
鸿蒙适配不能只做功能验证,还要做一致性和安全性验证。我强烈建议搭一套自动化对比测试:同一组助记词在 Android 真机和鸿蒙真机上推导出地址,结果必须一致;同一笔交易数据在两边的签名结果必须一致。这个测试对上链至关重要,因为链上节点只认密码学结果,不认平台差异。
实操层面的测试动作有几个关键点。第一,要覆盖确定性推导路径的向量测试,助记词到私钥、私钥到公钥、公钥到地址,每一条链都要有已知的测试向量来核对。第二,签名时人为制造错误场景,比如使用错误的 keyAlias、过期的解锁凭据、非法的待签数据,验证鸿蒙侧是否返回了可读的错误信息,而不是直接崩溃。第三,做批量交易压测,连续签名 100 次,观察是否有句柄泄漏或内存暴涨。鸿蒙的可回收对象和 Flutter 的内存模型有差异,签名句柄如果没释放,长时间跑会导致安全组件报错。
6. 性能调优和几个必须注意的安全细节
6.1 签名与初始化性能怎么拉上去
高性能私钥签名这个需求,在鸿蒙化之后最直接的瓶颈往往不在算法本身,而在跨通道的调用开销和密钥会话的建立次数。一次签名要经历 Dart 到鸿蒙的通道传输、密钥库会话建立、密码学运算、结果回传,链路比 Android 上直接调用要长,所以优化要从减少往返次数和复用会话两个方向下手。
第一个优化点是把多次签名请求合并成批处理。on_chain 在离线批量签名场景下,比如批量生成交易和签名上百笔空投交易时,Dart 侧可以先把所有待签数据打包成一个列表,通过一次平台通道调用下发,鸿蒙侧循环执行签名,最后一次性返回结果数组。实测下来,单笔签名耗时大约 120 毫秒,100 笔签名如果逐笔通道调用要 12 秒以上,合并后只需要 2.3 秒,性能提升明显。
第二个优化点是密钥库会话的复用。某些链的密钥库接口在每次签名时都会强制新建会话,如果授权令牌还在有效期内,可以直接复用之前的会话句柄,能省掉一大半的开销。
安全方面有一个底线:性能优化不能突破“私钥不出安全环境”这条红线。不要在鸿蒙侧把私钥读出来缓存到内存池,也不要为了并发性能把密钥句柄复制到多个线程。所有签名运算必须在同一个安全上下文里执行,否则密钥保护就形同虚设。
6.2 安全加固的雷区和原则
做链上应用和普通 App 不一样,攻击者盯的是私钥,所以适配层必须带着攻击者视角来审查。有几个雷区我在代码评审时反复强调。
第一个雷区是日志泄漏。调试阶段为了排查问题,可能会在 ArkTS 侧把待签名数据、地址、nonce 打印到日志里。这些信息虽然不直接泄露私钥,但会为攻击者提供交易关联分析的数据。上线前必须把所有 debug 日志全部关掉,生产包禁止保留任何密码学调用路径的日志输出。
第二个雷区是随机数质量。生成助记词、nonce、盐值时,必须使用鸿蒙系统的安全随机数生成接口,不能使用Math.random()或普通随机数生成器。签名算法的安全性强依赖随机 nonce 的不可预测性,如果随机数可预测,私钥可以从两个签名中反推出来。任何 Flutter 库的鸿蒙化适配,只要涉及密钥生成,都要把随机数来源审查一遍。
第三个雷区是密钥备份与恢复。on_chain 支持助记词备份机制,但有些开发者会为了方便,把私钥密文或助记词直接写入应用私有目录。在鸿蒙上,私有目录不一定做了硬件级加密,建议至少要放到系统提供的安全存储区域,或者使用应用级加密方案再落盘。一旦涉及跨设备迁移,密钥迁移协议也要走标准流程,不要自定义一套明文导出接口。
7. 常见问题速查与踩坑总结
把这段适配过程中遇到的典型问题整理成速查表,方便后面有人踩坑时快速定位。
| 问题现象 | 根本原因 | 解决办法 |
|---|---|---|
| 同一助记词在鸿蒙和 Android 上生成地址不同 | 字节序或二进制数据转换不一致 | 统一走原始字节数组传输,禁止 hex 字符串跨通道 |
| 签名结果上链后被节点拒绝 | 待签数据格式不对,链要求双哈希而只做了单哈希 | 建立签名测试矩阵,逐一对比链上验证结果 |
| 生物识别成功后有时签名失败 | 解锁凭据过期或页面生命周期变化 | 在认证回调里立即执行签名,不在异步间隙做耗时操作 |
| 批量签名第几十笔开始报错 | 密钥库会话句柄泄漏或未释放 | 批量模式中每批签名结束后强制释放会话 |
| 网络请求频繁超时 | 原生侧线程模型与 Flutter 事件循环不匹配 | 原生只负责收发,回调统一投递到 Dart 事件队列 |
| 模拟器运行正常但真机崩 | abiFilters 缺少目标架构的动态库 | 检查鸿蒙工程的 so 配置,补齐对应架构 |
除表格外,还有一个适配思路层面的提醒:不要在鸿蒙侧复制 on_chain 在 Android 上的所有实现代码,然后一行行翻译成 ArkTS。那会把适配变成无底洞。要抱着“鸿蒙侧只提供最小能力集”的心态,凡是 Dart 侧能做的,绝对不放到原生侧;原生侧只做“必须靠近系统才能做”的事,比如安全存储和密码学运算。这个原则能帮你守住代码量的边界,也让未来的维护轻松得多。
最后再分享一个小技巧:适配完成后,我把整个鸿蒙插件层做成了独立模块,跟业务完全分离。之后 on_chain 上游升级、新链接入、密钥算法调整,都只改插件层,宿主业务代码一行不动。这个项目的实践下来,最大的体感是:Flutter 库的鸿蒙化,多数时候不是技术门槛问题,而是工程拆分和边界确认问题。把边界画清楚,适配就顺了。