Flutter/OpenHarmony 三方库适配实战:jpush_flutter 推送兼容层
Flutter/OpenHarmony 三方库适配实战:jpush_flutter 推送兼容层
一、项目信息
| 项目 | 内容 |
|---|---|
| 仓库名称 | jpush-flutter-plugin |
| Dart 包名 | jpush_flutter |
| AtomGit 仓库地址 | https://atomgit.com/oh-flutter/jpush-flutter-plugin |
| 上游适配版本 | 2.1.4 |
| OHOS 适配版本 | 2.1.4-ohos.1 |
| 方法通道 | jpush |
| OHOS 原生入口 | JPushPlugin |
| 示例包名 | com.example.jpush_example |
| HAP 产物 | example/build/ohos/hap/entry-default-unsigned.hap |
| 当前状态 | 已完成分析、测试、构建和模拟器启动验证,并已推送到 main |

二、这个库为什么需要 OHOS 适配
JPush 的 Dart 层并没有直接依赖 Android 类,它把业务操作集中到一条
MethodChannel('jpush') 上:
static final JPush _instance =
JPush.private(const MethodChannel('jpush'), const LocalPlatform());
这条设计让适配边界变得很清楚:
业务页面
|
| JPush Dart API
v
MethodChannel("jpush")
|
+--> Android JPush SDK
+--> iOS JPush SDK
+--> OHOS JPushPlugin(本次新增)
真正困难的不是创建 MethodChannel,而是 OpenHarmony 当前没有可验证的
JPush 原生 SDK。如果把 setup、getRegistrationID 或 setTags
直接返回成功,业务会误以为设备已经注册并能收到远端推送,这比明确返回
不支持更容易造成线上问题。
因此本次适配分成两层:
- 工程层完成 OHOS 插件发现、HAR 构建、插件注册和通道存活。
- 能力层只实现可验证的平台版本与适配版本查询,其他远端推送能力返回
jpush_unsupported。
三、先让 Flutter OHOS 找到插件
根 pubspec.yaml 保留 Android 和 iOS 声明,只增加 OHOS 入口,并把版本
标记为 OHOS 适配版本:
version: 2.1.4-ohos.1
environment:
sdk: ">=3.2.0 <4.0.0"
flutter:
plugin:
platforms:
android:
package: com.jiguang.jpush
pluginClass: JPushPlugin
ios:
pluginClass: JPushPlugin
ohos:
pluginClass: JPushPlugin
这里有几个容易被忽略的点:
pluginClass必须和index.ets最终导出的默认类一致。- Dart SDK 下限从旧工程的过低版本提升到
3.2.0,才能与当前 Flutter OH
工具链一致。 platform依赖解析到3.2.0,示例代码中的过时 API 同步更新。- 版本追加
-ohos.1,避免与上游原版本混淆。
OHOS 模块是 HAR,不是应用工程,所以它的 hvigorfile.ts 使用
harTasks:
import { harTasks } from '@ohos/hvigor-ohos-plugin';
export default {
system: harTasks,
plugins: [],
};
index.ets 负责把 ArkTS 插件类交给 Flutter 生成的注册器:
import JPushPlugin
from './src/main/ets/components/plugin/JPushPlugin';
export default JPushPlugin;
如果这一层缺少任何一环,都会出现类似问题:
| 缺失位置 | 典型现象 |
|---|---|
pubspec.yaml 无 ohos | Flutter 不生成 OHOS 插件注册代码 |
hvigorfile.ts 使用 appTasks | HAR 构建任务类型错误 |
index.ets 没有默认导出 | ArkTS 注册器找不到插件类 |
| HAR 模块名与依赖不一致 | ohpm 依赖解析失败 |
| 通道名不一致 | Dart 调用抛出 MissingPluginException |
四、ArkTS 插件的最小完整实现
JPushPlugin.ets 保留和 Dart 完全一致的通道名:
const CHANNEL = 'jpush';
const UNSUPPORTED = 'jpush_unsupported';
export default class JPushPlugin
implements FlutterPlugin, MethodCallHandler {
private channel: MethodChannel | null = null;
getUniqueClassName(): string {
return 'JPushPlugin';
}
onAttachedToEngine(binding: FlutterPluginBinding): void {
this.channel = new MethodChannel(
binding.getBinaryMessenger(),
CHANNEL,
);
this.channel.setMethodCallHandler(this);
}
onDetachedFromEngine(binding: FlutterPluginBinding): void {
if (this.channel !== null) {
this.channel.setMethodCallHandler(null);
this.channel = null;
}
}
方法分发只返回两类结果:
onMethodCall(call: MethodCall, result: MethodResult): void {
switch (call.method) {
case 'getPlatformVersion':
result.success('OHOS');
return;
case 'getSDKVersion':
result.success(
'jpush_flutter OHOS adapter 2.1.4-ohos.1',
);
return;
default:
result.error(
UNSUPPORTED,
`${call.method}: JPush SDK is not available on OpenHarmony.`,
null,
);
return;
}
}
Dart 侧新增两个轻量查询方法,示例和业务都能验证插件是否真正注册:
Future<String> getPlatformVersion() async {
final String? version =
await _channel.invokeMethod<String>('getPlatformVersion');
return version ?? 'Unknown';
}
Future<String> getSDKVersion() async {
final String? version =
await _channel.invokeMethod<String>('getSDKVersion');
return version ?? 'Unknown';
}
这段 ArkTS 分发的核心价值是让失败可诊断:
result.success只用于已经验证的平台能力。result.error携带稳定错误码,Dart 可以精准判断 OHOS 尚未接入。onDetachedFromEngine清理 handler,避免引擎重建后残留旧通道。- 不实现假的 Registration ID,也不返回伪造 Tag 列表。
五、Dart 层保持原调用方式
上游 JPush 继续使用静态单例,业务代码不需要为 OHOS 写另一套 API:
final JPush jpush = JPush();
final String platform = await jpush.getPlatformVersion();
debugPrint(platform); // OHOS
远端推送方法仍按上游方式调用,但 OHOS 会返回 PlatformException:
try {
final Map<dynamic, dynamic> tags = await jpush.setTags([
'openharmony',
'flutter',
]);
debugPrint('$tags');
} on PlatformException catch (error) {
if (error.code == 'jpush_unsupported') {
debugPrint('OHOS 尚未接入 JPush 原生 SDK');
} else {
rethrow;
}
}
这里刻意没有修改 Dart API 的签名。未来接入真实 OHOS SDK 时,只需要替换
ArkTS 分支,业务层不用迁移。
六、同步修复 Dart 和示例工程
适配过程中同时处理了几处会阻断当前工具链的问题:
LocalNotification构造参数从过时的@required改为required。- 示例中的
MaterialStateProperty更新为WidgetStateProperty。 - 清理示例未使用的
mockito、test和jmessage_flutter。 - 替换过时测试 API,使用
TestDefaultBinaryMessengerBinding注册 Mock 通道。 - 使用当前 Flutter OH 工具链生成
example/ohos。 - 增加
getPlatformVersion和getSDKVersion公开方法,并让示例首屏
显示真实注册结果。
根测试验证通道契约:
test('OHOS adapter exposes the jpush channel contract', () async {
expect(
await channel.invokeMethod<String>('getPlatformVersion'),
'OHOS',
);
expect(
await channel.invokeMethod<String>('getSDKVersion'),
contains('2.1.4-ohos.1'),
);
});
这类测试不能验证远端推送,但可以阻止通道名、版本号和插件分发被后续改动
意外破坏。
七、示例页面验证插件注册
示例保留上游的推送操作按钮,并通过状态区域展示平台调用结果:
final String version = await jpush.getPlatformVersion();
setState(() {
debugLabel = 'OHOS plugin: $version';
});
图 1:OpenHarmony 模拟器上的 jpush_flutter 示例首屏。页面已加载,插件
通道和示例按钮均可访问。
截图中的状态区显示插件注册结果,通知、Tag、Alias 和角标按钮仍然保留,
是因为它们展示上游能力边界,并不代表这些业务已经在 OHOS 上接通。点击后应看到稳定、可解释的
jpush_unsupported,而不是静默成功。
八、HAP 构建与测试
本次实际执行的核心命令:
flutter analyze
flutter test
cd example
flutter analyze
flutter test
flutter build hap --debug --no-codesign
验证结果:
| 检查项 | 结果 |
|---|---|
| 根包 analyze | 通过,No issues found |
| 根包测试 | 通过 |
| 示例 analyze | 通过,No issues found |
| 示例测试 | 通过 |
| HAP 构建 | 通过 |
| 产物 | entry-default-unsigned.hap |
安装和启动命令:
hdc install -r \
example/build/ohos/hap/entry-default-unsigned.hap
hdc shell aa start \
-a EntryAbility \
-b com.example.jpush_example
最终验证中的真实日志:
start ability successfully.
10-19 01:08:51.405 5205 5205 D ... Flutter:
FlutterNapi --> called onFirstFrame isPreload:0
进程 5205 在首帧后稳定存活,验证没有停留在“构建成功但启动即退出”。
九、常见问题与定位顺序
1. MissingPluginException
按以下顺序检查:
pubspec.yaml是否存在ohos.pluginClass。example/ohos的生成插件注册文件是否包含JPushPlugin。index.ets是否默认导出同一个类。- ArkTS 和 Dart 的通道是否都叫
jpush。
2. HAP 能安装但启动失败
先卸载旧包,再安装当前构建。不同 Flutter Engine 和插件 HAR 混装可能在
插件注册阶段崩溃。验证日志必须检查 onFirstFrame,仅 aa start 返回
成功不足以证明首帧完成。
十、后续适配路线
- 接入或实现可验证的 JPush OHOS 原生 SDK。
- 实现 Registration ID、setup、Tag 和 Alias。
- 接入通知授权、本地通知和通知点击事件。
- 增加 OHOS 通知事件的 EventChannel 或方法回传。
十一、目录结构
jpush-flutter-plugin_ohos/
├── lib/jpush_flutter.dart
├── ohos/
│ ├── build-profile.json5
│ ├── hvigorfile.ts
│ ├── index.ets
│ └── src/main/ets/components/plugin/JPushPlugin.ets
├── example/
│ ├── lib/main.dart
│ └── ohos/
├── test/jpush_flutter_test.dart
├── photos/jpush_ohos.jpeg
├── verification.md
├── CHANGELOG.md
└── README.md
十二、总结
这次适配没有把“能编译”当作最终结果,而是建立了完整证据链:
pubspec OHOS 声明
|
v
HAR 构建和 index.ets 导出
|
v
GeneratedPluginRegistrant 注册
|
v
MethodChannel("jpush") 分发
|
v
analyze + test + HAP build
|
v
hdc 安装 + aa start + onFirstFrame + 进程存活
对于没有原生 OHOS SDK 的推送能力,正确结果不是返回假成功,而是保留统一
API、给出稳定错误码,并把真实 SDK 接入列为明确的下一步。
AtomGit 目标仓库:https://atomgit.com/oh-flutter/jpush-flutter-plugin,当前状态:已推送到 main。
欢迎加入 CPF-Flutter 社区,一起交流
Flutter 三方库 OpenHarmony 适配、HAP 构建和模拟器/真机验证经验:
https://atomgit.com/CPF-Flutter
更多推荐



所有评论(0)