可可图片编辑 HarmonyOS(3)应用间分享图片 
前言 
可可图标编辑也实现了图片的分享功能,演示效果如下。

Share Kit(分享服务) 介绍 
hare Kit(分享服务)为应用提供文本、图片、视频等内容跨应用、跨端分享能力。
应用把需要分享的内容和预览样式配置给Share Kit,Share Kit将根据不同的场景进行使用:
- 针对应用间分享的场景,根据分享的数据类型、数量等信息构建分享面板,为用户提供内容预览、推荐分享联系人、关联应用及操作界面,便于用户快速选择分享应用或操作,将内容分发到目标应用。
- 针对跨端分享的场景,根据分享的数据类型、数量等信息构建预览界面,用于跨端分享。
| 应用类型 | 相关逻辑 | 
|---|---|
| 宿主应用 | 宿主应用需要对可分享的内容提供分享入口,在用户点击分享时,配置分享内容到分享,拉起系统分享面板。通过分享面板发起分享碰一碰分享 | 
| 目标应用 | 需要在应用中构建具有数据处理能力组件,包括以下两种分享方式。应用内处理分享内容分享详情页处理分享内容(可选)社交类应用可遵照意图框架接入规范把最近分享行为联系人相关信息捐献到意图框架,Share Kit可从意图框架获取推荐信息,当用户选择推荐的联系人时,会把联系人信息随分享数据一起给到目标应用,目标应用可以根据联系人信息直接一步发送内容给指定用户。 | 
分类 
Share Kit 可以分为 systemShare 和 HarmonyShare ,两者区别主要是:
- systemShare 用于应用之间的分享
- HarmonyShare 用于设备之间的分享
在实际开发中,两者可能配合使用:
跨端分享:通过 HarmonyShare 发起碰一碰传输,接收端通过 HarmonyShare 的沙箱监听处理数据。
应用内分享:通过 systemShare 构造分享内容,用户选择目标应用后跳转到对应页面。
systemShare 使用步骤 


1. 选择图片 
- 配置图片选择参数- 创建 PhotoSelectOptions对象,设置MIMEType为IMAGE_TYPE限制只能选择图片类型文件
- 通过 maxSelectNumber = 5限制最大可选择数量,符合鸿蒙系统图片选择器的多选能力
 
- 创建 
- 创建图片选择器实例- 使用 PhotoViewPicker类(鸿蒙媒体访问框架)创建选择器实例,体现鸿蒙API的分层设计
 
- 使用 
- 调用异步选择方法- 通过 select()方法触发系统图片选择界面,采用Promise异步处理机制:- 成功回调:提取返回结果中的 photoUris数组,取首元素赋值给组件状态变量fileUri,并打印完整URI列表
- 异常处理:捕获 BusinessError异常,输出包含错误码和消息的日志,符合ArkTS错误处理规范
 
- 成功回调:提取返回结果中的 
 
- 通过 
typescript
      Button("选择图片")
        .onClick(() => {
          // 1 设置选择图片的参数
          const photoSelectOptions = new photoAccessHelper.PhotoSelectOptions();
          photoSelectOptions.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE; // 过滤选择媒体文件类型为IMAGE。
          photoSelectOptions.maxSelectNumber = 5; // 选择媒体文件的最大数目。
          let uris: Array<string> = [];
          // 2 创建图片选择器
          const photoViewPicker = new photoAccessHelper.PhotoViewPicker();
          // 3 开始选择图片
          photoViewPicker.select(photoSelectOptions).then((photoSelectResult: photoAccessHelper.PhotoSelectResult) => {
            uris = photoSelectResult.photoUris;
            this.fileUri = uris[0]
            console.info('photoViewPicker.select to file succeed and uris are:' + uris);
          }).catch((err: BusinessError) => {
            console.error(`Invoke photoViewPicker.select failed, code is ${err.code}, message is ${err.message}`);
          })
        })2. 拷贝到沙箱 
- 获取沙箱路径- 通过 getUIContext().getHostContext()获取 UIAbility 上下文
- 使用 cacheDir属性获取应用专属缓存目录(框架提供的安全存储路径)
 
- 通过 
- 生成唯一文件名- 通过 split('.').pop()解析原始文件的扩展名(ArkTS 的字符串操作特性)
- 使用 Date.now()生成时间戳作为文件名前缀,确保文件名唯一性
 
- 通过 
- 执行文件拷贝- 使用 fs.openSync以只读模式打开源文件(ArkTS 文件系统 API)
- 调用 fs.copyFileSync执行文件描述符到目标路径的同步拷贝操作
 
