4.B 分享逻辑对齐 daoqi msext:调用即触发 sharesuccess
【契约影响】docs/H5-Native-Contract.md §3.1[2]/§3.2[11]
H5 端 sharesuccess 时机改为"调用 friendsShare handler 即立刻发",与
原 msext 行为等价(live path 完全不等 SDK / URL Scheme 回包)。用户
明示有意为之:URL Scheme + 剪贴板路径本就没有可靠回包,乐观策略避免
H5 业务卡住。
3 平台分支严格 1:1 对齐 daoqi msext:
WechatShare(对齐 WechatShareManager shareWithContent)
- type=="2" → 截图 JPEG 0.6 + sendImageData + app icon thumb
- else → 链接分享 sendLinkURL + app icon thumb
- 移除原"远端图"分支(原项目无此分支)
- 新增 appIconImage helper(读 Info.plist CFBundleIcons,对齐
[self getAppIconImage])
QQShare(对齐 QQShareManager shareWithContent + simpleShareToQQFriend)
- type=="2" → 截图 → UIPasteboard.image → 4 URL Scheme fallback
- else → mqqapi://share/to_{fri,qzone}?req_type=1&url=...
&title=...&description=...(webpageUrl 空时 req_type=0)
- 不依赖 QQ SDK(CLAUDE.md ADR-006)
DouyinShare(对齐 DouyinShareManager shareWithContent)
- type=="2" → 截图 → UIPasteboard.image → "立即打开抖音"引导框
- else → title+"\n\n"+desc → UIPasteboard.string → 引导框
双侧空时兜底 "来自进贤聚友棋牌的精彩内容分享"
- 放弃之前的"存相册 + 自动拉起"激进路径,回到原项目"用户主动点"路径
架构调整:
- SharePlatform.share 改 sync fire-and-forget(去 ShareResult 返回)
- ShareCenter.dispatch / SharePanel.show 去 completion 参数
- FriendsShareHandler:解析后先发 responseCallback("sharefriend")
与 sharesuccess({success:"2", type:<sharefriend>}),再异步 dispatch
This commit is contained in:
@@ -2,17 +2,20 @@
|
||||
// WechatShare.swift
|
||||
// ylgamehall
|
||||
//
|
||||
// 微信分享 SharePlatform 实现。
|
||||
// 微信分享 SharePlatform 实现,1:1 对齐 daoqi msext WechatShareManager
|
||||
// `shareWithContent:completion:`(仅两个分支):
|
||||
// - type == "2" → 截图分享(getImageWithFullScreenshot + JPEG 0.6 + sendImageData)
|
||||
// - else → 链接分享(sendLinkURL + webpageUrl + title + desc)
|
||||
//
|
||||
// ⚠️ canImport(WechatOpenSDK) 守卫:SDK 未链接前 isInstalled = true / share = .success
|
||||
// 让 SharePanel 按钮可点;项目方在 Xcode Embed & Sign 后真实路径激活。
|
||||
// 缩略图:app icon(与原 `[self getAppIconImage]` 同源策略,不用 sharelogo)。
|
||||
//
|
||||
// fire-and-forget:H5 端的 sharesuccess 已在 FriendsShareHandler 立即触发,
|
||||
// 此处不再回传结果(与原 dispatch_after 1s completion(YES) 实质等价)。
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
// 微信 SDK 1.8.2 通过 Bridging Header 导入,无 import 语句
|
||||
|
||||
@MainActor
|
||||
public final class WechatShare: SharePlatform {
|
||||
|
||||
@@ -26,55 +29,53 @@ public final class WechatShare: SharePlatform {
|
||||
|
||||
public init() {}
|
||||
|
||||
public func share(_ content: ShareContent, scene: ShareScene) async -> ShareResult {
|
||||
guard WXApi.isWXAppInstalled() else {
|
||||
return .notInstalled(platform: name)
|
||||
}
|
||||
public func share(_ content: ShareContent, scene: ShareScene) {
|
||||
guard WXApi.isWXAppInstalled() else { return }
|
||||
|
||||
let wxScene: WeChatManager.ShareScene = (scene == .timeline) ? .timeline : .session
|
||||
do {
|
||||
switch content.type {
|
||||
case "1":
|
||||
// 链接分享(msext gameController.m:613-635)
|
||||
try await WeChatManager.shared.shareLink(
|
||||
.init(
|
||||
url: content.webpageUrl,
|
||||
title: content.title,
|
||||
desc: content.desc,
|
||||
thumbnailURL: nil
|
||||
),
|
||||
scene: wxScene
|
||||
)
|
||||
case "2":
|
||||
// 截图分享(msext gameController.m:637-658)
|
||||
let shot = try ImageProvider.captureScreenshot()
|
||||
guard let imageData = shot.jpegData(compressionQuality: 0.6) else {
|
||||
return .failed(reason: "screenshot JPEG encode failed")
|
||||
let thumb = Self.appIconImage()
|
||||
|
||||
Task { @MainActor in
|
||||
do {
|
||||
if content.type == "2" {
|
||||
// 截图分享(msext WechatShareManager isScreenshotShare 分支)
|
||||
let shot = try ImageProvider.captureScreenshot()
|
||||
guard let imageData = shot.jpegData(compressionQuality: 0.6) else { return }
|
||||
try await WeChatManager.shared.shareImage(
|
||||
.init(imageData: imageData, thumb: thumb),
|
||||
scene: wxScene
|
||||
)
|
||||
} else {
|
||||
// 链接分享(msext else 分支,含 type=="1" 与任何其它值)
|
||||
try await WeChatManager.shared.shareLink(
|
||||
.init(
|
||||
url: content.webpageUrl,
|
||||
title: content.title,
|
||||
desc: content.desc,
|
||||
thumbnailURL: nil
|
||||
),
|
||||
scene: wxScene
|
||||
)
|
||||
}
|
||||
let thumb = ImageProvider.scaledThumb(shot)
|
||||
try await WeChatManager.shared.shareImage(
|
||||
.init(imageData: imageData, thumb: thumb),
|
||||
scene: wxScene
|
||||
)
|
||||
default:
|
||||
// 远端图分享(msext gameController.m:659-680:type 是其它值就当 URL 远端图)
|
||||
let remote = try await ImageProvider.downloadRemote(content.webpageUrl)
|
||||
// msext 直接用原始 data 作为大图;这里 UIImage 已是 decode 后的,
|
||||
// 用 jpegData 重新编码维持等价(避免持有未压缩的原始字节膨胀)。
|
||||
guard let imageData = remote.jpegData(compressionQuality: 0.9) else {
|
||||
return .failed(reason: "remote image JPEG encode failed")
|
||||
}
|
||||
let thumb = ImageProvider.scaledThumb(remote)
|
||||
try await WeChatManager.shared.shareImage(
|
||||
.init(imageData: imageData, thumb: thumb),
|
||||
scene: wxScene
|
||||
)
|
||||
} catch {
|
||||
// SDK 回包失败不向 H5 反馈(sharesuccess 已乐观发出,对齐原项目)
|
||||
}
|
||||
return .success
|
||||
} catch let WeChatError.shareFailed(errCode) {
|
||||
if errCode == -2 { return .cancelled }
|
||||
return .failed(reason: "WeChat errCode \(errCode)")
|
||||
} catch {
|
||||
return .failed(reason: "\(error)")
|
||||
}
|
||||
}
|
||||
|
||||
/// app icon 缩略图。读 Info.plist `CFBundleIcons` → `CFBundlePrimaryIcon`
|
||||
/// → `CFBundleIconFiles` 的最后一个(最高分辨率),与原 msext
|
||||
/// WechatShareManager `getAppIconImage` 等价。失败兜底返回 1x1 透明图。
|
||||
private static func appIconImage() -> UIImage {
|
||||
if let icons = Bundle.main.object(forInfoDictionaryKey: "CFBundleIcons") as? [String: Any],
|
||||
let primary = icons["CFBundlePrimaryIcon"] as? [String: Any],
|
||||
let files = primary["CFBundleIconFiles"] as? [String],
|
||||
let last = files.last,
|
||||
let icon = UIImage(named: last) {
|
||||
return icon
|
||||
}
|
||||
if let icon = UIImage(named: "AppIcon") { return icon }
|
||||
let renderer = UIGraphicsImageRenderer(size: CGSize(width: 1, height: 1))
|
||||
return renderer.image { _ in }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user