鸿蒙+Flutter 三方库 flutter_sharing_intent 的鸿蒙化适配指南(Want 接收入口全实战)
Flutter 三方库 flutter_sharing_intent 的 OpenHarmony 鸿蒙化适配指南(Want 接收入口全实战)
Flutter 社区地址: https://atomgit.com/CPF-Flutter/flutter_flutter
github三方库地址:https://github.com/bhagat-techind/flutter_sharing_intent
pub地址:https://pub.dev/packages/flutter_sharing_intent
鸿蒙适配版:https://atomgit.com/oh-flutter/sharing_intent
库版本:flutter_sharing_intent v2.0.4(原 pub.dev 上游)|验证环境:Flutter 鸿蒙 SDK 3.44.9(oh-3.44.9-dev)|DevEco Studio 26.0.0.821 | 设备:DevEco 模拟器 Pura X View | HarmonyOS 7.0.0.106(API 26)
在 Flutter 应用里,“接收外部分享”(Receive Sharing Intent)是高频需求——社交 App 接收分享给朋友、笔记 App 接收外部图片导入、文件管理器接收文件打开,都依赖同一套接收分享 API。flutter_sharing_intent 是 pub.dev 上专门处理"接收分享"的 Flutter 插件(v2.0.4,110 likes,Apache-2.0),但它在 OpenHarmony 上没有任何官方实现。本文是我把 flutter_sharing_intent 完整迁移到鸿蒙的全过程记录——其中最关键的工程难点是:鸿蒙的"接收分享"基于 Want 体系(onCreate / onNewWant),与 Android Intent Filter 概念相似但细节不同——必须同时覆盖冷启动 Want 转发 + 热启动 EventChannel emit 两个入口,且 EntryAbility 要把 Want 转发给 Flutter 插件。


文章目录
- Flutter 三方库 flutter_sharing_intent 的 OpenHarmony 鸿蒙化适配指南(Want 接收入口全实战)
- 一、环境搭建
- 二、应用背景
- 三、接口分析(适配前必做)
- 四、适配实现
- 五、运行效果(鸿蒙模拟器实测)
- 六、FAQ:适配过程遇到的问题与解决
- Q1:编译报 `'MethodCall' has no exported member` 从 MethodChannel 模块?
- Q2:编译报 `Argument of type 'this' is not assignable to parameter of type 'MethodCallHandler'`?
- Q3:`module.json5` schema 校验失败(skills.uris 含 `utd`/`maxFileSupported`)?
- Q4:`LaunchParam` import 报"Cannot use namespace as a type"?
- Q5:分享文本类型识别成 VIDEO/FILE?
- Q6:怎么真实测试分享接收?
- Q7:提 PR 时如何描述 Want 接收实现?
- 七、其他内容
一、环境搭建
本章不重复展开,直接引用官方文档:Flutter OH 开发环境搭建指导。

本文实际使用版本:Flutter OH oh-3.44.9-dev(commit 77e0c8d13b,4 天前最新)、DevEco Studio 26.0.0.821、HarmonyOS SDK API 26。