- 使用 
- 状态反馈- 成功时通过 AlertDialog显示操作结果(ArkUI 的声明式 UI 组件)
- 失败时捕获异常并显示错误提示(try-catch 异常处理机制)
 
- 成功时通过 
- 数据绑定更新- 将生成的缓存路径 copyFilePath赋值给this.cacheUri,用于后续数据绑定或状态管理(响应式编程特性)
 
- 将生成的缓存路径 
typescript
Button("复制到沙箱")
.onClick(async () => {
  try {
    const context = this.getUIContext().getHostContext() as common.UIAbilityContext;
    const cacheDir = context.cacheDir;
    const fileType = this.fileUri.split('.').pop() // 后缀名
    // 生成一个新的文件名
    const fileName = Date.now() + '.' + fileType
    // 通过缓存路径+文件名 拼接出完整的路径
    const copyFilePath = cacheDir + '/' + fileName
    // 将文件 拷贝到 临时目录
    const file = fs.openSync(this.fileUri, fs.OpenMode.READ_ONLY)
    fs.copyFileSync(file.fd, copyFilePath)
    AlertDialog.show({ message: JSON.stringify('写入到沙箱', null, 2) })
    this.cacheUri = copyFilePath
  } catch (e) {
    AlertDialog.show({ message: JSON.stringify('写入失败', null, 2) })
  }
})3. 分享 
- 获取UI上下文 - 通过this.getUIContext()获取当前UI组件的上下文对象
- 使用getHostContext()获取UIAbility上下文,用于后续调用系统分享能力
 
- 通过
- 确定统一数据类型(UTD) - 通过文件后缀名(jpg/png/webp)匹配对应的UTD类型ID
- 使用utd.getUniformDataTypeByFilenameExtensionAPI获取标准数据类型标识
 
- 构建分享数据对象 - 创建 - systemShare.SharedData实例,包含:- utd:统一数据类型标识
- title/description:分享时显示的元数据
- uri:通过fileUri.getUriFromPath转换沙箱路径为可访问URI
 
- 初始化分享控制器 - 创建 - systemShare.ShareController实例,绑定分享数据
- 显示系统分享界面 - 调用 - controller.show()步方法,传入:- SelectionMode.SINGLE:单选模式
- SharePreviewMode.DETAIL:详细预览模式
 
