Files
youle_app_ios_v2/ylgamehall/Source/Bridge/Handlers/FriendsShareHandler.swift
T
joywayer a1332ed942 4.B FriendsShareHandler 加调试日志:原始 JSON + 解析字段 + 分发 mode
H5 调用分享接口时,按以下顺序输出到 Console(subsystem=ylgamehall,
category=FriendsShare):

  ← H5 friendsShare mode=lobby raw={"sharefriend":"1",...}
  friendsShare parsed:
    sharefriend = "1"  (1=好友/SharePanel, 2/其他=朋友圈)
    sharetype   = "1"  (1/2=微信, 3=闲聊;新外壳忽略)
    type        = "1"  (1=链接, 2=截图, 其他=远端图)
    webpageUrl  = "https://..."
    title       = "..."
    description = "..."
  → H5 sharesuccess fired: success="2", type="1"
  dispatch → lobby (直发微信 3 type 分支)

raw 字段直接 JSONSerialization 序列化整个 BridgeData,含 H5 传入的所有
键(不限于上面解析的 6 项),便于排查 H5 端偷偷加字段或类型漂移。
2026-06-24 09:07:36 +08:00

115 lines
5.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.
//
// FriendsShareHandler.swift
// ylgamehall
//
// H5 → Native handlerfriendsSharetypeUrlToptitleDescript — 分享
// 契约:docs/H5-Native-Contract.md §3.1 2 + §3.2 11sharesuccess
//
// **页面 mode 区分**(与原 msext 两个 ViewController 各注册一份且行为不同对齐):
// - `.lobby` 对应 NewRootVC.m:直发微信,3 type 分支(链接 / 截图 / 远端图)
// - `.subGame` 对应 gameController.m 活路径:SharePanel 三选一 + 朋友圈兜底
//
// 公共流程(无论 mode):
// 1. responseCallback("sharefriend")
// 2. 立即 bridge.call("sharesuccess", { success:"2", type:<sharefriend 原值> })
// (**有意为之**:调用分享接口即视为成功;URL Scheme / 剪贴板路径本就无返回)
// 3. 按 mode 异步 fire-and-forget 拉起 UI
//
// 各平台 SDK 依赖:
// - 微信:通过 WeChatManager(已接入 1.8.2 SDK
// - QQ + 抖音:不依赖 SDK,走 URL Scheme + 剪贴板(CLAUDE.md ADR-006
//
import Foundation
import os.log
@MainActor
public enum FriendsShareHandler {
private static let log = Logger(subsystem: "ylgamehall", category: "FriendsShare")
/// 注册时机的页面 mode。
public enum Mode: Sendable {
/// 大厅页:H5 在 WebContainer 调 friendsShare 时直发微信
case lobby
/// 子游戏页:H5 在 SubGame 调 friendsShare 时弹 SharePanel 或朋友圈兜底
case subGame
}
public static func register(on bridge: any BridgeProtocol, mode: Mode) {
// 【2】friendsSharetypeUrlToptitleDescript
// 入参:sharefriend / sharetype / type / webpageUrl / title / description
// cb: "sharefriend"msext 字面,沿用)
// 反向 callbacksharesuccess({ success: "2", type: sharefriend 原值 })
bridge.register("friendsSharetypeUrlToptitleDescript") { [weak bridge] data, callback in
// 1. responseCallback —— msext 字面 "sharefriend"
callback?(.string("sharefriend"))
await MainActor.run {
// 0. 调试日志:H5 传入的原始 JSON(含未声明字段,便于排查 H5 端字段漂移)
Self.log.debug("← H5 friendsShare mode=\(String(describing: mode), privacy: .public) raw=\(Self.describe(data), privacy: .public)")
guard let obj = data?.asObject else {
Self.log.error("friendsShare: data 不是 object,跳过分发")
return
}
let content = ShareContent(
// 缺失默认空串 → ShareCenter default 分支兜底(与原 msext [nil intValue]==0 等价)
sharefriend: obj["sharefriend"]?.asString ?? "",
sharetype: obj["sharetype"]?.asString ?? "",
type: obj["type"]?.asString ?? "",
webpageUrl: obj["webpageUrl"]?.asString ?? "",
title: obj["title"]?.asString ?? "",
desc: obj["description"]?.asString ?? ""
)
// 调试日志:解析后的 ShareContent 各字段(带语义注释方便定位行为分支)
Self.log.debug("""
friendsShare parsed:
sharefriend = "\(content.sharefriend, privacy: .public)" (1=好友/SharePanel, 2/其他=朋友圈)
sharetype = "\(content.sharetype, privacy: .public)" (1/2=微信, 3=闲聊;新外壳忽略)
type = "\(content.type, privacy: .public)" (1=链接, 2=截图, 其他=远端图)
webpageUrl = "\(content.webpageUrl, privacy: .public)"
title = "\(content.title, privacy: .public)"
description = "\(content.desc, privacy: .public)"
""")
// 2. 立即触发 sharesuccess —— 有意为之:调用即视为成功
bridge?.call(
"sharesuccess",
data: .object([
"success": .string("2"),
"type": .string(content.sharefriend)
]),
callback: nil
)
Self.log.debug("→ H5 sharesuccess fired: success=\"2\", type=\"\(content.sharefriend, privacy: .public)\"")
// 3. fire-and-forget 拉起真实分享 UI(按页面 mode 选路径)
switch mode {
case .lobby:
Self.log.debug("dispatch → lobby (直发微信 3 type 分支)")
ShareCenter.dispatchLobby(content)
case .subGame:
Self.log.debug("dispatch → subGame (SharePanel 或朋友圈兜底)")
ShareCenter.dispatchSubGame(content)
}
}
}
}
/// 把 BridgeData 整体序列化为 JSON 字符串方便日志输出(含 H5 传入的所有字段,
/// 不限于上面解析的 6 项 —— 万一 H5 偷偷加了字段也能看到)。
private static func describe(_ data: BridgeData?) -> String {
guard let data else { return "<nil>" }
let raw = data.jsonObject
if let bytes = try? JSONSerialization.data(
withJSONObject: raw,
options: [.fragmentsAllowed, .sortedKeys]
), let s = String(data: bytes, encoding: .utf8) {
return s
}
return String(describing: raw)
}
}