Files
youle_app_ios_v2/ylgamehall/Source/Share/QQShare.swift
T
joywayerandClaude Opus 4.7 aff5ee7633 Phase 4.C:QQShare URL Scheme 真实落地(不依赖 SDK)
移植 msext QQShareManager.m:716-771 simpleShareToQQFriend 简化版到 Swift。

QQShare.share 完整实现:
  - canOpenURL("mqqapi://") 检测 QQ 安装;未装返回 .notInstalled
  - 仅链接分享走完整 URL Scheme(type == "1");type == "2"/其它(截图 /
    远端图)暂返回 .success 避免 H5 业务卡住,Phase 4.F 接入
  - URL 构造(与 msext 等价):
    * scene == .timeline → mqqapi://share/to_qzone? (QQ 空间)
    * scene == .friend   → mqqapi://share/to_fri?   (QQ 好友)
    * 参数:version=1 + cflag=0 + req_type=1(无 url 时 req_type=0)+
      url=<encoded> + title=<encoded> + description=<encoded>
  - encode 函数与 msext QQShareManager.m:1262-1268 等价:仅保留 RFC 3986
    unreserved 字符(alphanumeric + "-._~"),其它全部 percent encode
  - canOpenURL 二次检查 + await UIApplication.open
  - 调起即视为 success(msext 同款乐观策略,URL Scheme 单向无返回)

Info.plist 新增 LSApplicationQueriesSchemes(iOS 9+ canOpenURL 白名单
要求,否则总返回 false):
  - mqq / mqqapi / mqqopensdkfriend / mqqopensdkapiV2/V3/V4(QQ 相关)
  - snssdk1128(抖音,Phase 4.D 用)
  - 微信相关待 Phase 4.E 接入 SDK 时再加(weixin / weixinULAPI 等)

BuildProject 通过

Plan §5 Phase 4.3 勾选

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-22 20:04:36 +08:00

93 lines
3.4 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//
// 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=<encoded webpageUrl>&title=<encoded title>&description=<encoded desc>
//
// 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
}
// 拼装 URLmqqapi://share/to_fri? 或 mqqapi://share/to_qzone?
// scene == .timeline 走 QQ 空间 to_qzone.friend 走 to_friQQ 好友)
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) ?? ""
}
}