typescript
Button("分享")
.onClick(async () => {
  try { // 获取UI上下文
    const uiContext: UIContext = this.getUIContext();
    const context: common.UIAbilityContext = uiContext.getHostContext() as common.UIAbilityContext;
    // 根据图片格式确定UTD类型
    let utdTypeId: string;
    switch (this.fileUri.split('.').pop()) {
      case 'jpeg':
      case 'jpg':
        utdTypeId = utd.getUniformDataTypeByFilenameExtension('.jpg', utd.UniformDataType.IMAGE);
        break;
      case 'png':
        utdTypeId = utd.getUniformDataTypeByFilenameExtension('.png', utd.UniformDataType.IMAGE);
        break;
      case 'webp':
        utdTypeId = utd.getUniformDataTypeByFilenameExtension('.webp', utd.UniformDataType.IMAGE);
        break;
      default:
        utdTypeId = utd.getUniformDataTypeByFilenameExtension('.jpg', utd.UniformDataType.IMAGE);
    }
    // 创建分享数据,使用沙箱中的图片URI
    const shareData: systemShare.SharedData = new systemShare.SharedData({
      utd: utdTypeId,
      title: 'Picture Title',
      description: 'Picture Description',
      uri: fileUri.getUriFromPath(this.cacheUri),
    });
    // 创建分享控制器
    const controller: systemShare.ShareController = new systemShare.ShareController(shareData);
    // 显示分享界面
    await controller.show(context, {
      selectionMode: systemShare.SelectionMode.SINGLE,
      previewMode: systemShare.SharePreviewMode.DETAIL
    });
    console.log('图片分享成功');
  } catch (e) {
    console.log('图片分享失败');
  }
})总结 
本文介绍了在鸿蒙应用中实现图片分享功能的完整流程。通过 Share Kit 的 systemShare 服务,开发者可以轻松实现应用间的图片分享。核心实现包括三个步骤:
- 图片选择:使用 PhotoViewPicker调用系统图片选择器,支持多选并限制文件类型
- 沙箱拷贝:将选中图片拷贝到应用缓存目录,确保分享时的文件访问权限
- 分享操作:通过 ShareController构建分享数据,调用系统分享面板完成跨应用分享
整个流程充分利用了鸿蒙系统的媒体访问框架、文件系统 API 和分享服务,为用户提供了原生、流畅的图片分享体验。
案例完整代码 
typescript
import { photoAccessHelper } from '@kit.MediaLibraryKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { fileUri, fileIo as fs } from '@kit.CoreFileKit';
import { common } from '@kit.AbilityKit';
import { uniformTypeDescriptor as utd } from '@kit.ArkData';
import { systemShare } from '@kit.ShareKit';
@ComponentV2
@Entry
struct Index {
  fileUri: string = ""
  cacheUri: string = ""
  build() {
    Column({ space: 10 }) {
      Button("选择图片")
        .onClick(() => {
          // 1 设置选择图片的参数
          const photoSelectOptions = new photoAccessHelper.PhotoSelectOptions();
          photoSelectOptions.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE; // 过滤选择媒体文件类型为IMAGE。
          photoSelectOptions.maxSelectNumber = 5; // 选择媒体文件的最大数目。
          let uris: Array<string> = [];
          // 2 创建图片选择器
          const photoViewPicker = new photoAccessHelper.PhotoViewPicker();
          // 3 开始选择图片
          photoViewPicker.select(photoSelectOptions).then((photoSelectResult: photoAccessHelper.PhotoSelectResult) => {
            uris = photoSelectResult.photoUris;
            this.fileUri = uris[0]
            console.info('photoViewPicker.select to file succeed and uris are:' + uris);
          }).catch((err: BusinessError) => {
            console.error(`Invoke photoViewPicker.select failed, code is ${err.code}, message is ${err.message}`);
          })
        })
      Button("复制到沙箱")
        .onClick(async () => {
          try {
            const context = this.getUIContext().getHostContext() as common.UIAbilityContext;
            const cacheDir = context.cacheDir;
            const fileType = this.fileUri.split('.').pop() // 后缀名
            // 生成一个新的文件名
            const fileName = Date.now() + '.' + fileType
            // 通过缓存路径+文件名 拼接出完整的路径
            const copyFilePath = cacheDir + '/' + fileName
            // 将文件 拷贝到 临时目录
            const file = fs.openSync(this.fileUri, fs.OpenMode.READ_ONLY)
            fs.copyFileSync(file.fd, copyFilePath)
            AlertDialog.show({ message: JSON.stringify('写入到沙箱', null, 2) })
            this.cacheUri = copyFilePath
          } catch (e) {
            AlertDialog.show({ message: JSON.stringify('写入失败', null, 2) })
          }
        })
      Button("分享")
        .onClick(async () => {
          try { // 获取UI上下文
            const uiContext: UIContext = this.getUIContext();
            const context: common.UIAbilityContext = uiContext.getHostContext() as common.UIAbilityContext;
            // 根据图片格式确定UTD类型
            let utdTypeId: string;
            switch (this.fileUri.split('.').pop()) {
              case 'jpeg':
              case 'jpg':
                utdTypeId = utd.getUniformDataTypeByFilenameExtension('.jpg', utd.UniformDataType.IMAGE);
                break;
              case 'png':
                utdTypeId = utd.getUniformDataTypeByFilenameExtension('.png', utd.UniformDataType.IMAGE);
                break;
              case 'webp':
                utdTypeId = utd.getUniformDataTypeByFilenameExtension('.webp', utd.UniformDataType.IMAGE);
                break;
              default:
                utdTypeId = utd.getUniformDataTypeByFilenameExtension('.jpg', utd.UniformDataType.IMAGE);
            }
            // 创建分享数据,使用沙箱中的图片URI
            const shareData: systemShare.SharedData = new systemShare.SharedData({
              utd: utdTypeId,
              title: 'Picture Title',
              description: 'Picture Description',
              uri: fileUri.getUriFromPath(this.cacheUri),
            });
            // 创建分享控制器
            const controller: systemShare.ShareController = new systemShare.ShareController(shareData);
            // 显示分享界面
            await controller.show(context, {
      
              selectionMode: systemShare.SelectionMode.SINGLE,
              previewMode: systemShare.SharePreviewMode.DETAIL
            });
            console.log('图片分享成功');
          } catch (e) {
            console.log('图片分享失败');
          }
        })
    }
    .width("100%")
    .height("100%")
    .justifyContent(FlexAlign.Center)
  }
}以往文章 
- 可可图片编辑 HarmonyOS 上架应用分享
- 可可图片编辑 HarmonyOS(2) 选择图片和保存到图库
- 懂你的HarmonyOS知识库更新了,已经来到10970个文档了
- AI编程神器!Trae+Claude4.0 简单配置 让 HarmonyOS 开发效率飙升
近期活动 
最近想要想要考取 HarmonyOS 基础或者高级证书,或者快要获取的同学都可以点击这个链接,加入我的班级,考取成功有机会获得鸿蒙礼盒一份。

联系我 
可以加我微信,带你了解更多HarmonyOS相关的资讯。
