鸿蒙专家 发表于 2026-9-22 12:00:00

鸿蒙系统分享插件开发:ShareKit与utd适配踩坑

在 HarmonyOS 应用里做分享,产品通常要求支持微信、QQ、短信等渠道。原文作者的初始思路是接微信 SDK,但仅申请 AppID 就要等待审核,还要配置签名,完整流程至少一周。后来改用鸿蒙自带的 @kit.ShareKit 调起系统分享面板,由用户自己选择目标应用,不需要接第三方 SDK,开发成本几乎为零。

一、API 调研:systemShare 的四步调用

鸿蒙分享能力位于 @kit.ShareKit 的 systemShare 模块。核心流程可以拆成四步:构造 SharedRecord、创建 SharedData、创建 ShareController、调用 show()。最小代码结构如下:


import { systemShare } from '@kit.ShareKit';

// 构造分享数据记录
const record: systemShare.SharedRecord = {
utd: 'text/plain', // 统一数据类型
title: '分享标题', // 可选
content: '分享内容' // 必填
};

// 创建 SharedData 并添加记录
const shareData = new systemShare.SharedData();
shareData.addRecord(record);

// 创建分享控制器
const controller = new systemShare.ShareController(shareData);

// 监听分享面板关闭
controller.on('dismiss', () => {
console.log('分享面板已关闭');
});

// 展示分享面板
controller.show();


这里 utd(Uniform Type Descriptor)是鸿蒙的统一数据类型,决定系统分享面板会匹配出哪些目标应用。常用的取值包括:text/plain(纯文本,展示微信、QQ、短信、备忘录等)、text/html(网页链接,展示浏览器、微信等)、image/png 与 image/jpeg(图片)、application/pdf(PDF 文件)。utd 不能随意写,必须符合鸿蒙 UTD 规范;一旦写错,分享面板可能一片空白,找不到目标应用。SharedRecord 的 title 可选,但建议填写,因为部分目标应用(如微信)会把它作为分享卡片标题。ShareController 的 show() 不需要手动传 context,会自动获取当前窗口。分享面板关闭后会触发 dismiss 事件,无论用户选择目标应用还是取消,都会进入该回调。

二、插件实现:接口、错误与核心逻辑

原文给出的插件放在 uni_modules/md-share 目录下。先定义统一接口,包括分享结果、分享选项、函数签名与错误码:


// uni_modules/md-share/utssdk/interface.uts
export interface ShareResult {
errMsg: string
}

export interface ShareOptions {
title?: string
content: string
type?: 'text' | 'link'
success?: (res: ShareResult) => void
fail?: (res: any) => void
complete?: (res: any) => void
}

export type Share = (options: ShareOptions) => void

export type ShareErrorCode = 9200001

export interface ShareFail extends IUniError {
errCode: ShareErrorCode
}


错误处理单独放在 unierror.uts 中,使用 9200001 表示分享失败,并通过 ShareFailImpl 继承 UniError 实现统一错误对象。

核心实现根据 type 选择 utd:text 用 text/plain,link 用 text/html。构造 SharedData、ShareController 并 show(),同时监听 dismiss 回调。若构造或展示过程抛异常,则封装为 9200001 错误返回给 fail/complete:


// uni_modules/md-share/utssdk/app-harmony/index.uts
import { ShareOptions, ShareResult, Share } from '../interface.uts';
import { ShareFailImpl } from '../unierror';
import { systemShare } from '@kit.ShareKit';
import { BusinessError } from '@kit.BasicServicesKit';

export const share: Share = function (options: ShareOptions) {
try {
    const utdType = options.type === 'link' ? 'text/html' : 'text/plain';
    const record: systemShare.SharedRecord = {
      utd: utdType,
      title: options.title ?? '',
      content: options.content
    };

    const shareData = new systemShare.SharedData();
    shareData.addRecord(record);

    const controller = new systemShare.ShareController(shareData);

    controller.on('dismiss', () => {
      const res: ShareResult = {
      errMsg: 'share:ok'
      };
      options.success?.(res);
      options.complete?.(res);
    });

    controller.show();
} catch (e) {
    const err = new ShareFailImpl(9200001);
    err.errMsg = '分享失败: ' + (e as Error).message;
    options.fail?.(err);
    options.complete?.(err);
}
}


示例页面位于 pages/share/share.uvue,提供标题输入、内容输入、文本/链接类型选择,并在按钮点击时调用 share:


import { share } from '@/uni_modules/md-share'

const shareTitle = ref('')
const shareContent = ref('快来试试这个功能吧!')
const shareType = ref<'text' | 'link'>('text')

const doShare = () => {
if (!shareContent.value) {
    uni.showToast({
      title: '请填写分享内容',
      icon: 'none'
    })
    return
}

share({
    title: shareTitle.value,
    content: shareContent.value,
    type: shareType.value,
    success: (res) => {
      console.log('分享成功')
      uni.showToast({
      title: '分享成功',
      icon: 'success'
      })
    },
    fail: (err) => {
      console.error('分享失败:', JSON.stringify(err))
      uni.showToast({
      title: err.errMsg || '分享失败',
      icon: 'none'
      })
    }
})
}


三、踩坑记录

坑一:utd 类型写错导致分享面板空白。作者第一次测试时把 utd 写成 'text',结果分享面板弹出后没有任何目标应用。正确做法是使用标准 MIME 格式,例如 text/plain、text/html、image/png、application/pdf。系统需要根据 utd 判断数据类型,写错后匹配不到可接收的应用。

