4.B 截图分享补齐 msext 字段:WeChat description / QQ 引导框

【契约影响】docs/H5-Native-Contract.md §3.1[2]type==2 分支

WeChat 截图分享之前丢了 H5 description(msext 通过
sendImageData:MessageExt: 写到 WXMediaMessage.description,接收方在
微信聊天预览里能看到)。链接分享之前完全没传 thumb(msext 用 app
icon)。统一补齐:

- WeChatManager.ShareImage 加 messageExt / mediaTagName 字段;
  shareImage 内 message.description = messageExt + message.messageExt
  = messageExt + setThumbImage(thumb) + mediaTagName
- WeChatManager.ShareLink 把 thumbnailURL: String? 替换为 thumb:
  UIImage?;shareLink 内 setThumbImage(thumb) + mediaTagName。drop
  Sendable 因 UIImage 不可 Sendable(调用都在 MainActor 上无风险)
- WechatShare 双分支统一传 appIconImage() 做 thumb;截图分支 messageExt
  = content.desc + mediaTagName "进贤聚友棋牌游戏截图分享";链接分支
  mediaTagName "进贤聚友棋牌游戏分享"(字面对齐 msext WechatShareManager.m)

QQ 截图分享原本 4-fallback URL 链不靠谱(file_type=news 给截图场景实际
无意义)。简化为 Douyin 同款模式:截图 → UIPasteboard.image → 弹"立即
打开 QQ / 稍后分享"二选一 Alert。承认 ADR-006 无 QQ SDK 退化的现实,
但 UX 不再让用户摸不着北。
This commit is contained in:
joywayer
2026-06-24 07:53:14 +08:00
parent 9bd5a81e6c
commit 68c668a06c
3 changed files with 109 additions and 34 deletions
+48 -16
View File
@@ -4,11 +4,11 @@
//
// QQ SharePlatform daoqi msext QQShareManager
// `shareWithContent:completion:` type
// - type == "2" UIPasteboard + mqqapi://
// - type == "2" UIPasteboard + " QQ"
// - else mqqapi://share/to_fri?req_type=1&url=...
//
// ** QQ SDK**CLAUDE.md ADR-006 SDK
// URL Scheme + pasteboard UX
// ** QQ SDK**CLAUDE.md ADR-006 SDK
// SDK 退" + " Douyin UX
//
// encodeString msext line 1262-1268 unreserved RFC 3986
// alphanumeric + "-._~" percent encode
@@ -49,27 +49,59 @@ public final class QQShare: SharePlatform {
/// msext QQShareManager.m:1876-1906 isScreenshotShare
/// QQ SDK shareToQQFriend QQShareTypeImage UIImage SDK
/// SDK 退 pasteboard QQ
/// SDK 退 UIPasteboard.image " QQ"
/// UX DouyinShare SDK
private func shareScreenshot() {
do {
let shot = try ImageProvider.captureScreenshot()
UIPasteboard.general.image = shot
Self.log.debug("QQShare 截图已复制到剪贴板")
} catch {
Self.log.error("QQShare 截图失败 \(error.localizedDescription, privacy: .public)")
}
let candidates = [
"mqqapi://share/to_fri?file_type=news&version=1&cflag=0",
"mqq://im/chat?chat_type=select",
"mqqapi://",
"mqq://"
]
for s in candidates {
guard let url = URL(string: s),
UIApplication.shared.canOpenURL(url) else { continue }
UIApplication.shared.open(url)
return
}
let message = """
✅ 图片已复制到剪贴板
🎯 分享到好友或群聊步骤:
1️⃣ 打开 QQ,选择好友或群聊进入聊天
2️⃣ 在输入框长按粘贴图片
3️⃣ 点击发送即可分享
"""
showGuidanceAlert(title: "QQ 分享准备完成", message: message)
}
/// " QQ / " Alert DouyinShare UX
private func showGuidanceAlert(title: String, message: String) {
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "立即打开 QQ", style: .default) { _ in
if let url = URL(string: "mqqapi://"),
UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url)
} else if let url = URL(string: "mqq://"),
UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url)
}
})
alert.addAction(UIAlertAction(title: "稍后分享", style: .cancel))
guard let topVC = Self.topViewController() else { return }
topVC.present(alert, animated: true)
}
private static func topViewController() -> UIViewController? {
let scene = UIApplication.shared.connectedScenes
.compactMap { $0 as? UIWindowScene }
.first(where: { $0.activationState == .foregroundActive })
?? UIApplication.shared.connectedScenes.compactMap { $0 as? UIWindowScene }.first
guard var top = scene?.windows.first(where: \.isKeyWindow)?.rootViewController
?? scene?.windows.first?.rootViewController else { return nil }
while let presented = top.presentedViewController { top = presented }
if let nav = top as? UINavigationController, let visible = nav.visibleViewController {
return visible
}
return top
}
// MARK: -