# 分享重构设计(微信/QQ/抖音去 SDK 化 + 剪贴板指引 + 内容对齐原工程) - 日期:2026-06-27 - 范围:`ShareProvider` 分享链路重构;支付桩边界确认;**契约(handler/DTO)零改动** - 关联:契约 §8.1 / §10.1 / §12(`friendsSharetypeUrlToptitleDescript`、`sharesuccess`、`SharetypeBean`);框架 §6.3 / §6.5 ## 1. 背景与动机 当前鸿蒙分享与原 Android 工程**没有对齐**: - 微信走 `@tencent/wechat_open_sdk`(网页/图片分享,缺缩略图)。 - QQ/抖音退化为纯 `systemShare` 系统面板,文本用统一 `joinText`(双换行、不含 url),与原工程逐渠道格式不符。 - 缺少原工程「复制内容到剪贴板 + 指引用户去对应 App 粘贴」的链路。 需求变更:三端统一改为「**优先拉起 App 分享界面 → 复制+指引 → 系统分享兜底**」,且微信不依赖 SDK。 ## 2. 关键验证结论(决定方案) 经鸿蒙文档 + 各开放平台资料核实: - 鸿蒙 NEXT **没有** Android `ACTION_SEND + setPackage` 那种「系统级带内容直分享到指定 App」的能力。 - 纯 scheme(`weixin://` / `mqqapi://` / `snssdk1128://`)**只能打开 App 或某页面,不能携带分享内容发起分享**。 - 「拉起 App 分享界面 + 预填内容 + 选好友直接分享」**只能靠各家官方鸿蒙 SDK**: - 微信 Open SDK(用户要求不使用 → 放弃直分享) - QQ 互联 `@tencent/qq-open-sdk` v1.0.3+(`shareToQQ` 可预填) - 抖音开放平台 SDK(仅「拉起编辑/发布页发布作品」,**无选好友私信能力**) - 三者均需 AppId 注册 / 签名指纹 / AppLinking 配置(属已登记的延期外部依赖)。 **决策(已确认)**:本期**不接任何分享 SDK**,三端统一走「**剪贴板 + 指引窗 → 系统分享**」,代码内预留 SDK 接入点;SDK 接入列为后续延期项。 ## 3. 对外契约(零改动,铁律判据) | 方向 | handler | 数据 | 说明 | |---|---|---|---| | 入站 | `friendsSharetypeUrlToptitleDescript` | JSON(`SharetypeBean`) | 触发分享 | | 出站 | `sharesuccess` | `{success:int, type:int}` | **仅微信**,success 2 成功 / 3 取消;type 1 好友 / 2 朋友圈 | `SharetypeBean`(不变): ```jsonc { "sharefriend": "1", // "1" 弹面板选目标 / "2" 朋友圈直发微信 "type": "1", // "1" 网页/文本 / "2" Canvas截图 / "3" 图片链接 / "4" 视频(抖音) "sharetype": "", // 截图子类型(canvasId) "webpageUrl": "https://...", "title": "标题", "description": "描述" } ``` ## 4. 交互流程 ``` H5 → friendsSharetypeUrlToptitleDescript(SharetypeBean) ├─ sharefriend=="2" → 微信渠道(朋友圈语义, 回传 type=2) → ShareGuideDialog(wechat) └─ sharefriend=="1" → SharePanel(微信/QQ/抖音/取消) └─ 选定渠道 → 按渠道+type 组装内容 + 写剪贴板 → ShareGuideDialog(platform) ├─「打开 微信/QQ/抖音」 canOpenLink + openLink(scheme) best-effort 打开 App,用户自行粘贴 ├─「用系统分享」 systemText(文本) / systemImage(图片)(可靠兜底) └─「取消」 ``` - `sharefriend=="1"` 弹自有 `SharePanel`(沿用现状);`=="2"` 不弹、直接微信指引窗。 - 指引窗展示前先把可分享内容写入剪贴板(文本 PLAIN_TEXT / 图片 PIXELMAP,尽力);图片粘贴不可保证,指引窗内「系统分享」按钮(`systemImage`)作可靠交付。 ## 5. 内容组装 ### 5.1 文本格式(三端统一) `buildShareText(bean)` = `title\ndescription`(**单换行、三端完全一致、不含 `webpageUrl`**)。空字段跳过对应行,避免多余空行。 - **"不含 url" 仅指文本分享**;图片分享按图片走,**绝不降级为文本**。 - `webpageUrl` 仅 `type "3"`(图片链接)用作图片来源 URL;`type "1"` 文本不使用;`type "4"` 视频 H5 未用、不实现。 ### 5.2 类型处理 | type | H5 用途 | 内容来源 | 第二层(剪贴板+指引窗) | 第三层(指引窗内「系统分享」按钮) | |---|---|---|---|---| | 1 | 网页/文本 | `buildShareText`(无 url) | PLAIN_TEXT 文本 | `systemText`(PLAIN_TEXT, 无 url) | | 2 | Canvas 截图 | `captureCanvas(sharetype)` → `saveDataUrlToFile` 沙箱图片 | PIXELMAP(**尽力**,对方支持才可粘贴) | `systemImage`(**可靠主交付**) | | 3 | 图片链接(低优先) | 从 `webpageUrl` 下载图片 → 沙箱,同 type2 图片管线 | PIXELMAP(尽力) | `systemImage` | | 4 | 视频 | **H5 未使用** | —— | —— | - **图片(type2/3)走「剪贴板图片(尽力) + 指引窗」**:复制 PIXELMAP(对方支持则可长按粘贴),指引窗同时提供「用系统分享」按钮 → `systemImage` 作可靠兜底(系统把图片文件交给目标 App)。理由:经验证微信/QQ 鸿蒙版能否粘贴 PIXELMAP 不可保证(§10),`systemImage` 才是确定能把图片交付的路径。 - **type4 视频**:H5 未用,分支**安全空实现**(不报错、不出站),不实现视频分享。 - **系统分享统一不下发 url**:文本 `systemText(title+description)`、图片 `systemImage`,**不再使用 `systemLink`/HYPERLINK**。`systemLink` 退役。 ## 6. `sharesuccess` 回传(仅微信,乐观) - 用户在微信指引窗点「打开微信」或「用系统分享」即视为已发起 → `callHandler('sharesuccess', {success:2, type})`。 - `type = (sharefriend=='1') ? 1 : 2`。 - 点「取消」 / 微信未安装且无法打开 → `{success:3, type}`。 - QQ、抖音**不回传**(与契约一致)。 ## 7. 组件与改动清单 ### 7.1 重写 `feature_capabilities/.../providers/ShareProvider.ets` - 保留:`FriendsShare` 注册、`PHOTO_UPLOAD`(`LocalUploadServer` 截图上传)链路 → 改为走微信指引窗(图片)。 - 新增:`sharefriend` 分流、`buildShareText`(统一 `title\ndescription`)、`writeClipboard`(文本 PLAIN_TEXT / 图片 PIXELMAP)、`showGuide` 经事件投给 UI、`openAppByScheme`(`canOpenLink`+`openLink`)。 - 图片管线:type2 走 `captureCanvas`→`saveDataUrlToFile`;type3 从 `webpageUrl` 下载→沙箱(复用平台层 `Downloader/HttpClient`,低优先);二者复用 PIXELMAP 写剪贴板 + `systemImage`。 - type4 视频:安全空实现(不报错、不出站)。 - 预留空分支:`qqSdkShare()` / `douyinSdkShare()`(注释 TODO,注册到位后接 SDK)。 - 复用:现有 `systemShare` 方法(`systemText/systemImage`,**`systemLink`/`systemVideo` 退役不再使用**)、`saveDataUrlToFile`、`captureCanvas`。 - 移除:对 `WeChatApi.sendShare` / `WXMediaMessage` / `WXWebpageObject` / `WXImageObject` / `SendMessageToWXReq` 的全部分享调用。 ### 7.2 新增 `entry/.../components/ShareGuideDialog.ets` - 自绘弹窗:渠道图标(复用 `share_wechat/share_qq/share_douyin`)+ 文案 + 三按钮(打开 App / 用系统分享 / 取消)。 - 文案按内容类型:文本类「内容已复制,请打开 XX 粘贴分享」;图片类「图片已复制,可在 XX 长按粘贴;或点下方用系统分享」。 - 「用系统分享」按钮:文本→`systemText`、图片→`systemImage`。 - 经 `EventBus`(仿 `SharePanel` 的 `SHOW_PANEL`/一次性回投模式)与 `BridgeGameContainer` 通信。 ### 7.3 `feature_capabilities/.../wx/WeChatApi.ets` - 删除 `sendShare`、`ShareRespCallback`、`routeResp` 中 `SendMessageToWXResp` 分支及其 import。 - **保留**授权登录路径(`sendAuth`/`handleWant`/`SendAuthResp`)。 ### 7.4 `entry/src/main/module.json5` - `querySchemes` 增加 `"mqqapi"`、`"snssdk1128"`(连同现有 `"weixin"`)。 ### 7.5 依赖 - **保留** `@tencent/wechat_open_sdk`(登录仍依赖;登录代码不动)。 ### 7.6 支付边界(确认现状已满足,无需删依赖) - `PayStubProvider` 已是 void 空桩(`PayBrowser`/`GetGameplay` noop、不出站、无 SDK)。 - 全工程无独立支付依赖;module.json5 无支付 scheme。 - **结论**:支付「移除依赖和逻辑、留空桩」诉求**已天然满足**,本期不改支付代码;仅在 spec 记录该结论。 ## 8. 不做(YAGNI / 延期) - 不接微信/QQ/抖音任何分享 SDK(tier1 直分享、选好友)→ 后续延期项(依赖外部注册)。 - 不实现 QQ/抖音 `sharesuccess` 回传(契约允许其无回传)。 - 不新增任何对外 handler;不改 H5。 ## 9. 测试与验收 - 单元测试(`entry/src/test`,纯逻辑):`buildShareText` 统一格式、空字段裁剪、`type`/`sharefriend` 分支映射(含 type4 安全空实现不报错)。 - 设备验证(真机/模拟器): - `friendsSharetypeUrlToptitleDescript` 各 `type`/`sharefriend` 组合弹窗正确、剪贴板内容正确、指引窗「系统分享」可拉起(文本 systemText / 图片 systemImage)。 - **人工真机验证(需配合)**:图片 PIXELMAP 复制后能否在微信/QQ 鸿蒙版对话框长按粘贴出图片——结果登记到风险册,决定是否保留剪贴板图片这条尽力路径。 - 微信渠道 `sharesuccess` 乐观回传时机正确;QQ/抖音不回传。 - `devecocli build` 通过、`code-linter` 无新增告警。 - 验收基线:H5 调用全程不报错、不卡死(`DefaultHandler` 兜底仍在)。 ## 10. 风险 - **拉起 App 仅"打开"不预填**:`openLink(scheme)` 只能打开 App,用户需手动粘贴;体验弱于原工程微信 SDK,已与用户确认接受。 - **scheme 可用性**:`mqqapi`/`snssdk1128` 能否 `canOpenLink` 取决于对方鸿蒙版注册情况;不可用时指引窗降级为纯文案提示,不报错。 - **图片剪贴板粘贴不可保证**:微信/QQ 鸿蒙版是否支持读取 PIXELMAP 类型剪贴板未知(且 API 12+ 读剪贴板有权限管控);故图片以指引窗内 `systemImage`(系统分享)为可靠交付,剪贴板图片仅尽力而为。待人工真机验证后登记风险册。