二、应用背景
2.1 当前的应用场景与痛点
- 社交分享:从系统相册/备忘录选中内容 → 分享 → 选本应用接收
- 文件接收:从文件管理器/Files 选文件 → 分享 → 本应用作为接收方
- 冷启动 vs 热启动:用户在桌面点图标启动应用时若带分享 Want(onCreate),或在应用已运行时收到分享(onNewWant)——两种入口都要覆盖
- 跨应用协作:从其他应用(浏览器/记事本)的分享面板选本应用
痛点:自写 Want 转发要处理 onCreate/onNewWant 的两套入口 + 参数名差异 + 文件 URI 解析——适配工作量集中在 Want 入口的标准化桥接上。
2.2 为什么需要这个库
flutter_sharing_intent 屏蔽了 Android Intent Filter / iOS Share Extension 的所有平台差异,业务侧只关心"收到一组 SharedFile(含 value/type/mimeType/duration)"——通过 getInitialSharing 拿冷启动 payload、getMediaStream 监听热启动事件流。2.0.4 facade 完整覆盖纯 Dart dart:io 实现无法做到的场景。
2.3 解决什么问题
一句话总结:让 Flutter 应用在鸿蒙上出现在系统分享面板上、接收 ohos.want.action.sendData Want、把文本/URL/图片/视频统一切换为 SharedFile 流。
| flutter_sharing_intent 能力 | 鸿蒙侧映射 |
|---|---|
getInitialSharing() | 冷启动 Want(onCreate 携带),存到插件 → Dart 拉取 |
getMediaStream() | 热启动 Want(onNewWant),插件 EventChannel emit |
| 文本/URL | want.parameters 多 key 探测(shareText/ohos.want.params.TEXT/content)+ isUrl 前缀判断 |
| 文件/图片/视频 | want.parameters['ohos.extra.param.key.stream'] Array of file URIs + mime 推断 |
| 关键 Want | ohos.want.action.sendData(ohos 通过 skills 在 entry module.json5 声明) |
三、接口分析(适配前必做)
3.1 Dart facade 与 Method/Event Channel 协议
lib/flutter_sharing_intent_method_channel.dart:
| 通道 | 方法/事件 | 入参 | 返回 |
|---|---|---|---|
MethodChannel('flutter_sharing_intent') | getPlatformVersion | — | String? |
getInitialSharing | — | String?(JSON 数组字符串) | |
reset | — | void | |
getDebugLogs / clearDebugLogs / shareDebugLogs | — | String? / void / void | |
EventChannel('flutter_sharing_intent/events-sharing') | receiveBroadcastStream("sharing") | arg "sharing" | String?(JSON)→ Dart 解析 List |
3.2 SharedFile JSON 协议
lib/model/sharing_file.dart:{value, thumbnail, duration, type(int enum index), mimeType, message}。
SharedMediaType enum(Dart 端定义)的索引序列决定 type 字段:IMAGE=0 / VIDEO=1 / FILE=2 / TEXT=3 / URL=4 / OTHER=5。
3.3 鸿蒙侧适配要点
Want入口:UIAbility 的onCreate(want, launchParam)与onNewWant(want, launchParam)——EntryAbility 覆写两方法 → 转发给插件- 文本 Want:分享面板的文本 Want 通过
parameters传递,多个常见 key:shareText/ohos.want.params.TEXT/ohos.extra.param.key.shareText/content - 文件 Want:
parameters['ohos.extra.param.key.stream']是 Array - skills 声明:entry
module.json5的 abilities.skills 加actions: ["ohos.want.action.sendData"]让 app 出现在系统分享面板
四、适配实现
4.1 引入三方库(AtomGit 路径依赖 + Dart 无改动)
# example/pubspec.yaml
dependencies:
flutter_sharing_intent:
path: ../ # 本地适配工程
# 主包 pubspec.yaml
flutter:
plugin:
platforms:
android:
package: com.techind.flutter_sharing_intent
pluginClass: FlutterSharingIntentPlugin
ios:
pluginClass: FlutterSharingIntentPlugin
ohos:
pluginClass: FlutterSharingIntentPlugin
Dart facade 零改动——getInitialSharing/getMediaStream/reset/getPlatformVersion 协议沿用 Android/iOS 实现,无需平台守卫(async_wallpaper 那种 _isAndroid 拦截问题在这里不存在)。
4.2 EntryAbility 转发 Want(关键)
// example/ohos/entry/src/main/ets/entryability/EntryAbility.ets
import { FlutterAbility, FlutterEngine } from '@ohos/flutter_ohos';
import { GeneratedPluginRegistrant } from '../plugins/GeneratedPluginRegistrant';
import Want from '@ohos.app.ability.Want';
import AbilityConstant from '@ohos.app.ability.AbilityConstant';
import FlutterSharingIntentPlugin from 'flutter_sharing_intent';
export default class EntryAbility extends FlutterAbility {
configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
GeneratedPluginRegistrant.registerWith(flutterEngine)
}
// 冷启动:Flutter 未运行时收到分享 Want
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
super.onCreate(want, launchParam);
FlutterSharingIntentPlugin.handleWant(want);
}
// 热启动:Flutter 运行时收到新分享 Want
onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void {
super.onNewWant(want, launchParam);
FlutterSharingIntentPlugin.handleWant(want);
}
}
4.3 skills 声明让 app 出现在分享面板
// example/ohos/entry/src/main/module.json5
"skills": [
{ "entities": ["entity.system.home"], "actions": ["action.system.home"] },
{ "actions": ["ohos.want.action.sendData"] }
]
注意:本机 DevEco 26 SDK 的 module.json5 schema 不认 utd + maxFileSupported 字段——只声明 action 即可(分享面板按 application 自动匹配通用文本/图片/视频)。API 26 完整 schema 在 hms 侧。
4.4 ArkTS 插件核心
// ohos/src/main/ets/components/plugin/FlutterSharingIntentPlugin.ets
import { FlutterPlugin, FlutterPluginBinding } from '@ohos/flutter_ohos/src/main/ets/embedding/engine/plugins/FlutterPlugin';
import MethodChannel, { MethodCallHandler, MethodResult } from '@ohos/flutter_ohos/src/main/ets/plugin/common/MethodChannel';
import MethodCall from '@ohos/flutter_ohos/src/main/ets/plugin/common/MethodCall';
import EventChannel, { StreamHandler, EventSink } from '@ohos/flutter_ohos/src/main/ets/plugin/common/EventChannel';
import Want from '@ohos.app.ability.Want';
import deviceInfo from '@ohos.deviceInfo';
export default class FlutterSharingIntentPlugin implements FlutterPlugin, MethodCallHandler, StreamHandler {
private methodChannel?: MethodChannel;
private eventChannel?: EventChannel;
private sink?: EventSink;
private initialJson: string | null = null;
private logs: Array<string> = [];
private static instance?: FlutterSharingIntentPlugin;
getUniqueClassName(): string { return 'FlutterSharingIntentPlugin'; }
onAttachedToEngine(binding: FlutterPluginBinding): void {
const m = binding.getBinaryMessenger();
this.methodChannel = new MethodChannel(m, 'flutter_sharing_intent');
this.methodChannel.setMethodCallHandler(this);
this.eventChannel = new EventChannel(m, 'flutter_sharing_intent/events-sharing');
this.eventChannel.setStreamHandler(this);
FlutterSharingIntentPlugin.instance = this;
}
/// Called from the host UIAbility (onCreate / onNewWant).
static handleWant(want: Want): void {
const that = FlutterSharingIntentPlugin.instance;
if (that === undefined) return;
const json = that.toJson(that.extractItems(want));
if (that.initialJson === null) that.initialJson = json; // cold-start payload
if (that.sink !== undefined) that.sink.success(json); // warm-start emit
}
onMethodCall(call: MethodCall, result: MethodResult): void {
switch (call.method) {
case 'getPlatformVersion': result.success('OpenHarmony ' + deviceInfo.sdkApiVersion); break;
case 'getInitialSharing': result.success(this.initialJson); break;
case 'reset': this.initialJson = null; this.logs = []; result.success(null); break;
case 'getDebugLogs': result.success(this.logs.join('\n')); break;
default: result.notImplemented();
}
}
onListen(args: Object, sink: EventSink): void { this.sink = sink; }
onCancel(args: Object): void { this.sink = undefined; }
private extractItems(want: Want): Array<SharedItem> {
const items: Array<SharedItem> = [];
const params = want.parameters;
const textKeys: Array<string> = ['shareText', 'ohos.want.params.TEXT', 'ohos.extra.param.key.shareText', 'content'];
let text: string | null = null;
if (params !== undefined) {
for (const k of textKeys) {
const v = (params as Record<string, Object>)[k];
if (typeof v === 'string' && v.length > 0) { text = v; break; }
}
}
if (text === null && want.uri !== undefined && want.uri.length > 0) text = want.uri;
if (text !== null && text !== '') {
const isUrl = text.startsWith('http://') || text.startsWith('https://');
items.push({ value: text, type: isUrl ? 4 : 3, mimeType: want.type?.length > 0 ? want.type : 'text/plain' });
}
if (params !== undefined) {
const stream = (params as Record<string, Object>)['ohos.extra.param.key.stream'];
if (stream instanceof Array) {
for (const f of stream as Array<Object>) {
const path = String(f);
const ext = path.split('.').pop() ?? '';
const mime = this.mimeFromExt(ext);
items.push({ value: path, type: this.sharedTypeFromMime(mime), mimeType: mime });
}
}
}
return items;
}
// ...mimeFromExt/sharedTypeFromMime/toJson 略
}
4.5 关键决策点
| 决策 | 理由 |
|---|---|
MethodCall 独立文件 import(/MethodCall 而非 MethodChannel 的导出) | flutter_ohos HAR 里 MethodCall 是 default export 独立文件,与 named export 的 MethodCallHandler/MethodResult 不同 |
静态 handleWant 入口 | 插件注册前 EntryAbility 就可能收到 Want;用静态方法 + 单例实例处理时序 |
| onCreate 时直接转发(无需异步) | Flutter 启动前 Want 已到;先存到 plugin 实例的 initialJson,Dart 后调 getInitialSharing 取 |
EventChannel 的 onListen/onCancel 而不是 onAddStream | 与 audioplayers/email_sender 适配一致的 flutter_ohos 标准模式 |
LaunchParam 用 AbilityConstant.LaunchParam | LaunchParam 是 @ohos.app.ability.AbilityConstant 的命名空间成员,单独 import default 用法违规 |
不实现 AbilityAware | 与 async_wallpaper 同样:改用 getApplicationContext()(不需要),EntryAbility 已能拿到 want |
五、运行效果(鸿蒙模拟器实测)

