ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Flutter插件鸿蒙化实战:以daktela_connector为例打通全渠道联络中心

Flutter插件鸿蒙化实战:以daktela_connector为例打通全渠道联络中心 如果你负责过联络中心相关 App 的开发应该能体会这种别扭业务逻辑已经用 Flutter 写得很顺了结果对接 Daktela V6 这套全渠道联络中台时原生插件在鸿蒙上直接哑火——登录、实时消息推送、通话事件回调全线失效用户侧看到的就是“客服不在线”或者消息一直转圈。这不是 Flutter 的错而是 daktela_connector 这类三方库天生只适配了 Android 和 iOS鸿蒙端缺了一个原生实现层。我在把 daktela_connector 鸿蒙化的过程中把整个链路从 Flutter 侧一路拆到 ArkTS 原生层包括 MethodChannel 调用、EventChannel 实时事件流、WebSocket 长连接、Token 刷新、脱敏日志等最终让这套联络中心交互回到了“全渠道极速”的状态。这篇内容不打算写成官方文档的复述而是把我实际操作中的方案选型、核心代码思路、踩过的坑、排查技巧全部摊开给同样要面对“Flutter 第三方库鸿蒙化”的朋友一份能直接抄作业的参考。1. 项目拆解daktela_connector 到底干了什么鸿蒙化要解决什么1.1 daktela_connector 在 Flutter 生态中的角色先说清楚这个库的定位。Daktela 本身是一套云端联络中心平台V6 版本主打“全渠道统一队列”也就是电话、在线聊天、邮件、工单、社交媒体消息可以进同一个客服工作台。对 App 开发者来说我们通常不需要把整个客服后台搬进 App只需要在 App 里做三件事登录/会话恢复、拉取会话列表和消息历史、接收实时事件新消息、客服接入、通话状态变化。daktela_connector 就是为此封装的一个 Flutter 端 SDK。它把 Daktela V6 的 REST API 和实时推送通道包装成 Dart 可以调用的 API上层业务不用关心 HTTP 请求、JSON 序列化、WebSocket 连接管理等细节。但这恰恰是鸿蒙化适配的核心难点这个库虽然是 Flutter 插件却不是一个纯 Dart 包它在原生层做了不少事情——比如维护 WebSocket 连接、注册平台通道、处理后台通知、依赖 Android 的 NetworkSecurityConfig 和 iOS 的 ATS 配置。放到鸿蒙上这些“原生依赖”全部要换成鸿蒙端的能力。另外要纠正一个常见误解Flutter 插件鸿蒙化不等于“把 dart 代码重新编译一遍”而是要在鸿蒙侧补齐一个与原库接口对齐的原生实现。Dart 层可以复用大部分代码但平台通道的另一端——MethodChannelHandler、EventChannelSink、WebSocket 会话管理——必须用 ArkTS 重新实现。1.2 鸿蒙化适配需要覆盖的四层能力我整理了一张对照表把 daktela_connector 依赖的原生能力与鸿蒙侧的替换方案列出来做技术评估时一眼就能看清工作量能力模块Android/iOS 原有实现鸿蒙侧适配方案涉及文件/接口API 通道MethodChannel / Pigeon使用 Flutter 鸿蒙引擎提供的 MethodChannel API用 ArkTS 实现 HandlerPlugin 入口类、ChannelName 注册实时事件推流EventChannel StreamHandlerEventChannelSink 实现事件流Dart 侧用 StreamSubscription 消费EventChannel 创建、事件发送长连接与推送OkHttp WebSocket / URLSessionWebSocketTaskohos.net.webSocket 建立连接自定义心跳与重连逻辑WebSocket 客户端类本地数据与 Token 存储SharedPreferences / Keychainohos.data.preferences 持久化Util 或加密存储保存密钥Token 存取模块网络与证书策略NetworkSecurityConfig / ATS 配置module.json5 中配置网络权限支持自定义证书信任策略网络权限、证书相关配置这里最关键的不是代码量而是“接口契约”。daktela_connector 的 Dart 层暴露给业务方的 API 往往已经定了比如login、subscribeToConversation、sendMessage鸿蒙端实现的目标不是设计一套新 API而是让这些已有 API 在鸿蒙上表现一致。也就是说适配工作的本质是“对已有契约做平台实现对齐”而不是重新发明轮子。1.3 为什么不能直接跑在鸿蒙上一个典型崩溃链路很多人一开始会抱着侥幸心理既然 Flutter 是跨平台的是不是把 daktela_connector 的依赖加进去就能跑了我在项目初期也试过这种“先跑起来再说”的路子。结果是很标准的失败链路编译阶段能过因为 Flutter 引擎本身在鸿蒙上已经有可用的鸿蒙化运行时但一运行到调用登录接口时Dart 层抛出MissingPluginException提示找不到daktela_connector对应的原生实现。这个异常的原因很简单Flutter 插件在 Android 上是靠GeneratedPluginRegistrant把MainActivity和插件类绑定起来的iOS 是靠plugin_register宏注册。鸿蒙 Flutter 引擎也有自己的注册机制但 daktela_connector 没有实现鸿蒙侧的注册入口于是 MethodChannel 的另一端永远是空的。这不只是 daktela_connector 一个库的问题是所有未做鸿蒙化的原生插件共同的问题。所以我在做正式适配前先画了一张“能力缺口清单”把 daktela_connector 的依赖项逐个标记为“已具备”“可替换”“需要自研”比直接看源码更快。2. 工具链与方案选型搭建鸿蒙 Flutter 插件开发环境2.1 环境准备Flutter SDK 要换成鸿蒙适配版做鸿蒙化适配的第一步不是打开 Android Studio而是把开发环境切换到支持鸿蒙目标的 Flutter SDK。目前官方主线 Flutter SDK 还不直接支持鸿蒙目标需要用 OpenHarmony 生态维护的 flutter_flutter 分支或者直接使用 DevEco Studio 内置的鸿蒙 Flutter 集成方案。我实际使用的是具备鸿蒙 target 支持的 Flutter 引擎版本它能在构建时生成鸿蒙平台插件注册表并且支持 MethodChannel 到 ArkTS 的桥接。环境清单大致是这样DevEco Studio建议使用支持 API 12 及以上版本的 IDE我使用的是 API 12 的 SDK 进行验证Flutter 鸿蒙化 SDK来自 openharmony 相关组织的 fork 版本建议固定版本不要随意升级OpenHarmony SDK Platform包含ohos.*系统 API鸿蒙真机或 HarmonyOS NEXT 模拟器用于联调这里有一个容易踩坑的细节鸿蒙 Flutter 插件工程的 Gradle 配置和 Android 工程不同插件模块本质上是一个 HarmonyOS HAR 包而不是 AAR。所以你不能把.aar直接扔进鸿蒙工程得用hvigor构建出.har包再让宿主 App 依赖这个 HAR。也就是我们在 CocoaPods 和 Android Archive 之外又增加了一种包管理方式。2.2 通信方案选型Pigeon 还是手写 MethodChanneldaktela_connector 原库在 Dart 侧用的是 MethodChannel 和 EventChannel。做鸿蒙化的时候我面临一个选择是沿用原来的 MethodChannel 手写桥接还是用 Pigeon 生成类型安全的跨语言接口我的结论是如果原库已经用了 MethodChannel并且数据结构不复杂用 Pigeon 重建收益不大反而会增加迁移成本。Pigeon 适合从零开始、需要多端一致接口的新插件它的优点是把 channel 名、方法名、参数编解码都收敛到代码生成里避免两边各写一套字符串出错时不容易排查。但 Pigeon 对鸿蒙端的支持尤其是 ArkTS 代码生成这块生态还没有 Android/iOS 那边成熟部分生成代码还需要手工调整。所以我在这次适配中保留了 MethodChannel 的方案但做了一层“契约收敛”把 daktela_connector 用到的每一个方法名、参数键、返回类型都整理成一张常量表Dart 侧和 ArkTS 侧共用这份约定。这个做法的好处是即使两边代码是两种语言至少错误信息是统一的排查时能直接定位到方法层面。提示鸿蒙化适配过程中最怕的是两边各自改参数名。接手这种工作时先把 channel 名和方法名固化成不可变常量任何一边要加参数必须同步更新契约文件。2.3 工程结构一个插件模块加一个宿主演示工程我不建议直接把所有适配代码塞进业务 App 工程里那样后面升级 daktela_connector 原库时会非常痛苦。正确做法是建一个独立的鸿蒙 HAR 模块比如叫daktela_connector_ohos里面包含完整的 ArkTS 原生实现Dart 侧则仍然引用原版的 daktela_connector。最终工程结构大致是这样的daktela_connector_ohos/ # 鸿蒙插件 HAR 模块 src/main/ets/ DaktelaConnectorPlugin.ets # 插件注册入口 DaktelaApiHandler.ets # MethodChannel 方法分发 DaktelaEventSink.ets # EventChannel 事件流 DaktelaWebSocketClient.ets # WebSocket 长连接 TokenStore.ets # Token 持久化 oh-package.json5 # 鸿蒙包配置 example/ # 宿主演示工程 entry/ src/main/ets/ entryability/ pages/ dart_plugin/ # Dart 侧示例与适配层鸿蒙插件模块和 Android 插件最大的区别在于Android 插件通常直接由 Flutter 引擎通过反射注册鸿蒙 HAR 则需要显式提供一个入口类给宿主工程调用。我在entryability的onCreate里显式注册了 DaktelaConnectorPlugin而不是依赖自动注册这样虽然多了一步手工操作但可以精确控制插件何时生效避免页面还没有绑定就被事件流冲进来。2.4 版本锁定与依赖管理的取舍三方库鸿蒙化的一个隐形风险是版本漂移。Daktela V6 的 API 会升级原版 daktela_connector 也会升级鸿蒙适配层如果跟踪不及时很可能出现“Dart 侧传入的新参数ArkTS 侧根本不知道”的情况。我在工程里做了一件很土但很有效的事把 Daktela V6 API 的核心字段会话 ID、消息类型、时间戳格式、用户角色枚举单独抽成一个数据契约文件放在仓库根目录。原库升级时先比对契约文件有没有变化再决定要不要动鸿蒙实现层。这个工作虽然只花半天但在后续维护中省掉了很多“怎么 Daktela 那边消息突然解析不出来了”的排查时间。3. 鸿蒙端核心实现从注册到事件流的完整落地3.1 插件入口用 ArkTS 注册 MethodChannel鸿蒙 Flutter 插件的入口类在形态上类似 Android 的Plugin。它的职责是创建通道实例并绑定到 Flutter 引擎。这里给出一个结构参考具体 API 名称以你使用的鸿蒙 Flutter SDK 版本为准import { MethodChannel, MethodCall, MethodResult } from flutter_lib_ohos; export class DaktelaConnectorPlugin { private static readonly CHANNEL_NAME daktela_connector/connector; static register(channel: MethodChannel): void { channel.setMethodCallHandler((call: MethodCall, result: MethodResult) { new DaktelaApiHandler().handle(call, result); }); } }这里有几个容易出问题的点。第一CHANNEL_NAME必须和 Dart 侧完全一致一个字符都不能差。如果原库在 Android 上用的 channel 名带了下划线或点号鸿蒙侧必须原样保留。第二setMethodCallHandler只能设置一次重复设置会覆盖之前的 handler导致某些方法突然失效。第三handler 里的异常必须通过result.error()返回不能直接 throw 到引擎层否则 Dart 侧收到的是PlatformException(code: error)错误码信息会丢失。Dart 侧调用时是这样import package:flutter/services.dart; const MethodChannel _channel MethodChannel(daktela_connector/connector); FutureString login(String username, String password) async { try { final String token await _channel.invokeMethod(login, { username: username, password: password, tenant: default, }); return token; } on PlatformException catch (e) { // 把原生错误码与 message 透传到业务层 throw DaktelaAuthException(e.code, e.message); } }3.2 MethodChannel 的 API 分发登录与会话恢复MethodChannel 的本质是一个异步 RPCDart 侧调用invokeMethod后数据通过二进制编码传递到鸿蒙侧ArkTS 侧解析参数执行逻辑再通过result.success()或result.error()返回。daktela_connector 的 API 大体分为三类第一类是认证类比如login、logout、refreshToken。这一类方法在鸿蒙侧要和 TokenStore 联动。login成功之后Daktela V6 会返回一个 access token 和 refresh token我这里把它们分别存放在 preferences 中。注意 refresh token 通常有效期较长属于敏感数据不建议明文存储。鸿蒙上可以先做一层简单的加密处理我实际使用的是系统提供的加密工具对 token 做 Base64 混淆存储后续如果要上生产环境建议接入密钥管理能力。第二类是数据查询类比如拉取会话列表、消息历史。这类方法往往是同步 HTTP 请求的封装。需要注意的是MethodChannel 的回调是异步的鸿蒙侧的HttpClient也是异步的因此处理时要确保result只被调用一次。一个比较隐蔽的 bug 是超时时间设置不当Daktela V6 在会话列表数据量大时超过 10 秒才返回是常事Android 侧可能设置了 15 秒超时鸿蒙侧如果沿用默认 5 秒就会出现频繁超时。必须把超时参数单独提出来做成可配置项。第三类是订阅类比如subscribeToConversation。这类方法在 Daktela V6 里会建立一条实时通道Dart 侧一般会传入一个会话 ID鸿蒙侧负责维护这个订阅关系并把后续事件通过 EventChannel 推送回 Dart 侧。3.3 EventChannel 实现实时事件流Daktela V6 的实时能力依赖于 WebSocket 或服务端推送。daktela_connector 在 Android 端通常会把 WebSocket 收到的事件装进 EventChannel。鸿蒙侧的实现思路完全一致import { EventChannel, EventSink } from flutter_lib_ohos; export class DaktelaEventSink { private static sink: EventSink | null null; static attach(channel: EventChannel): void { channel.setStreamHandler({ onListen: (arguments, sink) { DaktelaEventSink.sink sink; // 启动事件投递 }, onCancel: (arguments) { DaktelaEventSink.sink null; // 停止事件投递 }, }); } static pushEvent(event: object): void { if (DaktelaEventSink.sink) { DaktelaEventSink.sink.success(event); } } }EventChannel 有三个必须注意的坑。第一个坑EventSink不能用null。如果sink还没挂载好WebSocket 事件就来了最容易出现空指针异常。我在实现里做了一个缓冲队列attach之前的事件先放到内存队列onListen之后再补发确保事件不丢。第二个坑sink.success()一次只发一个事件Dart 侧的EventChannel.receiveBroadcastStream()是一个无限流两边对接没有问题但业务侧必须自己处理背压否则消息量大时 Dart 侧会积压。Daktela V6 的全渠道场景里一个会话高峰期可能每秒推送十几条消息我在 Dart 侧加了一个简单的合并策略同一会话的连续事件在 200ms 内先合并再交给 UI 刷新。第三个坑onCancel可能被系统触发比如页面销毁或引擎回收这时必须把sink置空否则会向已经销毁的通道继续发送事件造成内存泄漏或崩溃。3.4 WebSocket 长连接与心跳保活Daktela V6 的实时推送机制采用 WebSocket。鸿蒙的系统能力里提供了ohos.net.webSocket可以创建客户端 WebSocket 连接。我的实现里把 WebSocket 的生命周期拆成了四段连接建立阶段从 TokenStore 里取 token拼好 Daktela 的 WebSocket 地址带上鉴权头发起连接。这里要特别注意 Daktela 的私有化部署场景不同租户的 WebSocket 路径或端口可能不一样不能写成死配置。鉴权与订阅阶段连接成功后要立刻发送一个订阅消息告诉服务端“这个客户端想接收哪些事件”。Daktela V6 通常要求先鉴权再订阅顺序反了会直接被服务端断开。心跳保活阶段Daktela 服务端一般有一个空闲断开时间客户端必须周期性发送 ping 帧或者业务层心跳消息。鸿蒙 WebSocket 接口支持ping方法我这里设成每 30 秒发送一次并记录上一次收到 pong 的时间。如果连续三次没有收到 pong就主动断开重连。重连与退避阶段WebSocket 断开后不能无脑重连要用指数退避策略。我采用 1 秒、2 秒、4 秒、8 秒依次递增最多 30 秒封顶。同时重连前要先确认 Token 是否过期如果过期先走 refreshToken 流程再重建连接。import { webSocket } from ohos.net.webSocket; function connectDaktelaWebSocket(url: string, token: string): void { const ws webSocket.createWebSocket(); ws.on(open, () { // 发送鉴权与订阅消息 ws.send(JSON.stringify({ action: subscribe, token: token })); startHeartbeat(ws); }); ws.on(message, (data) { // 解析事件投递给 EventSink DaktelaEventSink.pushEvent(JSON.parse(data)); }); ws.on(close, () { stopHeartbeat(); scheduleReconnect(); }); }注意一个安全细节Dart 层返回给 UI 的事件对象里绝对不能把 WebSocket 的 token 带进去。我在鸿蒙侧做事件反序列化时就把鉴权字段剔除干净避免在 debug 日志或 UI 侧误打出来。3.5 Dart 侧 API 兼容层业务代码不用大面积改动鸿蒙适配最终要交付给业务方一个“行为一致”的体验而不是一套新 API。因此 Dart 侧尽可能不要动原库的对外接口。我在实际工程里只增加了一个条件判断如果当前运行在鸿蒙平台就使用适配层的通道名否则用原库的通道名。这里可以通过Platform.isHarmonyOS或 Theme 来判断但更稳妥的做法是让适配层和原库暴露同一套接口内部路由到不同的 channel。这里给出一个扩展思路如果原库没有显式暴露 channel 名可以在 Dart 侧用MethodChannel的动态代理思路把原库的 method call 透明转发。但这个方案侵入性大我通常只在原库完全无法修改时才用。能改原库代码的情况下尽量在daktela_connector的插件注册入口加一个鸿蒙分支这样对业务方最透明。4. 实操验证与性能优化从编译通过到“全渠道极速”4.1 编译与联调的完整流程联调阶段我把流程拆成八步每一步都有明确产出和验证点构建鸿蒙 HAR 模块在daktela_connector_ohos根目录执行 hvigor 构建命令产出.har文件。这里注意 hvigor 的版本要跟 DevEco Studio 匹配否则可能报版本冲突。让宿主工程依赖 HAR在entry的oh-package.json5中加依赖并同步module.json5中的权限配置。在页面中手动注册插件在entryability的onCreate中调用DaktelaConnectorPlugin.register。运行到鸿蒙模拟器/真机确认 Flutter 页面能正常渲染没有白屏或闪退。在 Dart 侧增加一段自检代码调用_channel.invokeMethod(ping)验证通道是否打通。验证登录接口用测试账号登录确认 Token 正常返回并持久化。验证事件流在 Daktela 后台手动给测试账号发送一条消息确认 App 能实时收到推送。验证语音呼叫事件模拟 V6 通话状态变化确认callStatusChanged事件能到达 UI 层。第 5 步特别重要。很多团队在联调时直接调登录结果发现MissingPluginException不一定是鸿蒙实现没写而是插件根本没有注册。先单独验证通道连通性能大大缩小排查范围。4.2 全渠道场景压测消息、会话与通话事件我不是只在模拟器里跑通了就宣布结束。Daktela V6 的“全渠道”意味着事件类型很杂有聊天消息、有工单状态变化、有呼叫中心的振铃和接通事件。我针对三个高频场景做了集中验证消息收发场景同时订阅 5 个会话每个会话每秒注入 5 条消息观察消息是否乱序、是否丢失。实测下来EventChannel 的缓冲队列起到了关键作用在 UI 线程来不及处理时事件不会丢失只是在队列里排队。会话状态场景在 Daktela 后台不断把会话分配给不同客服、打标签、转接。这个场景里最容易出问题的是事件字段里的枚举值不一致。Daktela V6 在有些环境里返回的是assigned有些环境返回ASSIGNED大小写不统一。我在鸿蒙侧的解析层统一做了大小写归一化处理。通话事件场景电话呼叫的振铃和接通事件通常要求低延迟。一次实际压测中从 Daktela 后台触发振铃到 App 界面弹出来电卡片鸿蒙端耗时在 200ms 到 400ms 之间其中网络往返占了绝大部分这个数值在可接受范围内。但如果事件流里夹带了大体积的会话摘要数据解析和序列化的耗时就会明显上升建议在上层使用懒加载不全量下发。4.3 线程模型与内存管理不要让原生事件卡住 UIFlutter 的 UI 线程和鸿蒙原生线程是两套体系。鸿蒙侧 EventChannel 的事件投递如果直接在 WebSocket 的 message 回调里执行sink.success可能会带来两个问题一是 WebSocket 回调线程和 Flutter 引擎的通道线程是不同的频繁切换有额外开销二是如果事件数据是一个很大的 JSON 对象序列化和结构化克隆会阻塞通道。我的优化思路是在鸿蒙侧把 WebSocket 收到的原始 JSON 字符串先做一次轻量校验确认不是错误帧后再投递给 EventSink。具体转换放到 Dart 侧完成。这样做的好处是Dart 侧拿到的是结构化数据后可以决定哪些字段要展示、哪些要丢弃鸿蒙侧只负责“透传”不承担业务解析逻辑降低了耦合。另外事件流需要保证时序。同一会话的消息如果乱序到达聊天界面会很难看。我在 Dart 侧的事件分发器里维护了一个按会话 ID 分组的缓存区事件先按到达时间排序再以会话为单位提交给 UI。这个排序在消息量小的时候没什么感觉但在多渠道混合推送时非常关键。4.4 日志与脱敏联调时必备的调试手段Daktela V6 涉及大量用户敏感信息联调时日志里不能直接打 token 和完整消息内容。我在适配层内置了专门的 debug 通道在 debug 构建下MethodChannel 的入参和出参会打印到控制台但自动把token、refreshToken、password这三个字段替换成***。这个做法在排查问题时有巨大价值。比如有一次用户反馈“登录偶发失败”业务侧拿不到任何信息。通过脱敏日志我看到某一次请求中鸿蒙侧传入的 username 末尾多了一个空格导致 Daktela V6 返回 401。如果没有日志这种问题几乎查不出来。5. 常见问题与排查技巧实录5.1 常见错误速查表我把实际开发中遇到的高频问题整理成一张表方便大家对照处理现象可能原因排查与解决MissingPluginException插件未注册 / channel 名不一致检查register是否在onCreate中调用channel 名与 Dart 侧是否一致调用登录接口后无响应MethodChannel 回调未执行或卡死检查 handler 内是否持有result未返回确认没有异常被吞掉EventChannel 收不到事件onListen 未触发 / sink 未挂载在setStreamHandler中打日志确认 attach 时机检查缓冲队列是否已补发WebSocket 频繁断开心跳间隔大于服务端空闲阈值把心跳间隔调到 30 秒以内观察断开前是否有 pong 超时消息偶尔乱序多处投递事件 / 线程竞争在 Dart 侧按会话分组排序确认没有多个线程同时写 sinkJSON 解析报错ArkTS 对类型严格空值字段导致异常用安全类型转换工具包统一处理 null 和 undefined鸿蒙真机无法联调网络权限未配置 / 设备未开启调试检查 module.json5 的ohos.permission.INTERNET确认设备调试模式正常5.2 网络与证书私有化部署的隐藏坑Daktela V6 既有公有云版本也有很多政企客户私有化部署。私有化环境通常使用内部证书或自签名证书鸿蒙端如果沿用默认的证书校验策略会直接拒绝连接。Android 上可以用NetworkSecurityConfig信任用户证书鸿蒙上则需要在网络请求配置里做证书信任设置。我在项目里做了一个可配置项默认模式校验系统证书debug 模式允许信任用户安装的证书生产环境如果确需自签名证书必须通过运维把证书放到受信任区域而不是在代码里关闭校验。安全底线不能丢。另一个网络相关的坑是 IPv6 与网络切换。鸿蒙真机在 Wi-Fi 和移动网络之间切换时WebSocket 连接会断掉。如果没有监听网络变化并主动重连会出现“App 到后台再回前台就没消息”的假象。我实现了一个简单的网络变化监听发现网络断开时立即释放 WebSocket恢复后走重连逻辑。5.3 生命周期App 到后台与进程回收联络中心 App 有个特殊场景用户切到后台来电事件也必须能到达。这里涉及两个层面。一个是 Flutter 引擎层面App 到后台后Flutter view 可能仍然存活但 Dart 层的事件处理不一定继续。另一个是鸿蒙 Ability 的生命周期在onBackground或onForeground时插件需要感知状态变化。我在插件里做了onForeground和onBackground的显式通知到后台时暂停 UI 刷新但 WebSocket 心跳继续回前台时先检查 WebSocket 是否还在线如果不在就立刻重建而不是等下一次心跳超时才发现。这样用户回前台时消息列表往往是已经刷新的状态体验上就是“全渠道极速”的感觉。5.4 鸿蒙独有包名、Har 冲突与热更新最后说几个鸿蒙特有的小问题。第一包名限制。鸿蒙应用包名不能与系统组件冲突适配时如果 HAR 的包名起得不好可能出现运行时权限判定异常。建议插件 HAR 包名以com.yourcompany.daktela_connector格式命名不要用裸名。第二Har 冲突。如果宿主同时依赖多个 HAR而某些 HAR 打包时把其他模块的类也打进去了会出现重复类冲突。排查方法是检查构建产物里的.har解压内容确认没有重复的 ets 文件。第三不要太依赖热更新思路。鸿蒙 Flutter 适配层如果出现逻辑 bug最稳妥的方式是重新打 HAR 并让宿主升级而不是尝试在运行时动态替换 ArkTS 代码。我在早期试过一些动态加载的思路稳定性和合规性都不够好后来果断放弃。把 daktela_connector 鸿蒙化并不是把 Android 代码逐行翻译成 ArkTS而是要把原库的能力边界、数据契约和生命周期管理都摸透再用鸿蒙的系统能力重新实现一遍。特别是 WebSocket 心跳、EventChannel 的挂载时机、MethodChannel 的一次性回调这三个点只要有一个没处理干净线上就会表现为“偶发收不到消息”或“登录卡死”而这种问题特别难排查。如果你正在做类似的 Flutter 三方库鸿蒙化建议先从通道连通性自检做起再逐步深入事件流和长连接别一上来就铺开全量功能。
返回列表