ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

鸿蒙Share Kit视频分享实战:从URI权限到分享面板的完整链路

鸿蒙Share Kit视频分享实战:从URI权限到分享面板的完整链路 做鸿蒙版社区应用的时候产品给我提了一个需求用户看到帖子里的视频之后想一键把视频转给聊天好友。我第一反应是“这不就是把视频地址塞进分享接口嘛”但真动手才发现鸿蒙的分享链路跟安卓完全不是一个套路——光一个分享类型映射就能让人绕半天。后来老老实实用 Share Kit 把流程跑通才摸清里面那些隐藏规则。这篇是《鸿蒙学习实战之路 Share Kit 系列》的第 5 篇专门聊分享视频内容这件事适合已经在鸿蒙工程里写过业务代码、想给应用加系统分享能力的开发者参考。1. 先把 Share Kit 在视频分享里的“分工”搞清楚1.1 系统分享面板背后的调度逻辑Share Kit 在鸿蒙里不是“一个帮你去发 QQ 发微信的工具”它更像一个快递中转站。你的 App 把要分享的数据打包好交给系统分享面板面板根据数据内容、媒体类型和目标应用声明的支持范围自动匹配合适的接收端。整个过程你的 App 不需要知道用户最终选了哪个应用也不需要替目标应用准备数据格式Share Kit 会做一次统一包装。这个设计对视频分享特别重要。视频不像文本那样有个字符串就行也不像图片那样系统直接读一遍就行它涉及格式、编码、体积、权限多个环节。一旦这些环节没处理好面板能弹出来但用户在选择目标 App 之后看到的可能是一张“无法打开”的卡片甚至啥都没有。1.2 视频与文本、图片分享的三点关键差异第一点接收端对视频的识别依赖媒体类型。文本分享基本只分“纯文本”和“富文本”两类图片分享也就 JPEG、PNG、GIF 这些。视频不一样同样是一个文件有的接收端希望它是“视频”可以预览播放有的接收端只把它当作“普通文件”给个下载入口有的接收端甚至根本不认这个类型系统只能降级处理成文件。第二点临时文件的授权链路更敏感。分享图片时很多接收端会先读缩略图真正下载原图靠自己的逻辑分享视频时绝大多数接收端要拿完整文件如果分享方给的是无权限的本地路径读的时候就直接失败而且失败表现往往很隐蔽不报错、不提示就是打不开。第三点体积和耗时明显影响体验。视频文件动辄几十上百 MB在分享面板弹出前系统就可能做类型探测、读取头信息、生成展示摘要这部分耗时比图片分享长得多。如果视频放在网络链接上接收端还需要额外的网络拉取逻辑所以参数里有没有正确的预览地址、标题、摘要直接决定分享卡片好不好看、能不能确认来源。1.3 什么时候不必上 Share Kit我遇到过一些开发者把 Share Kit 当成万能方案不管什么分享场景都用它。其实如果你的数据有固定的接收方比如“点了这个按钮就一定要通过某个指定应用发送”那直接用显式 intent 或者接入对方 SDK 更合适。Share Kit 的核心价值是“让用户自己选、按系统规则匹配”如果你需要的是流程可控、接收方固定反而会绕远路。反过来只要你的场景里出现“用户可能想发到微信、QQ、网盘、备忘录、蓝牙接收设备”这类不确定目标就适合用 Share Kit。视频分享尤其典型因为接收方的能力差异太大了你自己维护接收方适配列表根本不现实。2. 接入前的工程准备权限、SDK 版本和真机校验2.1 module.json5 里的隐私权限与授权方式先回到工程配置。很多人以为分享视频要申请一堆读写存储的权限实际上在 HarmonyOS NEXT 上官方推荐用系统选择器来做文件授权让用户明确选一次视频拿到的是一个有授权范围的 uri。这样既满足合规要求也能避免在应用市场上因为过度索权被卡。如果你的业务确实需要主动读取相册里的视频列表那要在module.json5里声明媒体读取权限{ module: { requestPermissions: [ { name: ohos.permission.READ_IMAGEVIDEO, reason: 用于读取用户选择的视频并分享, usedScene: { abilities: [EntryAbility], when: inuse } } ] } }但我的建议是优先用PhotoViewPicker。它让用户在系统相册界面里选择你拿到的是系统授权的 uri不需要自己维护权限申请流程后续分享到其他应用时也不会遇到“你这个 App 读得到目标 App 读不到”的尴尬。2.2 SDK 与真机系统版本匹配Share Kit 的能力在 API 12 上已经比较完整但它的稳定表现和系统版本强相关。我自己用 DevEco Studio 5.x 配合 HarmonyOS 5.0 真机跑通了一套流程中间发现 4.x 上分享面板的行为、回调语义跟 5.x 有明显差异这一点后面详细说。所以建议工程里把compileSdkVersion提到当前 IDE 支持的最高版本单真机调试选 HarmonyOS 5.0 以上。如果你还在老 SDK 上开发代码里用到的一些高级字段可能编译不过甚至编译过了运行也会因为系统不识别而静默失败。2.3 用能力校验避免低版本直接 crash分享面板不是每个老版本系统都稳的。我的习惯是在拉起分享前做一次系统能力预检用一个 try/catch 包住首次调用。一旦发现当前系统不支持或者服务异常就降级成“复制链接”或“保存到相册”的兜底方案而不是让用户点击后没有任何反应。这里有个容易被忽略的点Share Kit 的校验不能只判断手机是不是华为、系统是不是 5.0最好在运行时判断关键接口是否存在。开发时我见过同样的代码在 Mate 系列上正常、在部分老旗舰上直接抛“Service not found”的异常这种差异只能在真机上提前测出来。3. 分享视频的参数设计ShareData 与链接媒体类型3.1 在线视频ShareData.link 带上的不止是地址分享在线视频时核心工作是构建一个ShareData然后把视频地址填进link字段。写过一次你会觉得这就是“填个链接”但实际差距很大title、description、linkSummary这些字段决定接收端展示分享卡片的能力不填的话很多端显示的就是一串光秃秃的 URL。我目前用的示例大概是这样的import { shareKit } from kit.ShareKit; let shareData: shareKit.ShareData { title: XX产品体验视频, description: 一段真实上手视频来自社区用户分享, link: https://yourdomain.com/video/detail?id12345, linkSummary: 点击查看完整视频 }; // 给 ShareData 打上视频类型的标签不同版本SDK对字段方式略有区别 // 以你IDE里shareKit的声明为准我这里标的是运行时枚举 shareKit.setShareLinkMediaType(shareData, shareKit.LinkMediaType.VIDEO); let result await shareKit.fulfillShare(shareData); if (result.code 0) { console.info(分享面板成功唤起用户完成了分享动作); } else { console.error(分享失败错误码: result.code); }如果你直接把视频地址写进 link 却不设置媒体类型系统可能会把这段内容当普通网页处理接收端打开后可能先展示标题摘要而不是直接播放。所以在线视频分享里“链接地址 视频类型”是成对出现的。3.2 本地文件file:// 与 datashare:// 的取舍本地视频分享是另一个套路。这里要认清一个事实Share Kit 的link字段实际上放的是“统一资源标识”不光是 http 地址只要是系统能识别的 uri 都可以往里放。从相册拿到的视频一般是datashare://开头的媒体库 uri从应用沙箱拿到的视频一般是自己拼接的file://地址。两种 uri 我都试过经验是datashare://适合直接从相册、媒体库选择后立刻分享系统对这类 uri 有一套授权映射接收端通过系统转发能拿到读取能力。file://适合先把视频复制到应用自己的沙箱目录再由你分享出去。这种地址语义简单接收端读起来直接但你必须保证文件的临时授权能传过去否则对方一样打不开。我踩过的坑是用文件管理器的路径直接拼了一个file:///storage/...塞给 Share Kit。面板能弹出来但接收端完全没权限读这个文件。后面会讲这个问题的完整排查过程。3.3 缩略图和封面视频分享比图片分享更需要它千万注意系统分享面板对视频的“摘要展示”依赖封面。如果你分享的线上视频链接是直接指向.mp4文件很多接收端没法直接预览内容卡片会变得很干。我建议给视频搞一个独立的落地页并在页面里放og:video、og:image之类的元信息这样分享到大部分应用时能带出视频信息和封面图。本地视频同理。如果视频本身没有生成封面分享后卡片就只剩标题和文件大小用户根本看不出这是个视频。你需要提前给视频抽一帧作为封面图放到应用缓存目录再通过系统支持的字段把封面一起带过去。3.4 回调结果怎么判断真正分享成功fulfillShare的返回码为 0 只代表“分享面板被正常唤起用户完成了这次分享动作”不代表对方真的把视频成功收下。你要理解这层含义从你调用到面板弹出你的 App 只是把数据交给了系统后续发送环节由系统跟接收端协作你无法也不应该控制。所以不要拿回调结果做数据埋点里的“分享成功数”它更多代表“用户完成了分享动作”。如果你要在产品层面统计“对方真正收到”得靠接收端自己的回调或落地页的访问数据来验证。我是在做落地页之后才发现回调成功和对方点开视频之间差了很远的距离。4. 本地视频从选片到分享面板的完整链路4.1 用 PhotoViewPicker 选视频的推荐写法本地视频分享最标准的路径就是让用户先选视频再拉起分享面板。选视频我推荐直接用系统选择器代码量小、权限问题少import { photoAccessHelper } from kit.MediaLibraryKit; async function pickVideo(): Promisestring { let picker new photoAccessHelper.PhotoViewPicker(); let result await picker.select({ MIMEType: photoAccessHelper.PhotoViewMIMEType.VIDEO_TYPE, maxSelectNumber: 1 }); if (!result.photoUris || result.photoUris.length 0) { return ; } return result.photoUris[0]; }拿到 uri 之后我一般会先打印一下它的前缀确认到底是datashare://还是file://。这一步听起来多余但它能帮你在排查分享问题时缩小范围因为两种 uri 对接收端的授权路径完全不同。4.2 拿到的 uri 为什么不能直接到处传用户选完视频后你手上的 uri 是在“你的 App 有读取权”的前提下返回的。它不代表任何其他 App 读到更不代表分享目标能直接读。很多初学者把 uri 直接塞给 Share Kit面板正常弹出来结果选择方打不开然后怎么查都查不出代码问题因为他们没意识到“自己能读”和“对方能读”是两码事。我的做法是如果视频不大、允许临时处理就先把它复制到应用沙箱的缓存目录用沙箱里的file://uri 分享如果视频来自媒体库且不方便复制就依赖媒体库系统对 urite 的授权扩展看看当前 SDK 是否提供临时的持久化授权接口。一句话结论不要裸传媒体库 uri除非你确认当前系统版本能自动完成授权转发。4.3 大视频与低内存机型上的预处理超过 100MB 的视频文件在分享链路里体验会明显变差系统在读取文件头、生成摘要时会出现明显卡顿接收端也可能因为体积限制直接拒绝响应。做产品的人可能在 UI 上设计了“一键分享原片”但工学上的现实是原片分享除了特大型网盘类目标端很多聊天工具都会压缩、转码或直接失败。所以我在工程里加了一道预处理超过 50MB 的视频先提示用户“是否压缩后分享”压缩用系统自带的视频编辑能力或者调用硬件编码器转成低码率版本。这道逻辑在 6.0 的新机型上不算成本但在老机型上能明显降低分享失败率。4.4 最后一步唤起分享面板的完整示例选完视频、确认 uri 有效之后就可以把它交给 Share Kit 了import { shareKit } from kit.ShareKit; async function shareLocalVideo(uri: string, title: string) { let shareData: shareKit.ShareData { title: title, description: 来自我的鸿蒙应用, link: uri, linkSummary: 这是一个视频文件 }; shareKit.setShareLinkMediaType(shareData, shareKit.LinkMediaType.VIDEO); try { let result await shareKit.fulfillShare(shareData); if (result.code 0) { // 用户完成了分享动作 } else { // 查看错误码做对应提示 } } catch (error) { // 这里处理系统服务异常最好降级为复制链接或保存文件 } }这里需要你留意自己 IDE 里ShareData的类型声明不同 SDK 版本里媒体类型字段的赋值方式可能从属性变成了方法但核心逻辑是一样的就是把视频标识清楚、把链接填对、再交给系统。5. 我在真机上踩过的几个坑带排查过程5.1 坑一分享面板能打开对方却收到打不开的视频现象特别迷惑在自己的 App 里点击分享面板正常弹出选择微信后提示已发送但对方点开视频就是转圈、黑屏、甚至直接显示“文件已失效”。排查链路如下。第一步把同一个 uri 粘贴到系统文件管理器里直接打开确认视频文件本身没坏。第二步从系统相册里选同一个视频用系统自带的分享入口发给同一个接收端发现对方能正常打开。这一步已经把范围缩小到“系统自带分享和我的业务分享之间参数不一致”。第三步我打印出系统自带分享和我这边 ShareData 的差异发现系统分享的 link 指向的是一个带短时权限令牌的 uri而我这边塞的是原样媒体库 uri。第四步把分享参数改为应用沙箱里复制后的file://uri问题解决。这个坑告诉我们接收端读不读得到文件取决于你的 uri 带了多少权限信息而不是取决于文件本身是否有效。5.2 坑二本地视频 uri 在回调里返回错误码还有一次是fulfillShare直接抛了错误辅助排查时发现 uri 指向的文件已经被清理了。原因是我的业务逻辑在分享前先压缩视频压缩后把临时文件写进cache目录但分享回调还没有回来缓存目录就被系统或我的定时任务清掉了一部分。排查时我先在回调里打印 uri再用fs.access去判断文件是否存在发现文件确实没了。后来我把临时文件的清理时机改了不是压缩完就删除也不是放在统一清缓存的逻辑里而是等分享面板关闭、确认业务不再需要这个文件后再删。如果你也遇到类似问题先确认文件生命周期别一上来就怀疑 Share Kit。5.3 坑三接收端不识别 VIDEO 类型静默转成普通文件有一类接收端对系统分享映射表做得很窄只识别自己能处理的 mime 类型。你的 ShareData 明明是视频类型对方也可能只当成一个普通附件或网盘文件链接来接收。这种现象在微信、钉钉这类自成生态的 App 里最明显。排查方法很简单用同一个参数分别分享到几个不同目标端观察每个端接收后的展示。如果有的端能直接播放、有的端只显示文件名那就不是你的问题而是接收端能力差异。这种差异改不了系统只能做业务降级对不支持的目标端及时给出“对方可能会收到链接建议在浏览器中打开”的文案提示。5.4 坑四多系统版本下分享链路行为不一致我在 HarmonyOS 4.x 和 5.0 上做了对比。同样一段代码4.x 的分享面板弹出稍慢回调code的语义跟 5.0 也不是完全对齐。有一版代码我用“回调为 0 就上报分享成功”结果在 4.x 上因为用户中途取消也会走到 0导致上报数据虚高。排查办法是把分享面板的“用户点击了分享目标”和“用户取消了面板”分开判断不同系统版本按返回结果里的详细状态码去区分不要图省事只判断一个code 0。这件事在同一个工程里同时兼容 4.x 和 5.x 的时候尤其明显建议在接入初期就把版本兼容测试排进计划。6. 我做视频分享沉淀下来的几条实操习惯视频分享跟文本、图片分享的最大差别是“链路长了太多”。文本分享你只管文字内容图片分享你只管文件路径视频分享你要管封装格式、授权范围、封面展示、体积大小、接收端兼容、结果回调语义一环不行整个就崩。所以我现在做这块一定会先用线上视频走通完整链路再做本地文件分享最后才优化封面、压缩这类体验项。如果你正在接入 Share Kit 分享视频我给两个具体建议优先用“在线链接 视频落地页”的方式分享链路最干净接收端兼容性也最好。本地视频分享一定要对 uri 做权限预处理并反复在 5.0 真机上看接收端实际读取情况。我自己的工程里最终把视频分享拆成了三条分支秒开在线视频走链接分享小文件走本地沙箱复制后分享大文件先提醒压缩再走分享链路。这样跑下来产品那边再也没因为“分享打不开”“分享没反应”来找过我。
返回列表