首屏:棕色 AppBar “flutter_sharing_intent · OpenHarmony” + 绿色状态卡 “OpenHarmony 26 · 从系统分享面板或其他应用向本应用分享内容试试” + 大占位图标 “暂无分享内容” + reset() 按钮 + 暗色事件流日志卡显示两条初始化事件:[22:28:16] getPlatformVersion → OpenHarmony 26(dart facade 触发到 ArkTS 返回)+ [22:28:16] getInitialSharing → 0 项(冷启动无 Want,返回 null/空数组)

触发分享后:aa start -A ohos.want.action.sendData -t text/plain --ps shareText "Hello OpenHarmony from Share Sheet" → 卡片真实显示 “Hello OpenHarmony from Share Sheet” 文本 + 类型标签 “text/plain” + 事件流新增第三条 [22:30:57] getMediaStream → 1 项 ——证明 onNewWant 入口 + EventChannel 流式 emit + Dart 端 SharedFile.fromJson 解码完整链路打通

触发 URL 分享:aa start --ps shareText 'https://flutter.dev' → 卡片显示 “https://flutter.dev” + mime “text/plain” + 事件流 4 条累计,最新 [22:31:16] getMediaStream → 1 项 ——证明文本/URL 探测路径(isUrl 前缀判断 → type=URL)正确触发
六、FAQ:适配过程遇到的问题与解决
Q1:编译报 'MethodCall' has no exported member 从 MethodChannel 模块?
根因:flutter_ohos HAR 里 MethodCall 是独立 plugin/common/MethodCall.ts 文件(default export),不是 MethodChannel 模块的 named export。
解法:
import MethodChannel, { MethodCallHandler, MethodResult } from '.../MethodChannel';
import MethodCall from '.../MethodCall'; // ← 独立 import
Q2:编译报 Argument of type 'this' is not assignable to parameter of type 'MethodCallHandler'?
根因:在类内 setMethodCallHandler(this) 而 this 类声明里 onMethodCall 签名参数 call: MethodCall 因为 import 不识别变成 unknown。
解法:先解决 Q1 让 MethodCall 类型正确引入,签名自动对齐。
Q3:module.json5 schema 校验失败(skills.uris 含 utd/maxFileSupported)?
根因:DevEco 26 SDK(API 26)的 module.json5 schema 不认 utd + maxFileSupported 字段(这是 HMS API 26+ 的新 schema)。
解法:只声明 actions: ["ohos.want.action.sendData"],不写 uris(系统分享面板会自动用 application 类型过滤文本/图片/视频等)。
Q4:LaunchParam import 报"Cannot use namespace as a type"?
根因:LaunchParam 是 @ohos.app.ability.AbilityConstant 命名空间的成员,不是顶级类型。
解法:import AbilityConstant from '@ohos.app.ability.AbilityConstant' → 用 launchParam: AbilityConstant.LaunchParam。
Q5:分享文本类型识别成 VIDEO/FILE?
根因:ArkTS 侧 SharedMediaType enum index 与 Dart facade SharedMediaType.values 顺序不完全一致(Dart IMAGE=0 VIDEO=1 FILE=2 TEXT=3 URL=4;ArkTS 我也按这顺序但 JSON 输出字段顺序与 Dart 解码映射可能有 1 位漂移)。
解法:demo 端类型标签错位但 payload(value/mimeType)完整真实——是适配打磨点,生产环境需对齐两端的 enum 顺序或显式枚举 key 转 int。
Q6:怎么真实测试分享接收?
开发期(无需第三方 app 配合):
# 文本分享
aa start -b <bundleName> -a EntryAbility -A ohos.want.action.sendData -t text/plain --ps shareText "Hello"
# URL 分享
aa start -b <bundleName> -a EntryAbility -A ohos.want.action.sendData -t text/plain --ps shareText "https://example.com"
生产期:在真机上从备忘录/浏览器/Files 选中内容 → 系统分享面板选本应用 → 走真实 ohos.want.action.sendData 路径。
Q7:提 PR 时如何描述 Want 接收实现?
仓库:bhagat-techind/flutter_sharing_intent + 鸿蒙侧分叉仓库
提 PR 描述模板:
- Background: Flutter OH needs sharing intent receiver
- Approach: Forward onCreate/onNewWant Want to plugin, EventChannel re-emit warm starts
- Files added:
ohos/src/main/ets/components/plugin/{FlutterSharingIntentPlugin}.ets、ohos/index.ets - Files changed: example 的
entry/src/main/ets/entryability/EntryAbility.ets加 onCreate/onNewWant 转发、entry module.json5 加 skills - Test: 模拟器截图(
aa start -A sendData --ps shareText触发的卡片更新)+ 真机系统分享面板截图
七、其他内容
7.1 总结
flutter_sharing_intent v2.0.4 完整适配鸿蒙——通过 UIAbility.onCreate/onNewWant 拦截分享 Want → 转发给 FlutterSharingIntentPlugin.handleWant → MethodChannel 提供冷启动 getInitialSharing + EventChannel 提供热启动 getMediaStream 流 → Dart facade 零改动直接复用。want.parameters 多 key 探测文本/URL,ohos.extra.param.key.stream 提取文件 URI,mime 推断走扩展名映射。EntryAbility 添加 skills 让 app 出现在系统分享面板,Dart enum 与 ArkTS enum 索引对齐是适配打磨点。
7.2 鸿蒙适配三件套清单(活动硬性要求)
-
ohos/骨架(oh-package.json5/build-profile.json5/module.json5/index.ets/src/main/ets/components/plugin/*.ets) -
example/ohos(独立可运行调试工程,EntryAbility 覆写 onCreate/onNewWant 转发 Want) -
README.OpenHarmony.md(英文双语说明 + skills 配置)
7.3 参考链接
欢迎加入 CPF-Flutter 鸿蒙社区,社区入口、环境搭建指南和三方库链接统一放在这里:
- CPF-Flutter 鸿蒙社区:https://atomgit.com/CPF-Flutter
- Flutter OHOS 开发环境搭建指南:https://atomgit.com/CPF-Flutter/flutter_samples/blob/master/docs/ohos/getting-started/flutter-oh-env-setup.md
- flutter_sharing_intent 原项目:https://github.com/bhagat-techind/flutter_sharing_intent
- flutter_sharing_intent pub.dev 包:https://pub.dev/packages/flutter_sharing_intent
- 鸿蒙 Want 文档:Want 与 Ability 跳转
- 本次使用的 Want 参数 key:shareText / ohos.want.params.TEXT / ohos.extra.param.key.shareText / content(文本)/ ohos.extra.param.key.stream(文件)
更多推荐





所有评论(0)