// // QQShare.swift // ylgamehall // // QQ 分享 SharePlatform 实现(Phase 4.C 完整)。 // // 移植 msext QQShareManager.m:716-771 simpleShareToQQFriend 的 URL Scheme // fallback。**不依赖 QQ SDK**。 // // URL 构造: // mqqapi://share/to_fri?version=1&cflag=0&req_type=1 // &url=&title=&description= // // encodeString 与 msext line 1262-1268 等价:unreserved 字符集(RFC 3986 // alphanumeric + "-._~"),其它全部 percent encode。 // // ⚠️ 当前仅支持链接分享(type == "1")。type == "2" 截图 / 其它 远端图 // 在 Phase 4.F 接入(依赖 UIGraphicsImageRenderer + Photos / 临时文件 + // mqqapi://share/to_fri?file_type=img 路径)。 // import UIKit import os.log @MainActor public final class QQShare: SharePlatform { public static let shared = QQShare() private static let log = Logger(subsystem: "ylgamehall", category: "QQShare") public let name = "QQ" public var isInstalled: Bool { guard let url = URL(string: "mqqapi://") else { return false } return UIApplication.shared.canOpenURL(url) } public init() {} public func share(_ content: ShareContent, scene: ShareScene) async -> ShareResult { guard isInstalled else { return .notInstalled(platform: name) } // 仅链接分享走完整 URL Scheme;图片分享留 Phase 4.F guard content.type == "1" else { Self.log.warning("QQShare: type=\(content.type, privacy: .public) (非链接) 暂未实现,返回 success 避免 H5 业务卡住") return .success } // 拼装 URL:mqqapi://share/to_fri? 或 mqqapi://share/to_qzone? // scene == .timeline 走 QQ 空间 to_qzone;.friend 走 to_fri(QQ 好友) let host = scene == .timeline ? "share/to_qzone" : "share/to_fri" var parts: [String] = [ "version=1", "cflag=0", "req_type=1" ] if !content.webpageUrl.isEmpty { parts.append("url=\(Self.encode(content.webpageUrl))") } else { // 无 URL → 改 req_type=0 文本分享 parts = ["version=1", "cflag=0", "req_type=0"] } if !content.title.isEmpty { parts.append("title=\(Self.encode(content.title))") } if !content.desc.isEmpty { parts.append("description=\(Self.encode(content.desc))") } let urlString = "mqqapi://\(host)?\(parts.joined(separator: "&"))" Self.log.debug("QQShare open: \(urlString, privacy: .public)") guard let qqURL = URL(string: urlString), UIApplication.shared.canOpenURL(qqURL) else { return .failed(reason: "invalid QQ URL") } // URL Scheme 单向调起:msext 同款乐观策略 — 调起即视为 success let opened = await UIApplication.shared.open(qqURL) return opened ? .success : .failed(reason: "openURL failed") } /// 与 msext QQShareManager.m:1262-1268 等价:仅保留 RFC 3986 unreserved /// 字符(alphanumeric + "-._~"),其它全部 percent encode。 nonisolated static func encode(_ string: String) -> String { var allowed = CharacterSet.alphanumerics allowed.insert(charactersIn: "-._~") return string.addingPercentEncoding(withAllowedCharacters: allowed) ?? "" } }