Flutter for OpenHarmony三方库适配实战:share_plus 分享功能
分享功能是移动应用中常见的社交特性,用户可以将文本、链接、图片、文件等内容分享到其他应用。在 Flutter for OpenHarmony 应用开发中,share_plus是一个功能强大的分享插件,提供了完整的跨平台分享能力。share_plus 库为 Flutter for OpenHarmony 开发提供了完整的分享功能。通过简洁的 API,开发者可以轻松实现文本、URL、图片、文件的分享。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
本文基于flutter3.27.5开发
一、share_plus 库概述
分享功能是移动应用中常见的社交特性,用户可以将文本、链接、图片、文件等内容分享到其他应用。在 Flutter for OpenHarmony 应用开发中,share_plus 是一个功能强大的分享插件,提供了完整的跨平台分享能力。
share_plus 库特点
share_plus 库基于 Flutter 平台接口实现,提供了以下核心特性:
多类型分享:支持分享文本、URL、图片、文件等多种类型的内容,满足各种分享场景需求。
系统分享面板:调用系统原生分享面板,用户可以选择任意支持的应用进行分享,体验一致流畅。
分享结果反馈:提供分享结果回调,可以获知用户是完成了分享还是取消了操作。
多文件分享:支持同时分享多个文件,并提供 MIME 类型设置。
功能支持对比
| 功能 | Android | iOS | OpenHarmony |
|---|---|---|---|
| 分享文本 | ✅ | ✅ | ✅ |
| 分享 URL | ✅ | ✅ | ✅ |
| 分享图片 | ✅ | ✅ | ✅ |
| 分享文件 | ✅ | ✅ | ✅ |
| 多文件分享 | ✅ | ✅ | ✅ |
| 分享结果 | ✅ | ✅ | ✅ |
| 分享位置 | ✅ | ✅ | ✅ |
使用场景:分享文本内容、分享网页链接、分享图片到社交应用、分享文件到其他应用等。
二、安装与配置
2.1 添加依赖(完整代码中使用到了其他库,具体请看完整代码部分)
在项目的 pubspec.yaml 文件中添加 share_plus 依赖:
dependencies:
share_plus:
git:
url: https://atomgit.com/openharmony-sig/flutter_plus_plugins.git
path: packages/share_plus/share_plus
然后执行以下命令获取依赖:
flutter pub get
2.2 兼容性信息
| 项目 | 版本要求 |
|---|---|
| Flutter SDK | 3.7.12-ohos-1.0.6 |
| OpenHarmony SDK | 5.0.0 (API 12) |
| DevEco Studio | 5.0.13.200 |
| ROM | 5.1.0.120 SP3 |
2.3 权限配置
share_plus 在 OpenHarmony 平台上不需要额外权限配置,系统分享面板会自动处理相关权限。
三、核心 API 详解
3.1 Share.share 方法
Share.share 是最基础的分享方法,用于分享文本内容。
static Future<void> share(
String text, {
String? subject,
Rect? sharePositionOrigin,
})
参数说明:
text 参数是要分享的文本内容,不能为空。
subject 参数是可选的主题,当用户选择邮件分享时会作为邮件主题使用。
sharePositionOrigin 参数用于指定分享面板的弹出位置,在 iPad 和 Mac 上有效。
使用示例:
await Share.share('这是一段要分享的文本内容');
3.2 Share.shareUri 方法
Share.shareUri 用于分享 URL 链接。
static Future<void> shareUri(Uri uri)
参数说明:
uri 参数是要分享的 URI 对象。
使用示例:
await Share.shareUri(Uri.parse('https://flutter.dev'));
在 iOS 上,系统会自动获取网页的图标和预览信息显示在分享面板中。
3.3 Share.shareXFiles 方法
Share.shareXFiles 用于分享一个或多个文件。
static Future<ShareResult> shareXFiles(
List<XFile> files, {
String? subject,
String? text,
Rect? sharePositionOrigin,
})
参数说明:
files 参数是要分享的文件列表,使用 XFile 对象表示。
subject 参数是可选的主题。
text 参数是可选的附加文本。
sharePositionOrigin 参数用于指定分享面板的弹出位置。
返回值:返回 ShareResult 对象,包含分享结果状态。
使用示例:
final List<XFile> files = [
XFile('/path/to/image.jpg', name: 'image.jpg', mimeType: 'image/jpeg'),
];
await Share.shareXFiles(files, text: '分享图片');
3.4 Share.shareWithResult 方法
Share.shareWithResult 用于分享文本并获取分享结果。
static Future<ShareResult> shareWithResult(
String text, {
String? subject,
Rect? sharePositionOrigin,
})
返回值:返回 ShareResult 对象,包含分享结果状态。
使用示例:
final result = await Share.shareWithResult('分享内容');
if (result.status == ShareResultStatus.success) {
print('分享成功');
} else if (result.status == ShareResultStatus.dismissed) {
print('用户取消分享');
}
3.5 ShareResult 类
ShareResult 类包含分享操作的结果信息。
class ShareResult {
final String raw;
final ShareResultStatus status;
}
属性说明:
raw 属性是平台返回的原始结果,空字符串表示用户取消分享。
status 属性是分享结果状态枚举。
3.6 ShareResultStatus 枚举
ShareResultStatus 枚举定义了分享结果的状态。
ShareResultStatus.success 表示用户选择了某个分享动作并完成分享。
ShareResultStatus.dismissed 表示用户取消了分享操作。
ShareResultStatus.unavailable 表示状态无法确定,通常表示平台不支持返回分享结果。
3.7 XFile 类
XFile 类用于表示要分享的文件。
XFile(
String path, {
String? name,
String? mimeType,
})
参数说明:
path 参数是文件的路径。
name 参数是文件名,可选。
mimeType 参数是文件的 MIME 类型,可选。
静态方法:
XFile.fromData(Uint8List bytes, {String? name, String? mimeType}) 从字节数据创建文件。
四、实战案例
4.1 分享文本
Future<void> shareText() async {
await Share.share(
'这是一段要分享的文本内容,可以包含任意文字。',
subject: '分享主题',
);
}
4.2 分享 URL
Future<void> shareUrl() async {
final Uri url = Uri.parse('https://flutter.dev');
await Share.shareUri(url);
}
4.3 分享图片
Future<void> shareImage(String imagePath) async {
final XFile file = XFile(
imagePath,
name: 'shared_image.jpg',
mimeType: 'image/jpeg',
);
await Share.shareXFiles([file], text: '分享一张图片');
}
4.4 分享多个文件
Future<void> shareMultipleFiles(List<String> paths) async {
final List<XFile> files = paths.map((path) {
return XFile(path, mimeType: 'image/jpeg');
}).toList();
await Share.shareXFiles(
files,
subject: '分享多张图片',
text: '这是多张图片的分享',
);
}
4.5 分享并获取结果
Future<void> shareWithResult() async {
final ShareResult result = await Share.shareWithResult(
'分享内容',
subject: '分享主题',
);
switch (result.status) {
case ShareResultStatus.success:
print('分享成功: ${result.raw}');
break;
case ShareResultStatus.dismissed:
print('用户取消分享');
break;
case ShareResultStatus.unavailable:
print('分享结果不可用');
break;
}
}
4.6 从资源文件分享
Future<void> shareFromAssets() async {
final ByteData bytes = await rootBundle.load('assets/image.png');
final Uint8List list = bytes.buffer.asUint8List();
final XFile file = XFile.fromData(
list,
name: 'shared_image.png',
mimeType: 'image/png',
);
await Share.shareXFiles([file]);
}
五、最佳实践
5.1 指定分享面板位置
在 iPad 和 Mac 上,需要指定分享面板的弹出位置:
final box = context.findRenderObject() as RenderBox?;
if (box != null) {
await Share.share(
'分享内容',
sharePositionOrigin: box.localToGlobal(Offset.zero) & box.size,
);
}
5.2 错误处理
对分享操作进行错误处理:
Future<void> safeShare(String text) async {
try {
await Share.share(text);
} on PlatformException catch (e) {
print('分享失败: ${e.message}');
} catch (e) {
print('发生错误: $e');
}
}
5.3 检查内容有效性
分享前检查内容是否有效:
Future<void> shareIfValid(String? text) async {
if (text == null || text.isEmpty) {
print('分享内容为空');
return;
}
await Share.share(text);
}
5.4 结合图片选择器
结合 image_picker 实现选择图片后分享:
Future<void> pickAndShare() async {
final ImagePicker picker = ImagePicker();
final XFile? image = await picker.pickImage(source: ImageSource.gallery);
if (image != null) {
await Share.shareXFiles([image], text: '分享选中的图片');
}
}
六、常见问题
Q1:如何分享带格式的文本?
share_plus 只支持纯文本分享,不支持富文本格式。如需分享带格式内容,可以考虑生成图片或 PDF 后分享。
Q2:如何知道用户分享到了哪个应用?
出于隐私考虑,平台不会告知用户选择了哪个应用进行分享。ShareResult 只能知道用户是否完成了分享操作。
Q3:分享大文件时需要注意什么?
分享大文件时建议先检查文件是否存在,并提示用户等待:
final file = File(path);
if (await file.exists()) {
await Share.shareXFiles([XFile(path)]);
}
Q4:如何在 OpenHarmony 上调试分享功能?
在 OpenHarmony 上,分享功能会调用系统分享面板。确保设备上安装了可接收分享内容的应用。
Q5:分享图片后图片存储在哪里?
分享的图片会被复制到系统临时目录,接收方应用会处理图片的存储。
七、总结
share_plus 库为 Flutter for OpenHarmony 开发提供了完整的分享功能。通过简洁的 API,开发者可以轻松实现文本、URL、图片、文件的分享。该库在鸿蒙平台上已经完成了完整的适配,支持所有核心功能,开发者可以放心使用。
八、完整代码示例

