ARTICLE DETAIL

资讯详情

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

square_connect鸿蒙化适配:Flutter支付插件迁移HarmonyOS的实战指南

square_connect鸿蒙化适配:Flutter支付插件迁移HarmonyOS的实战指南 Square 支付这名字做出海应用的朋友应该不陌生。square_connect 是 Flutter 生态里接入 Square In-App Payments 最常用的三方库但问题在于它默认只支持 Android 和 iOS鸿蒙HarmonyOS NEXT这边基本是空白。我前段时间接了个活儿要把一个带海外支付场景的 Flutter 应用平移到鸿蒙上支付渠道恰恰就是 Square这就意味着我必须亲自动手把 square_connect 这条路趟出来。这篇内容主要讲清楚一件事把 square_connect 鸿蒙化的过程中哪些代码能直接留哪些必须换底座鸿蒙端插件结构怎么搭以及实际编译联调时会撞上哪些墙。如果你是做鸿蒙应用出海、或者正在维护 Flutter 跨端支付模块的开发者这篇文章应该能帮你少走不少弯路。我会尽量按真实操作路径来讲不绕弯子。1. 先说清楚square_connect 到底是干吗的1.1 这个库在 Flutter 生态里的定位square_connect 本质上是对 Square 官方原生 SDK 的 Flutter 封装。Square 的 In-App Payments SDK 核心目标只有一个在客户端把银行卡号、CVV、有效期等敏感信息通过 Square 的加密组件转换成一个一次性 payment token然后你的服务端拿这个 token 去调用 Square 的 Charge API 完成扣款。这样做的好处非常明显敏感卡数据不在你的服务器上停留PCI DSS 合规压力大幅降低。客户端拿到 token 之后甚至连 token 本身都可以不落盘用完即焚。square_connect 在 Flutter 端的职责就是把这个流程胶水化——你只需要在页面里放一个卡片输入表单用户输完卡回调里给你一个 token剩下的是服务端的事。它还顺带封装了 Google Pay、Apple Pay 等数字钱包渠道方便用户在移动端一键拉起系统支付界面。但请注意这些能力都建立在 GMS 和 iOS 生态之上放到鸿蒙环境里就是另一回事了。1.2 为什么鸿蒙上不能直接跑先说结论square_connect 在没有改造的情况下在 HarmonyOS NEXT 上根本跑不起来。原因有几个层面HarmonyOS NEXT 不兼容 Android APKGoogle Play Services 自然不可用Google Pay 这条路断了。Apple Pay 只存在于 iOS 设备鸿蒙设备上压根没有这个能力。Square 官方 Android SDK 是依赖 GMS 的即便你用 HarmonyOS 的兼容内核去跑底层服务缺失也会导致运行时崩溃。鸿蒙的 Flutter 引擎和官方 Flutter SDK 在插件通道上有差异库内原生代码无法直接编译成 HAP 包中的动态库。也就是说这不是简单的“重新编译一下”就能解决的问题。需要把整个库拆开看逐层判断哪些能力能保留、哪些要替换、哪些要砍掉。1.3 先想清楚你要的是“支付中台”而不是“一个库”我在动手之前先想明白了一件事很多团队做支付集成时容易把“接入一个 SDK”当成“完成支付功能”。但在鸿蒙化这种多端异构场景下这种思路很危险。支付中台的含义是把支付流程拆成三层——客户端交互层、渠道网关层、业务订单层。客户端负责收集支付信息和展示结果渠道网关负责对接 Square、Stripe、华为支付等不同供应商业务订单层负责创建订单、核销回调、处理对账。这样设计之后哪天你想把 Square 换成 Adyen或者增加一个华为支付渠道只需要在渠道层新增适配器而不是重写客户端。square_connect 的鸿蒙化适配本质上就是要在这个三层结构里重新铺一条鸿蒙专属的管道。搞明白这个边界后面每一步都有方向。2. 鸿蒙化适配的整体拆解不是改代码是换底座2.1 先理解鸿蒙上的 Flutter 插件运行模型鸿蒙上的 Flutter 插件运行机制和 Android/iOS 并没有本质区别依然是 Dart 端通过 Platform Channel 调用原生端实现。但在鸿蒙生态里你面对的原生端不是 Android 的 Java/Kotlin也不是 iOS 的 Objective-C/Swift而是 ArkTS 加 Native APIC/C。具体来说鸿蒙 Flutter 插件工程里会多出一个ohos目录结构上和 Android 的android目录平行。你在ohos目录下用 DevEco Studio 维护一个鸿蒙模块通过继承 Flutter 插件基类注册 MethodChannel / EventChannel 的处理器然后在这个处理器里调用鸿蒙的 API 能力比如华为支付、蓝牙、网络请求等。需要特别注意的是鸿蒙版的 Flutter SDK 并不是 Google 官方那个 Flutter而是 OpenHarmony 组织维护的 flutter_flutter 分支。很多人在适配时直接用官方 Flutter 开发结果发现编译出来的产物不是 HAP 格式或者 Platform Channel 注册不了——因为 Flutter 引擎在鸿蒙侧的插件注册表机制和官方版本并不完全一致。所以第一步不是写业务代码而是先编译一个最小的“helloworld 插件”在鸿蒙模拟器上跑通确认你的 Flutter 工具链和鸿蒙 SDK 环境正确。2.2 square_connect 的能力映射方案把 square_connect 的所有功能列出来逐一做映射是鸿蒙化最核心的一步。我建议你动手前先做一张表然后按表施工原功能模块Android/iOS 实现鸿蒙适配方案适配难度SqPaymentForm 卡片输入表单原生视图嵌入 Flutter用 Flutter 自绘卡片表单或通过 PlatformView 调 ArkUI 组件中SqGooglePayGoogle Play Services替换为华为支付/自有后端代扣高SqApplePayPassKit直接移除无对应硬件生态低非接触式读卡器Square Reader SDK鸿蒙蓝牙适配或降级为扫码/手动输入高Tokenize 银行卡Square 原生 SDK tokenization服务端代理 tokenize 或替换渠道中charge 扣款接口Square API服务端对接与客户端解耦低如果你只是为了在鸿蒙上先跑通卡支付流程最简路径是自绘一个卡片输入表单拿到卡数据后通过你自己的后端转发到 Square API 做 tokenize 和 charge。这里提醒一下Square 对 card data 从客户端转发到服务端的合规要求很严格PCI DSS 的 SAQ 范围不同处理方式也不同。如果你的客户要求保留 Square 的 SAQ-A 等级那就必须使用 Square 提供的加密组件进行处理不能自己在 Flutter 层收集明文卡号再转发。这一点必须先和业务方法确认清楚别踩合规红线。2.3 哪些代码能留哪些必须动square_connect 的 Dart 层代码大部分是可以留的。它里面设计的支付表单状态机、卡类型识别、表单校验逻辑这些不依赖具体平台保留下来能省不少事。真正不能留的集中在几个地方所有通过MethodChannel(square_connect)发起的原生调用鸿蒙端根本没有对应的原生实现全部要补。所有使用 Google Pay / Apple Pay 的页面入口要么删掉要么换成鸿蒙上的华为支付调用。与 Square Reader SDK 相关的设备发现、连接、交易逻辑因为底层蓝牙/USB 通信协议不一样几乎要重写适配层。我的建议是fork 一份 square_connect 仓库创建一个新的square_connect_harmony包在 Dart 层通过条件编译或者运行时动态路由在鸿蒙上走自定义实现在其他平台走原逻辑。这样能最大限度地保证多端行为一致又不会把原库改得面目全非。3. 实操记录把 square_connect“搬到”鸿蒙上3.1 环境准备别在版本上消耗耐心适配鸿蒙插件环境是第一道坎。网络上很多人问“flutter 环境搭建”“vscode 鸿蒙版”之类的问题说明工具链本身对新手就不友好。我这边确定的基础版本组合是Flutter SDKOpenHarmony 维护的 flutter_flutter 分支基于 Flutter 3.7.x 的鸿蒙适配版。注意不要用官方 Flutter SDK否则编译产物不对。DevEco Studio5.x 及以上版本带 HarmonyOS SDK 和 hvigor 构建工具。Node.js 和 ohpm鸿蒙原生模块的包管理器类似 npm插件依赖都用 ohpm 拉取。模拟器或真机建议先用模拟器跑通 channel 注册再上真机测试支付流程。这里重点说下 Flutter SDK 的坑OpenHarmony 的 flutter_flutter 分支和官方 Flutter SDK 是两套东西。如果你在flutter doctor里看到版本号异常或者提示 “The current configured Flutter SDK is not known to be fully supported”先别慌这是正常的因为鸿蒙分支本身就和官方版本号不同步。关键是确认你的flutter命令指向的是鸿蒙分支的路径。3.2 第一步fork 原库建立 ohos 插件目录我在实际做法是这样的把 square_connect 的仓库 fork 下来在工程根目录下新建一个ohos/文件夹。这个文件夹的结构遵循鸿蒙插件标准大意是square_connect/ ├── lib/ # Dart 层源码保留原实现 ├── android/ # Android 原生插件不动 ├── ios/ # iOS 原生插件不动 ├── ohos/ # 新增鸿蒙原生模块 │ ├── entry/src/main/ets/ # ArkTS 业务代码 │ ├── entry/src/main/resources/ # 资源配置 │ └── build-profile.json5 # 鸿蒙构建配置 └── pubspec.yaml注意ohos目录不是一个独立 HAP它是作为插件模块参与 Flutter 应用的鸿蒙式编译。在 Flutter 工程中引入这个插件时hvigor 会自动把它作为依赖模块加载。pubspec.yaml 里需要新增一个依赖声明指向本地的 ohos 模块路径。这一步不同版本写法有差异我建议直接参考你用的 flutter_flutter 分支目录下flutter create --platformsohos生成的模板复制它的配置最稳妥。3.3 第二步在 ArkTS 端实现 MethodChannel这是整个适配过程中最核心的编码阶段。square_connect 在 Dart 端会通过 channel 发起多种调用例如初始化支付表单、tokenize 卡信息、处理回调等。你需要在 ArkTS 端为每一个 channel 方法提供具体实现。ArkTS 侧的大致实现骨架如下import { FlutterPlugin, MethodCall, MethodResult } from ohos/flutter_plugin export class SquareConnectPlugin implements FlutterPlugin { onAttach(engine: any) { engine.methodChannel(square_connect).setMethodCallHandler( (call: MethodCall, result: MethodResult) { switch (call.method) { case tokenizeCard: this.tokenizeCard(call.arguments, result) break case factoryPaymentForm: this.factoryPaymentForm(call.arguments, result) break default: result.notImplemented() } } ) } tokenizeCard(args: any, result: MethodResult) { // 这里不直接持有敏感卡数据而是通知后端服务发起 tokenize // 实际实现取决于你选用的支付网关 result.success({ token: mock_token }) } }需要注意一点在鸿蒙端不要试图把 Square 原生 Android SDK 偷偷搬过来因为那样会牵扯到 GMS 依赖问题。最干净的方案是鸿蒙端只负责收集卡数据用 Flutter 自绘 UI并把数据加密传给自己的后端由后端完成和 Square API 的 tokenize 交互。也许你会问那 tokenize 不还是走了服务端吗对这就是我在前面提到的支付中台思路。客户端和 Square 之间永远隔着一层服务端这样无论是适配鸿蒙还是未来接其他渠道改动都会小很多。3.4 第三步Dart 端兼容层的改造思路原库的 Dart 层改动不需要伤筋动骨。最核心的两处在调用原生通道前判断平台类型。如果是鸿蒙Platform.isHarmonyOS或通过defaultTargetPlatform判断就走自定义的实现分支。对于SqPaymentForm、SqGooglePay、SqApplePay这类类不直接实例化原生对象而是抽象出一个统一的PaymentMethod接口各端分别实现。Dart 层兼容层代码的示意结构FuturePaymentResult chargeWithCard({ required String cardNumber, required String expiryDate, required String cvv, }) async { if (Platform.isHarmonyOS) { // 鸿蒙自定义支付通道 return HarmonyPaymentChannel().charge(cardNumber, expiryDate, cvv); } // 其他平台使用 square_connect 原实现 return SquarePaymentForm().tokenize(...); }兼容层的价值在于应用层业务代码不感知底层替换调用方不需要因为你适配了鸿蒙而改一堆页面逻辑。如果你后续要加一个微信支付渠道也只需要新增一个适配器类而已。3.5 第四步对接支付渠道的推荐形态Square 在鸿蒙上的目标用户基本是出海 App 的海外用户。这些用户本来就可能用本地支付方式比如信用卡、Google Pay、PayPal 等。鸿蒙因为没有 Google Pay最需要解决的是“无卡快捷支付”这个缺口。我推荐的做法是鸿蒙端优先对接两个能力。华为支付Huawei IAP / Huawei Pay覆盖国内和部分海外用户可以替代 Google Pay 的数字钱包体验适合那些目标用户中鸿蒙设备占比不低的 App。服务端代理 Square保留原有信用卡主流程先把卡输入和 token 创建跑通后续再逐渐丰富渠道。还有一个思路如果你的 App 在全球分发用户群体分散可以暂时不集成华为支付而是引导用户走“卡输入 3DS 验证”的流程。Square 的 3DS 验证本来就走 WebView鸿蒙 WebView 是支持的这条路也通。4. 编译与联调常见问题与排查实录4.1 编译期依赖解析和构建版本是最大拦路虎编译鸿蒙插件时最常遇到的就是各种依赖冲突和构建工具版本不一致。我遇到的一个典型问题是hvigor 版本和 DevEco Studio 版本对不上导致的报错往往是“Could not resolve dependencies”或者“unsupported hvigor version”。解决办法通常是到 DevEco 的 SDK 安装目录下把 hvigor-wrapper 版本和 IDE 内置版本对齐然后在build-profile.json5里显式指定版本号。还有一个很常见的报错在网络上能搜到很多人问“You are applying Flutters main Gradle plugin imperatively using the apply script”。这虽然是个 Gradle 配置问题但在鸿蒙适配场景下经常被忽视。原因是 Flutter 工程里残留了 Android 的 Gradle 插件引用鸿蒙构建时也会尝试解析这些 Gradle 配置。解决办法是把android/目录下的 Gradle 相关配置暂时移出工程路径或者确保构建脚本里不残留 Android 特有的apply调用。另外提醒一句ohpm install拉取鸿蒙依赖时网络不稳会导致解析失败。建议在.npmrc或ohpm配置里设置好镜像仓库别等构建到一半才发现依赖没拉全。4.2 运行期channel 未注册、网络错误、权限问题最常见的一个运行期坑Dart 端调用 channel 方法报“MissingPluginException”。原因是鸿蒙插件没有正确注册到 Flutter 引擎上。这种情况通常和插件的初始化时机有关尤其是当你用的是FlutterPlugin接口而不是传统的MethodChannel手动注册时必须在onAttach生命周期里完成 setMethodCallHandler否则 channel 注册时机可能晚于 Dart 端首次调用。另外一个高频问题就是网络上经常被搜索的 “android 请求正常鸿蒙请求 2300056”。这个错误码我在联调时遇到过几次。出现原因多半不是代码逻辑问题而是鸿蒙应用请求网络时的证书校验、网络安全配置或者权限声明不对。排查路径是这样的确认module.json5里是否声明了ohos.permission.INTERNET这个权限在鸿蒙上必须显式声明不声明请求直接失败。确认服务端 TLS 证书是否被鸿蒙的网络安全组件接受。鸿蒙对证书链校验比 Android 更严格自签名证书大概率会挂。如果使用了 HttpDNS 或自定义 DNS 解析检查鸿蒙的 DNS 解析 API 是否兼容。联调阶段我习惯用 Charles 抓包观察服务端回调的报文确认 tokenize 请求有没有真正到达后端。但这里必须提醒一句调试支付模块时只观察自己的服务端接口返回和回调结构不要去截取真实的卡数据和支付凭证也不要保存任何用户的敏感信息到日志文件。务必用测试卡号跑流程这是行业底线。4.3 真机测试与签名模拟器能跑通不算完支付类应用在模拟器上能跑通 UI 流程不代表真机能跑通支付。因为真机的安全模块、设备指纹、密钥存储这些都是模拟器不具备的。鸿蒙端签名调试有个很容易忽略的点HAP 包需要签名才能安装到真机上Debug 签名和 Release 签名的 scheme 不同。如果你的应用要上架华为应用市场还需要申请发布证书和 Profile。签名不匹配会直接导致安装失败或运行时报 “signature verification failed”。更隐蔽的问题是如果你的鸿蒙应用最终要回归到华为应用市场的上架审核支付类应用通常需要提供相应的行业资质与业务说明。尤其是涉及真实资金交易的审核周期比普通应用长。建议早点提交预审不要等到功能开发完成才开始走流程。5. 一些过来人的建议5.1 不要把 API 全量适配优先做核心支付链路square_connect 的 API 表面看起来不多但内部有些能力依赖非常重比如 Square Reader 的蓝牙刷卡器。这个能力在鸿蒙上做适配既要处理蓝牙协议差异又要重新对接硬件厂商成本不亚于开发一个独立模块。我的建议是优先适配“表单收集 服务端 tokenize 服务端 charge”这条主链路。这条链路能覆盖绝大多数线上支付场景。读卡器这种软硬件结合的场景要么砍掉要么等有实际客户需求再接。另外Google Pay 和 Apple Pay 这些渠道在鸿蒙上不要强行做兼容层。华为支付的能力模型和 Google Pay 不一样强行抽象一个通用接口最后只会得到一个“哪边都不好用”的结果。不如直接做成可插拔渠道。5.2 支付中台的扩展方向顺着中台的思路square_connect 鸿蒙化只是第一步。你完全可以在这个基础上继续抽象出订阅扣费、退款、对账、撤销等能力。这些能力在 Square API 里都是现成的服务端封装一次多端复用。鸿蒙端的原生支付能力比如华为支付的“应用内支付”和“钱包能力”也可以逐步接入到同一个中台里。这样你的 App 在不同设备上支付入口可能不同但底层的订单、回调、退款逻辑完全一致。5.3 我的个人体会做完这个适配项目我最直观的感受是鸿蒙生态已经跳出“只能跑安卓应用”的圈子了但它的三方库生态还有很大缺口。square_connect 的鸿蒙化表面上是给一个支付库打补丁本质上是对整个支付中台做了一次重构校验。如果你只是“把代码跑通”而不是“把结构理顺”后面每加一个新渠道、每适配一个新系统都会非常痛苦。最后再分享一个小技巧适配过程中每完成一个 channel 方法就在鸿蒙端写一个小例程做冒烟测试不要等所有方法都写完再联调。否则遇到MissingPluginException时你都分不清是哪个方法没注册成功。小步快跑适配效率会高很多。
返回列表