diff --git a/ylgamehall/Source/SDK/WeChat/WeChatManager.swift b/ylgamehall/Source/SDK/WeChat/WeChatManager.swift index 3a1cd6f..c2fdc4a 100644 --- a/ylgamehall/Source/SDK/WeChat/WeChatManager.swift +++ b/ylgamehall/Source/SDK/WeChat/WeChatManager.swift @@ -69,6 +69,19 @@ public final class WeChatManager: NSObject { } } + /// 图片分享载荷(type=2 截图 / type=3 远端图)。 + /// imageData 是大图原始字节(JPEG 等),thumb 是缩略图源 — SDK + /// `setThumbImage:` 内部把 thumb 压到 32KB。 + public struct ShareImage { + public let imageData: Data + public let thumb: UIImage + + public init(imageData: Data, thumb: UIImage) { + self.imageData = imageData + self.thumb = thumb + } + } + /// 链接分享(FIFO 串行)。微信回包不携带配对 ID,连续调时按入队顺序消费。 public func shareLink(_ link: ShareLink, scene: ShareScene) async throws { #if canImport(WechatOpenSDK) @@ -97,6 +110,35 @@ public final class WeChatManager: NSObject { #endif } + /// 图片分享(FIFO 串行,复用 sharePending)。msext gameController.m:637-678 + /// type=2 截图 / type=其它 远端图 共用同一条 WXImageObject + setThumbImage 路径。 + public func shareImage(_ img: ShareImage, scene: ShareScene) async throws { + #if canImport(WechatOpenSDK) + try await withCheckedThrowingContinuation { (cont: CheckedContinuation) in + sharePending.append(cont) + + let media = WXImageObject() + media.imageData = img.imageData + + let message = WXMediaMessage() + // 图片分享不需要 title / description(msext 字面:传 nil;这里传空串等价) + message.mediaObject = media + message.setThumbImage(img.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) + } + WXApi.send(req) + } + #else + throw WeChatError.sdkNotLinked + #endif + } + // MARK: - Internal: resolve callbacks fileprivate func resolveAuth(state: String, code: String?, errCode: Int) { diff --git a/ylgamehall/Source/Share/ImageProvider.swift b/ylgamehall/Source/Share/ImageProvider.swift index 5e020c5..bdaaaa0 100644 --- a/ylgamehall/Source/Share/ImageProvider.swift +++ b/ylgamehall/Source/Share/ImageProvider.swift @@ -39,6 +39,22 @@ public enum ImageProvider { } } + /// 等比缩放图片用作微信分享的缩略图源。默认 0.4x 与 msext + /// `imageByScalingAndCroppingForSize:CGSizeMake(w*0.4, h*0.4)` 等价 + /// (gameController.m:656 / 677 字面常量)。微信 SDK `setThumbImage:` + /// 内部会再压缩至 32KB,外层只需把图像尺寸压低,避免传 4K 截图过 SDK 时 + /// 内部 JPEG 编码出超大缩略图。 + public static func scaledThumb(_ image: UIImage, scale: CGFloat = 0.4) -> UIImage { + let target = CGSize( + width: max(1, image.size.width * scale), + height: max(1, image.size.height * scale) + ) + let renderer = UIGraphicsImageRenderer(size: target) + return renderer.image { _ in + image.draw(in: CGRect(origin: .zero, size: target)) + } + } + /// 下载远端 URL → UIImage。仅简单 URLSession 同步路径,无重试 / 缓存。 public static func downloadRemote(_ urlString: String) async throws -> UIImage { guard let url = URL(string: urlString) else { diff --git a/ylgamehall/Source/Share/WechatShare.swift b/ylgamehall/Source/Share/WechatShare.swift index 1df2706..2c6d68a 100644 --- a/ylgamehall/Source/Share/WechatShare.swift +++ b/ylgamehall/Source/Share/WechatShare.swift @@ -9,6 +9,7 @@ // import Foundation +import UIKit #if canImport(WechatOpenSDK) import WechatOpenSDK @@ -37,18 +38,44 @@ public final class WechatShare: SharePlatform { return .notInstalled(platform: name) } let wxScene: WeChatManager.ShareScene = (scene == .timeline) ? .timeline : .session - // 当前仅链接分享(type == "1")走真实 SDK;截图 / 远端图分享待 Phase 4.F 接入 - // WXImageObject + WXMediaMessage.thumbData do { - try await WeChatManager.shared.shareLink( - .init( - url: content.webpageUrl, - title: content.title, - desc: content.desc, - thumbnailURL: nil // type=2/3 缩略图待 Phase 4.F - ), - scene: wxScene - ) + 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 = 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 + ) + } return .success } catch let WeChatError.shareFailed(errCode) { if errCode == -2 { return .cancelled }