以下是一个完整的可运行示例,展示了 share_plus 库的核心功能:
pubspec.yaml
name: share_plus_demo
description: Flutter for OpenHarmony share_plus 演示项目
publish_to: 'none'
version: 1.0.0+1
environment:
sdk: '>=3.0.0 <4.0.0'
dependencies:
flutter:
sdk: flutter
share_plus:
git:
url: https://atomgit.com/openharmony-sig/flutter_plus_plugins.git
path: packages/share_plus/share_plus
image_picker:
git:
url: https://atomgit.com/openharmony-tpc/flutter_packages.git
path: packages/image_picker/image_picker
flutter:
uses-material-design: true
assets:
- assets/
main.dart
import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:image_picker/image_picker.dart';
import 'package:path_provider/path_provider.dart';
import 'package:share_plus/share_plus.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
Widget build(BuildContext context) {
return MaterialApp(
title: 'Share Plus Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({super.key});
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
final TextEditingController _textController = TextEditingController();
final TextEditingController _subjectController = TextEditingController();
final TextEditingController _urlController = TextEditingController();
final List<XFile> _selectedFiles = [];
String _resultMessage = '';
Future<void> _shareText() async {
if (_textController.text.isEmpty) {
_showMessage('请输入要分享的文本');
return;
}
try {
await Share.share(
_textController.text,
subject: _subjectController.text.isEmpty ? null : _subjectController.text,
);
_showMessage('分享完成');
} catch (e) {
_showMessage('分享失败: $e');
}
}
Future<void> _shareUrl() async {
if (_urlController.text.isEmpty) {
_showMessage('请输入要分享的 URL');
return;
}
try {
final Uri uri = Uri.parse(_urlController.text);
await Share.shareUri(uri);
_showMessage('分享完成');
} on FormatException catch (e) {
_showMessage('URL 格式错误: $e');
} catch (e) {
_showMessage('分享失败: $e');
}
}
Future<void> _shareWithResult() async {
if (_textController.text.isEmpty) {
_showMessage('请输入要分享的文本');
return;
}
try {
final result = await Share.shareWithResult(
_textController.text,
subject: _subjectController.text.isEmpty ? null : _subjectController.text,
);
switch (result.status) {
case ShareResultStatus.success:
_showMessage('分享成功');
break;
case ShareResultStatus.dismissed:
_showMessage('用户取消分享');
break;
case ShareResultStatus.unavailable:
_showMessage('分享结果不可用');
break;
}
} catch (e) {
_showMessage('分享失败: $e');
}
}
Future<void> _pickImage() async {
final ImagePicker picker = ImagePicker();
final XFile? image = await picker.pickImage(source: ImageSource.gallery);
if (image != null) {
setState(() {
_selectedFiles.add(image);
});
}
}
Future<void> _pickMultipleImages() async {
final ImagePicker picker = ImagePicker();
final List<XFile> images = await picker.pickMultiImage();
if (images.isNotEmpty) {
setState(() {
_selectedFiles.addAll(images);
});
}
}
void _removeFile(int index) {
setState(() {
_selectedFiles.removeAt(index);
});
}
Future<void> _shareFiles() async {
if (_selectedFiles.isEmpty) {
_showMessage('请先选择要分享的文件');
return;
}
try {
await Share.shareXFiles(
_selectedFiles,
text: _textController.text.isEmpty ? null : _textController.text,
subject: _subjectController.text.isEmpty ? null : _subjectController.text,
);
_showMessage('分享完成');
} catch (e) {
_showMessage('分享失败: $e');
}
}
Future<void> _shareFromAssets() async {
try {
final ByteData bytes = await rootBundle.load('assets/flutter_logo.png');
final Uint8List list = bytes.buffer.asUint8List();
final XFile file = XFile.fromData(
list,
name: 'flutter_logo.png',
mimeType: 'image/png',
);
await Share.shareXFiles([file], text: '分享 Flutter Logo');
_showMessage('分享完成');
} catch (e) {
_showMessage('分享失败: $e');
}
}
void _showMessage(String message) {
setState(() {
_resultMessage = message;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(message)),
);
}
void dispose() {
_textController.dispose();
_subjectController.dispose();
_urlController.dispose();
super.dispose();
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Share Plus 演示'),
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Text(
'Share Plus 功能演示',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
const SizedBox(height: 24),
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('分享文本', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16)),
const SizedBox(height: 12),
TextField(
controller: _textController,
decoration: const InputDecoration(
labelText: '分享内容',
border: OutlineInputBorder(),
),
maxLines: 3,
),
const SizedBox(height: 12),
TextField(
controller: _subjectController,
decoration: const InputDecoration(
labelText: '主题(可选)',
border: OutlineInputBorder(),
),
),
const SizedBox(height: 12),
Row(
children: [
Expanded(
child: ElevatedButton.icon(
onPressed: _shareText,
icon: const Icon(Icons.share),
label: const Text('分享文本'),
),
),
const SizedBox(width: 8),
Expanded(
child: ElevatedButton.icon(
onPressed: _shareWithResult,
icon: const Icon(Icons.share_rounded),
label: const Text('分享并获取结果'),
),
),
],
),
],
),
),
),
const SizedBox(height: 16),
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('分享 URL', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16)),
const SizedBox(height: 12),
TextField(
controller: _urlController,
decoration: const InputDecoration(
labelText: 'URL 地址',
border: OutlineInputBorder(),
hintText: 'https://flutter.dev',
),
keyboardType: TextInputType.url,
),
const SizedBox(height: 12),
ElevatedButton.icon(
onPressed: _shareUrl,
icon: const Icon(Icons.link),
label: const Text('分享 URL'),
),
],
),
),
),
const SizedBox(height: 16),
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('分享文件', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16)),
const SizedBox(height: 12),
Row(
children: [
Expanded(
child: ElevatedButton.icon(
onPressed: _pickImage,
icon: const Icon(Icons.image),
label: const Text('选择图片'),
),
),
const SizedBox(width: 8),
Expanded(
child: ElevatedButton.icon(
onPressed: _pickMultipleImages,
icon: const Icon(Icons.photo_library),
label: const Text('选择多张'),
),
),
],
),
const SizedBox(height: 12),
if (_selectedFiles.isNotEmpty) ...[
const Text('已选择的文件:', style: TextStyle(fontWeight: FontWeight.w500)),
const SizedBox(height: 8),
...List.generate(_selectedFiles.length, (index) {
return ListTile(
dense: true,
leading: const Icon(Icons.insert_drive_file),
title: Text(_selectedFiles[index].name),
trailing: IconButton(
icon: const Icon(Icons.close),
onPressed: () => _removeFile(index),
),
);
}),
const SizedBox(height: 12),
],
ElevatedButton.icon(
onPressed: _shareFiles,
icon: const Icon(Icons.attach_file),
label: const Text('分享选中的文件'),
),
],
),
),
),
const SizedBox(height: 16),
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('从资源分享', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16)),
const SizedBox(height: 12),
ElevatedButton.icon(
onPressed: _shareFromAssets,
icon: const Icon(Icons.archive),
label: const Text('分享资源文件'),
),
],
),
),
),
const SizedBox(height: 24),
if (_resultMessage.isNotEmpty)
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.blue.shade50,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.blue.shade200),
),
child: Text(
_resultMessage,
style: const TextStyle(fontSize: 14),
),
),
],
),
),
);
}
}
九、参考资源
更多推荐




所有评论(0)