微信分享去sdk

This commit is contained in:
joywayer
2026-06-30 17:41:10 +08:00
parent c1e51d2183
commit 113b4d4960
7 changed files with 227 additions and 171 deletions
@@ -2,10 +2,11 @@
// WeChatManager.swift
// ylgamehall
//
// 微信 SDK 持久 delegate + authorize + share 异步包装。
// 把 WXApiDelegate 的回调 → async/await,state UUID 配对多发起方。
// 微信 SDK 持久 delegate + authorize 异步包装。
// 把 WXApiDelegate 的 onResp 回调 → async/await,state UUID 配对多发起方。
//
// Design §8.5;msext WXApiManager.m 等价。
// 注:分享路径已改走剪贴板 + 引导框(详见 WechatShare.swift),不再依赖
// 微信 SDK 的 SendMessageToWXReq;本类只剩登录 OAuth 链路。
//
import Foundation
@@ -23,8 +24,6 @@ public final class WeChatManager: NSObject {
/// 待 resolve 的 authorize continuation(state UUID 配对)
private var authPending: [String: CheckedContinuation<WXAuthCodePayload, Error>] = [:]
/// 待 resolve 的 share continuation(FIFO 串行 — 微信回包不带配对 ID)
private var sharePending: [CheckedContinuation<Void, Error>] = []
public override init() {
super.init()
@@ -84,125 +83,6 @@ public final class WeChatManager: NSObject {
return top
}
// MARK: - Share
public enum ShareScene {
case session // 微信好友
case timeline // 朋友圈
}
/// 链接分享载荷。`mediaTagName` 对齐 msext WXApiRequestHandler `TagName:`
/// 参数(写入 WXMediaMessage.mediaTagName,微信内部分类用)。
/// 含 UIImage 故无法 Sendable —— 实际使用都在 MainActor 上发起,无跨 actor 风险。
public struct ShareLink {
public let url: String
public let title: String
public let desc: String
public let thumb: UIImage?
public let mediaTagName: String?
public init(
url: String, title: String, desc: String,
thumb: UIImage?, mediaTagName: String? = nil
) {
self.url = url; self.title = title; self.desc = desc
self.thumb = thumb; self.mediaTagName = mediaTagName
}
}
/// 图片分享载荷(type=2 截图)。
/// - `imageData`:大图原始字节(JPEG)
/// - `thumb`:缩略图源 — SDK `setThumbImage:` 内部压到 32KB
/// - `messageExt`:H5 的 description;写入 `WXMediaMessage.description`
/// 与 `.messageExt`,对齐 msext `WXApiRequestHandler sendImageData:MessageExt:`
/// - `mediaTagName`:对齐 msext `TagName:` 参数
public struct ShareImage {
public let imageData: Data
public let thumb: UIImage
public let messageExt: String
public let mediaTagName: String?
public init(
imageData: Data, thumb: UIImage,
messageExt: String = "", mediaTagName: String? = nil
) {
self.imageData = imageData
self.thumb = thumb
self.messageExt = messageExt
self.mediaTagName = mediaTagName
}
}
/// 链接分享(FIFO 串行)。微信回包不携带配对 ID,连续调时按入队顺序消费。
public func shareLink(_ link: ShareLink, scene: ShareScene) async throws {
try await withCheckedThrowingContinuation { (cont: CheckedContinuation<Void, Error>) in
sharePending.append(cont)
let media = WXWebpageObject()
media.webpageUrl = link.url
let message = WXMediaMessage()
message.title = link.title
message.description = link.desc
message.mediaObject = media
if let mediaTagName = link.mediaTagName {
message.mediaTagName = mediaTagName
}
if let thumb = link.thumb {
message.setThumbImage(thumb)
}
let req = SendMessageToWXReq()
req.bText = false
req.message = message
switch scene {
case .session: req.scene = Int32(WXSceneSession.rawValue)
case .timeline: req.scene = Int32(WXSceneTimeline.rawValue)
}
// 1.x: sendReq BOOL 返回;分享回包通过 SceneDelegate.openURLContexts →
// WXApi.handleOpen(url:delegate:WeChatManager.shared) → onResp 路径到达。
// ObjC selector +sendReq:,Swift 简化为 send(_:)(去 Req 后缀)。
// 运行时仍调 +[WXApi sendReq:]
WXApi.send(req)
}
}
/// 图片分享(FIFO 串行,复用 sharePending)。对齐 msext WechatShareManager
/// `sendImageData:TagName:MessageExt:Action:ThumbImage:InScene:` 的字段映射:
/// TagName → mediaTagName
/// MessageExt → description(接收方预览可见)+ messageExt(SDK 内部回包)
/// ThumbImage → setThumbImage
public func shareImage(_ img: ShareImage, scene: ShareScene) async throws {
try await withCheckedThrowingContinuation { (cont: CheckedContinuation<Void, Error>) in
sharePending.append(cont)
let media = WXImageObject()
media.imageData = img.imageData
let message = WXMediaMessage()
message.description = img.messageExt
message.mediaObject = media
message.setThumbImage(img.thumb)
if !img.messageExt.isEmpty {
message.messageExt = img.messageExt
}
if let mediaTagName = img.mediaTagName {
message.mediaTagName = mediaTagName
}
let req = SendMessageToWXReq()
req.bText = false
req.message = message
switch scene {
case .session: req.scene = Int32(WXSceneSession.rawValue)
case .timeline: req.scene = Int32(WXSceneTimeline.rawValue)
}
// ObjC selector +sendReq:,Swift 简化为 send(_:)(去 Req 后缀)。
// 运行时仍调 +[WXApi sendReq:]
WXApi.send(req)
}
}
// MARK: - Internal: resolve callbacks
fileprivate func resolveAuth(state: String, code: String?, errCode: Int) {
@@ -213,16 +93,6 @@ public final class WeChatManager: NSObject {
cont.resume(throwing: WeChatError.authFailed(errCode))
}
}
fileprivate func resolveShare(errCode: Int) {
guard !sharePending.isEmpty else { return }
let cont = sharePending.removeFirst()
if errCode == 0 {
cont.resume(returning: ())
} else {
cont.resume(throwing: WeChatError.shareFailed(errCode))
}
}
}
// MARK: - WXApiDelegate
@@ -242,11 +112,8 @@ extension WeChatManager: WXApiDelegate {
Task { @MainActor in
Self.shared.resolveAuth(state: state, code: code, errCode: errCode)
}
} else if resp is SendMessageToWXResp {
Task { @MainActor in
Self.shared.resolveShare(errCode: errCode)
}
}
// 分享走剪贴板路径(WechatShare),不再有 SendMessageToWXResp 回包
}
}
@@ -260,5 +127,4 @@ public struct WXAuthCodePayload: Sendable {
public enum WeChatError: Error, Sendable {
case sdkNotLinked
case authFailed(Int)
case shareFailed(Int)
}