在移动应用开发领域,跨平台分享功能一直是刚需但实现起来颇为棘手的环节。Flutter生态中的share_plus库作为社区广泛使用的分享插件,长期以来主要服务于Android和iOS平台。随着鸿蒙系统的快速崛起,开发者们面临着一个现实问题:如何让现有Flutter应用在鸿蒙设备上也能保持完整的分享能力?
这个适配项目的核心价值在于解决三个关键问题:
鸿蒙虽然兼容Android应用,但其原生能力接口存在显著区别。分享功能在鸿蒙上主要通过Ability和Intent两种机制实现:
dart复制// 鸿蒙Ability调用示例
var intent = new Intent();
Operation operation = new Intent.OperationBuilder()
.withAction(Intent.ACTION_SEND)
.build();
intent.setOperation(operation);
intent.setType("text/plain");
intent.setStringParam(Intent.EXTRA_TEXT, shareContent);
startAbility(intent);
关键差异点:
鸿蒙的权限声明需要在config.json中配置:
json复制{
"module": {
"reqPermissions": [
{
"name": "ohos.permission.DISTRIBUTED_DATASYNC",
"reason": "跨设备分享需要"
}
]
}
}
采用平台通道(Platform Channel)+条件编译的方案:
code复制lib/
├── share_plus.dart # 统一接口层
├── src/
│ ├── share_plus_android.dart
│ ├── share_plus_ios.dart
│ └── share_plus_harmony.dart # 新增鸿蒙实现
鸿蒙平台实现类关键代码:
dart复制class SharePlusHarmony implements SharePlusPlatform {
@override
Future<void> share(
String text, {
String? subject,
Rect? sharePositionOrigin,
}) async {
final Intent intent = Intent();
final Operation operation = OperationBuilder()
.withAction(Intent.ACTION_SEND)
.build();
intent.setOperation(operation)
..setType("text/plain")
..setStringParam(Intent.EXTRA_TEXT, text)
..setStringParam(Intent.EXTRA_SUBJECT, subject ?? '');
try {
await FlutterHarmonyAppBundle.startAbility(intent);
} on PlatformException catch (e) {
throw ShareException(e.message ?? '分享失败');
}
}
}
鸿蒙的文件URI需要特殊处理:
dart复制String _convertFileUri(String filePath) {
if (Platform.isHarmonyOS) {
return 'ohos.global.uri://file$filePath';
}
return filePath;
}
bash复制npm install -g @ohos/hpm-cli
hpm install @ohos/hvigor
yaml复制# pubspec.yaml
dependencies:
share_plus: ^6.3.0
flutter_harmony: ^0.4.0 # 鸿蒙插件
在鸿蒙入口注册MethodChannel:
dart复制// lib/main_harmony.dart
void main() {
SharePlusHarmony.registerWith();
runApp(MyApp());
}
修改harmony/config.json:
json复制{
"app": {
"bundleName": "com.example.app",
"vendor": "example",
"version": {
"code": 1,
"name": "1.0.0"
}
},
"deviceConfig": {
"default": {
"abilities": [
{
"name": "ShareAbility",
"type": "page",
"visible": true
}
]
}
}
}
现象:分享时设备选择器不显示附近鸿蒙设备
解决方案:
dart复制void _checkDistributedPermission() async {
final bool granted = await PermissionHandler()
.checkPermissionStatus(Permission.distributedData);
if (!granted) {
await PermissionHandler()
.requestPermissions([Permission.distributedData]);
}
}
处理方案:使用鸿蒙的ImagePacker转换图片格式
dart复制Future<Uint8List> _convertImage(File file) async {
final ImagePacker packer = ImagePacker.createImagePacker();
final PackingOptions options = PackingOptions();
options.format = 'image/jpeg';
options.quality = 90;
return await packer.packImage(file.path, options);
}
dart复制class SharePlusHarmony {
static bool _isHarmonyInitialized = false;
Future<void> _initialize() async {
if (!_isHarmonyInitialized) {
await FlutterHarmonyAppBundle.initialize();
_isHarmonyInitialized = true;
}
}
}
dart复制void _setupShareResultListener() {
const EventChannel('plugins.flutter.io/share_plus_harmony/events')
.receiveBroadcastStream()
.listen((event) {
debugPrint('分享结果: $event');
}, onError: (error) {
debugPrint('分享监听错误: $error');
});
}
dart复制void main() {
test('鸿蒙文本分享', () async {
final mockChannel = MockMethodChannel();
SharePlusHarmony.channel = mockChannel;
when(mockChannel.invokeMethod<void>('share', any))
.thenAnswer((_) => Future.value());
await SharePlusHarmony().share('测试文本');
verify(mockChannel.invokeMethod('share', {
'text': '测试文本',
'subject': null,
})).called(1);
});
}
基础功能测试:
边界测试:
分布式测试:
dart复制String _getShareIntentAction() {
if (HarmonyPlatform.version >= 3.0) {
return 'ohos.intent.action.SEND_MULTIPLE';
} else {
return 'ohos.intent.action.SEND';
}
}
当鸿蒙分享不可用时自动回退到系统分享:
dart复制Future<void> shareWithFallback(String text) async {
try {
await SharePlusHarmony().share(text);
} catch (e) {
debugPrint('鸿蒙分享失败,回退系统分享: $e');
await SharePlus().share(text);
}
}
dart复制Future<void> shareWithMenu(
String text, {
required List<ShareMenuItem> items,
}) async {
final Intent intent = Intent();
intent.setOperation(OperationBuilder()
.withAction('ohos.intent.action.CHOOSER')
.build());
intent.setStringParam(Intent.EXTRA_TEXT, text);
intent.setListParam(
'ohos.intent.extra.CHOOSER_ITEMS',
items.map((item) => item.toHarmonyMap()).toList(),
);
await FlutterHarmonyAppBundle.startAbility(intent);
}
dart复制@override
Future<ShareResult> shareWithResult(String text) async {
final Completer<ShareResult> completer = Completer();
final callbackId = _nextCallbackId++;
_callbacks[callbackId] = completer;
try {
await channel.invokeMethod('shareWithResult', {
'text': text,
'callbackId': callbackId,
});
return await completer.future;
} finally {
_callbacks.remove(callbackId);
}
}
修改pubspec.yaml:
yaml复制flutter:
plugin:
platforms:
android:
package: com.example.share_plus
pluginClass: SharePlusPlugin
ios:
pluginClass: SharePlusPlugin
harmony:
pluginClass: SharePlusHarmonyPlugin
bash复制flutter pub add share_plus_harmony
dart复制void main() {
if (Platform.isHarmonyOS) {
SharePlusHarmony.initialize();
}
runApp(MyApp());
}
dart复制Share.share('来自鸿蒙的分享内容');
测试环境:MatePad Pro 12.6 (HarmonyOS 3.0)
| 操作类型 | 原生实现(ms) | 适配后(ms) | 开销占比 |
|---|---|---|---|
| 文本分享 | 120 | 145 | +20% |
| 图片分享(1MB) | 210 | 250 | +19% |
| 多文件分享 | 380 | 420 | +10.5% |
| 跨设备分享 | 520 | 550 | +5.8% |
优化建议:
| share_plus版本 | HarmonyOS支持 | 备注 |
|---|---|---|
| 6.3.0+ | 2.0+ | 基础分享功能 |
| 7.0.0+ | 3.0+ | 支持分布式分享 |
| 7.2.0+ | 3.1+ | 支持分享菜单定制 |
建立鸿蒙专属issue模板:
markdown复制## 环境信息
- 设备型号:
- HarmonyOS版本:
- Flutter版本:
- share_plus版本:
## 问题描述
## 重现步骤
## 预期行为
## 实际行为
## 日志输出
鸿蒙代码遵循OpenHarmony编码规范:
Dart层接口保持与原生share_plus一致:
dart复制/// 保持与主库相同的API签名
@override
Future<void> shareFiles(
List<String> paths, {
List<String>? mimeTypes,
String? subject,
String? text,
Rect? sharePositionOrigin,
}) async {
// 鸿蒙具体实现
}
新增代码必须满足:
测试示例:
dart复制test('分享空文本应抛出异常', () async {
expect(
() => SharePlusHarmony().share(''),
throwsA(isA<ShareEmptyContentException>()),
);
});
某头部电商App的实践:
dart复制void shareProduct(Product product) {
final card = buildHarmonyShareCard(
title: product.name,
content: product.desc,
imageUrl: product.cover,
deepLink: 'harmony://product/${product.id}',
);
SharePlusHarmony().share(card);
}
处理高频分享场景的优化:
dart复制class ShareService {
static final _intentPool = List<Intent>.generate(
5,
(_) => Intent()..setOperation(_baseOperation),
);
Future<void> _shareWithPool(String text) async {
final intent = _intentPool.removeLast();
intent.setStringParam(Intent.EXTRA_TEXT, text);
try {
await _startAbility(intent);
} finally {
intent.removeParam(Intent.EXTRA_TEXT);
_intentPool.add(intent);
}
}
}
dart复制// 根据设备能力自动选择最佳分享方式
void smartShare(ShareContent content) {
if (device.capabilities.contains('harmony.distributed')) {
_distributedShare(content);
} else if (device.capabilities.contains('android.intent')) {
_intentShare(content);
} else {
_fallbackShare(content);
}
}
dart复制class ShareTracker {
final _analytics = ShareAnalytics();
void trackShareFlow(ShareFlow flow) {
_analytics.logEvent('share_start', flow.metadata);
Timer.periodic(Duration(seconds: 1), (timer) {
_analytics.logEvent('share_heartbeat', {
'duration': timer.tick,
'flow_id': flow.id,
});
});
flow.onComplete.then((_) {
_analytics.logEvent('share_success', flow.result);
timer.cancel();
});
}
}
在完成这套适配方案后,我们发现鸿蒙平台的分享能力实际上比传统Android Intent更加灵活,特别是在分布式场景下。一个实用的建议是:在处理大文件分享时,可以优先检查设备间的网络连接质量,如果发现是低速网络连接,自动触发文件压缩转换,这能显著提升跨设备分享的成功率。