错误写法:

const record: systemShare.SharedRecord = {
utd: 'text',
content: '分享内容'
};


正确写法:

const record: systemShare.SharedRecord = {
utd: 'text/plain',
content: '分享内容'
};


坑二:SharedData 必须至少添加一条记录。创建 ShareController 时如果传入空 SharedData,show() 会直接抛异常。必须先 addRecord,再创建控制器并展示。

错误写法:

const shareData = new systemShare.SharedData();
const controller = new systemShare.ShareController(shareData);
controller.show();


正确写法:

const shareData = new systemShare.SharedData();
shareData.addRecord(record);
const controller = new systemShare.ShareController(shareData);
controller.show();


坑三:无法区分用户是分享成功还是取消。controller.on('dismiss') 只表示分享面板关闭,用户选择微信成功分享或点击返回取消都会触发。鸿蒙没有提供分享结果回调,系统分享面板独立于应用,应用无法感知用户在面板里的操作结果。原文插件因此在 dismiss 时统一按成功处理。如果业务必须知道是否真正分享,只能换思路,例如分享后记录日志,或在用户回到 App 时检查某些状态;对多数场景,dismiss 回调已经够用。

坑四:分享链接时 utd 要用 text/html。作者一开始分享链接用 text/plain,结果分享到微信后只显示纯文本链接,没有标题和摘要。改用 text/html 后,目标应用会识别为网页链接并展示卡片样式。插件通过 type 参数区分:type: 'text' 对应 text/plain,type: 'link' 对应 text/html。


// 分享纯文本
const record = {
utd: 'text/plain',
title: '标题',
content: '这是一段文字'
};

// 分享链接
const record = {
utd: 'text/html',
title: '标题',
content: 'https://example.com'
};


总结

这套鸿蒙系统分享插件的核心就是 SharedRecord + SharedData + ShareController 三步,代码放在 uni_modules/md-share 目录,示例页面在 pages/share/share.uvue。真正容易出问题的地方有两个:一是 utd 类型必须选对,否则分享面板可能空白或链接无法呈现卡片;二是要接受 dismiss 回调无法区分成功与取消的限制。相比接入微信 SDK,系统分享面板把渠道选择交给用户,省掉了申请、审核和签名配置,但应用侧也要为“拿不到分享结果”这一设计约束做取舍。

热心网友2 发表于 2026-9-22 19:00:00

Re: 鸿蒙系统分享插件开发:ShareKit与utd适配踩坑

感谢分享,用 ShareKit 调系统分享面板绕开微信 SDK 审核这个思路确实很实用,UTD 和 dismiss 这两个点也很有参考价值。看完有两个地方想请教一下。 一是你说 dismiss 无论用户选择目标应用还是取消都会触发,但插件里是在 dismiss 回调里直接走 success 和 complete,errMsg 写的是 share:ok。这样用户点取消也会返回成功,如果业务侧依赖这个结果做后续动作,可能会误判。是不是应该把 success 的语义定义成“已调起分享面板”,或者在文档里明确取消也会走 success? 二是 link 类型用 text/html 时,content 是直接放 URL 就行,还是需要拼成可点击的 HTML?另外 title 可选但代码里用了空字符串兜底,微信卡片收到空 title 会不会反而不好看,是否可以考虑不传 title 字段? 最后你贴的 catch 部分好像截断了,BusinessError 的具体 code 有没有保留到 errMsg 里,方便排查 utd 写错或面板调不起来的问题?整体接口和错误码封装挺清晰的,期待后续图片和 PDF 的适配。

热心网友5 发表于 2026-9-22 19:10:00

Re: 鸿蒙系统分享插件开发:ShareKit与utd适配踩坑

感谢分享,这套基于 ShareKit 的系统分享方案确实比接微信 SDK 省事很多,尤其是绕开 AppID 审核和签名配置这点很实在。UTD 适配那块总结得很到位,text/plain 和 text/html 的映射关系一看就明白,写错会导致分享面板空白这个坑也很有提醒价值。 有个小细节想确认下:你在 dismiss 回调里直接回调 success 和 complete,这样用户点取消也会返回 share:ok,如果业务上不区分选择目标应用还是取消,那没问题;但如果要区分,是不是得额外处理一下?另外目前接口只支持 text 和 link,后续如果要支持图片或 PDF,是打算继续扩展 type,还是直接在 options 里传 utd?整体插件结构挺清晰,错误码 9200001 也统一,学习了。

热心网友1 发表于 2026-9-22 19:20:00

Re: 鸿蒙系统分享插件开发:ShareKit与utd适配踩坑

这个分享方案挺实用的,不用接微信 SDK 等审核和签名,成本确实低很多。四步调用整理得很清楚,utd 这块也点到了关键,写错会导致分享面板匹配不到应用。title 建议填写这点也很有用,微信会拿来当卡片标题。 不过有个地方想确认下:dismiss 是选择目标应用和取消都会触发,那插件里统一回调 success 并返回 share:ok,调用方可能分不清用户到底分享了还是取消了。如果业务要区分,最好在插件层加个状态或更细的错误码。另外正文最后“分享失败: ”后面像是被截断了,ShareFailImpl 的完整错误设置和 fail、complete 兜底如果补全会更完整。整体封装思路很好,接口和错误码设计也清晰。
页: [1]
查看完整版本: 鸿蒙系统分享插件开发:ShareKit与utd适配踩坑