Files
youle_app_ios_v2/ylgamehall/Source/Share/DouyinShare.swift
T
joywayer 9bd5a81e6c 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
2026-06-24 07:34:03 +08:00

136 lines
5.0 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.
//
// DouyinShare.swift
// ylgamehall
//
// 抖音分享 SharePlatform 实现,1:1 对齐 daoqi msext DouyinShareManager
// `shareWithContent:completion:`(按 type 分两个分支):
// - type == "2" → 截图分享:截图 → UIPasteboard → 弹"立即打开抖音"引导框
// - else → 文字分享:title + "\n\n" + desc → UIPasteboard → 弹引导框
//
// **不依赖抖音 SDK**CLAUDE.md ADR-006):抖音的图片 / 文本分享原本就是
// 剪贴板 + 引导用户在抖音内粘贴的非 SDK 路径,新外壳照搬。
//
// fire-and-forgetsharesuccess 已在 FriendsShareHandler 立即触发。
//
import UIKit
import os.log
@MainActor
public final class DouyinShare: SharePlatform {
public static let shared = DouyinShare()
private static let log = Logger(subsystem: "ylgamehall", category: "DouyinShare")
private static let douyinScheme = "snssdk1128://"
public let name = "Douyin"
public var isInstalled: Bool {
guard let url = URL(string: Self.douyinScheme) else { return false }
return UIApplication.shared.canOpenURL(url)
}
public init() {}
public func share(_ content: ShareContent, scene: ShareScene) {
guard isInstalled else { return }
if content.type == "2" {
shareScreenshot()
} else {
shareText(content)
}
}
// MARK: - 截图分享
/// 对齐 msext DouyinShareManager.m:139-162 isScreenshotShare 分支:
/// 截图 → pasteboard.image → 弹引导框(不自动拉起抖音,等用户点"立即打开")。
private func shareScreenshot() {
do {
let shot = try ImageProvider.captureScreenshot()
UIPasteboard.general.image = shot
Self.log.debug("DouyinShare 截图已复制到剪贴板")
} catch {
Self.log.error("DouyinShare 截图失败 \(error.localizedDescription, privacy: .public)")
return
}
let message = """
✅ 图片已复制到剪贴板
🎯 分享到好友或群聊步骤:
1️⃣ 打开抖音,点击右下角「消息」
2️⃣ 选择好友或群聊进入聊天
3️⃣ 在输入框长按粘贴图片
4️⃣ 点击发送即可分享
"""
showGuidanceAlert(title: "抖音分享准备完成", message: message)
}
// MARK: - 文字分享
/// 对齐 msext DouyinShareManager.m:163-196 else 分支:
/// title + "\n\n" + desc 拼字符串 → pasteboard.string → 弹引导框。
/// 双侧都空时用 msext 同款兜底文案"来自进贤聚友棋牌的精彩内容分享"。
private func shareText(_ content: ShareContent) {
var shareText = ""
if !content.title.isEmpty {
shareText = content.title
}
if !content.desc.isEmpty {
shareText = shareText.isEmpty ? content.desc : "\(shareText)\n\n\(content.desc)"
}
if shareText.isEmpty {
shareText = "来自进贤聚友棋牌的精彩内容分享"
}
UIPasteboard.general.string = shareText
Self.log.debug("DouyinShare 文字已复制到剪贴板")
let message = """
✅ 内容已复制到剪贴板
🎯 分享到好友或群聊步骤:
1️⃣ 打开抖音,点击右下角「消息」
2️⃣ 选择好友或群聊进入聊天
3️⃣ 在输入框长按粘贴内容
4️⃣ 点击发送即可分享
"""
showGuidanceAlert(title: "抖音分享准备完成", message: message)
}
// MARK: - 引导弹窗
/// 弹"立即打开抖音 / 稍后分享"二选一 Alert,对齐 msext
/// `showGuidanceAlertWithTitle:message:`。
private func showGuidanceAlert(title: String, message: String) {
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "立即打开抖音", style: .default) { _ in
if let url = URL(string: Self.douyinScheme),
UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url)
}
})
alert.addAction(UIAlertAction(title: "稍后分享", style: .cancel))
guard let topVC = Self.topViewController() else { return }
topVC.present(alert, animated: true)
}
private static func topViewController() -> UIViewController? {
let scene = UIApplication.shared.connectedScenes
.compactMap { $0 as? UIWindowScene }
.first(where: { $0.activationState == .foregroundActive })
?? UIApplication.shared.connectedScenes.compactMap { $0 as? UIWindowScene }.first
guard var top = scene?.windows.first(where: \.isKeyWindow)?.rootViewController
?? scene?.windows.first?.rootViewController else { return nil }
while let presented = top.presentedViewController { top = presented }
if let nav = top as? UINavigationController, let visible = nav.visibleViewController {
return visible
}
return top
}
}