4.B 分享按页面 mode 拆分:大厅直发微信 3 分支 / 子游戏 SharePanel
【契约影响】docs/H5-Native-Contract.md §3.1[2]
原 msext 把 friendsSharetypeUrlToptitleDescript 同名 handler 在两个 VC
各注册一份且**行为完全不同**:
- NewRootVC.m(大厅):直发微信,3 type 分支
type==1 sendLinkURL(sharelogo 缩略图)
type==2 sendImageData(截图 40% 缩放为 thumb)
其他 NSData fromURL → sendImageData(公众号二维码场景)
- gameController.m(子游戏,活路径,早 return):
sharefriend==1 SharePanel 三选一
其他 WechatShareManager 朋友圈兜底(2 分支:截图/链接)
先前新外壳两个 VC 都注册同一份 handler 走"子游戏"逻辑,导致大厅页:
1. 强行弹 SharePanel 多一步操作
2. 丢失"远端图"分支(公众号二维码被错当链接发)
按页面 mode 拆开:
- FriendsShareHandler 加 Mode { lobby, subGame } 参数
- ShareCenter 拆 dispatchLobby(直发微信)/ dispatchSubGame(SharePanel)
- WechatShare 加 shareLobby() 实现完整 3 type 分支:
type==1 → shareLink + mediaTagName "游戏下载链接" + appIcon thumb
(原 msext 用 sharelogo.png,按用户决定 fallback 到 app icon)
type==2 → shareImage + mediaTagName "游戏截图分享" + 截图 0.4x thumb
+ messageExt = H5 description
其他 → URLSession 下载 NSData 直发 + 远端图 0.4x thumb
+ mediaTagName/messageExt 固定字面"公众号二维码分享"
- WebContainerViewController 注册 .lobby;SubGameViewController .subGame
附带修 sharefriend 默认值:之前 ?? "1"(弹面板)与原 msext nil→[intValue]
==0→朋友圈微信不一致。改成 ?? "",由 ShareCenter default 分支兜底走
朋友圈微信,与原项目完全等价。
This commit is contained in:
@@ -5,13 +5,15 @@
|
|||||||
// H5 → Native handler:friendsSharetypeUrlToptitleDescript — 分享
|
// H5 → Native handler:friendsSharetypeUrlToptitleDescript — 分享
|
||||||
// 契约:docs/H5-Native-Contract.md §3.1 [2] + §3.2 [11]sharesuccess
|
// 契约:docs/H5-Native-Contract.md §3.1 [2] + §3.2 [11]sharesuccess
|
||||||
//
|
//
|
||||||
// 流程(与 msext gameController.m:575-597 等价,调用即视为成功):
|
// **页面 mode 区分**(与原 msext 两个 ViewController 各注册一份且行为不同对齐):
|
||||||
// 1. 入参解析 ShareContent
|
// - `.lobby` 对应 NewRootVC.m:直发微信,3 type 分支(链接 / 截图 / 远端图)
|
||||||
// 2. responseCallback("sharefriend")
|
// - `.subGame` 对应 gameController.m 活路径:SharePanel 三选一 + 朋友圈兜底
|
||||||
// 3. 立即 bridge.call("sharesuccess", { success:"2", type:<sharefriend 原值> })
|
//
|
||||||
// (**有意为之**:H5 端把"调用分享接口"等同"分享成功",无须等 SDK 回包;
|
// 公共流程(无论 mode):
|
||||||
// URL Scheme / 剪贴板路径本身就无返回。)
|
// 1. responseCallback("sharefriend")
|
||||||
// 4. 异步 fire-and-forget 调用 ShareCenter.dispatch 拉起真实分享 UI
|
// 2. 立即 bridge.call("sharesuccess", { success:"2", type:<sharefriend 原值> })
|
||||||
|
// (**有意为之**:调用分享接口即视为成功;URL Scheme / 剪贴板路径本就无返回)
|
||||||
|
// 3. 按 mode 异步 fire-and-forget 拉起 UI
|
||||||
//
|
//
|
||||||
// 各平台 SDK 依赖:
|
// 各平台 SDK 依赖:
|
||||||
// - 微信:通过 WeChatManager(已接入 1.8.2 SDK)
|
// - 微信:通过 WeChatManager(已接入 1.8.2 SDK)
|
||||||
@@ -23,7 +25,15 @@ import Foundation
|
|||||||
@MainActor
|
@MainActor
|
||||||
public enum FriendsShareHandler {
|
public enum FriendsShareHandler {
|
||||||
|
|
||||||
public static func register(on bridge: any BridgeProtocol) {
|
/// 注册时机的页面 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
|
// 【2】friendsSharetypeUrlToptitleDescript
|
||||||
// 入参:sharefriend / sharetype / type / webpageUrl / title / description
|
// 入参:sharefriend / sharetype / type / webpageUrl / title / description
|
||||||
// cb: "sharefriend"(msext 字面,沿用)
|
// cb: "sharefriend"(msext 字面,沿用)
|
||||||
@@ -34,9 +44,10 @@ public enum FriendsShareHandler {
|
|||||||
|
|
||||||
guard let obj = data?.asObject else { return }
|
guard let obj = data?.asObject else { return }
|
||||||
let content = ShareContent(
|
let content = ShareContent(
|
||||||
sharefriend: obj["sharefriend"]?.asString ?? "1",
|
// 缺失默认空串 → ShareCenter default 分支兜底(与原 msext [nil intValue]==0 等价)
|
||||||
|
sharefriend: obj["sharefriend"]?.asString ?? "",
|
||||||
sharetype: obj["sharetype"]?.asString ?? "",
|
sharetype: obj["sharetype"]?.asString ?? "",
|
||||||
type: obj["type"]?.asString ?? "1",
|
type: obj["type"]?.asString ?? "",
|
||||||
webpageUrl: obj["webpageUrl"]?.asString ?? "",
|
webpageUrl: obj["webpageUrl"]?.asString ?? "",
|
||||||
title: obj["title"]?.asString ?? "",
|
title: obj["title"]?.asString ?? "",
|
||||||
desc: obj["description"]?.asString ?? ""
|
desc: obj["description"]?.asString ?? ""
|
||||||
@@ -53,8 +64,11 @@ public enum FriendsShareHandler {
|
|||||||
callback: nil
|
callback: nil
|
||||||
)
|
)
|
||||||
|
|
||||||
// 3. fire-and-forget 拉起真实分享 UI
|
// 3. fire-and-forget 拉起真实分享 UI(按页面 mode 选路径)
|
||||||
ShareCenter.dispatch(content)
|
switch mode {
|
||||||
|
case .lobby: ShareCenter.dispatchLobby(content)
|
||||||
|
case .subGame: ShareCenter.dispatchSubGame(content)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,17 @@
|
|||||||
// ShareCenter.swift
|
// ShareCenter.swift
|
||||||
// ylgamehall
|
// ylgamehall
|
||||||
//
|
//
|
||||||
// H5 friendsShare 调用入口的协调中心,按 msext gameController.m:575-597 行为:
|
// H5 friendsShare 调用入口的协调中心。原 msext 同名 handler 在两个
|
||||||
// - sharefriend == "1"(好友/私聊)→ 弹 SharePanel 三选一(微信/QQ/抖音)
|
// ViewController 各注册一份且**行为不同**,新外壳按页面 mode 分发:
|
||||||
// - sharefriend == "2"(朋友圈) → 直接 WechatShare(朋友圈 timeline 场景)
|
//
|
||||||
|
// • dispatchSubGame — 对齐 msext gameController.m:575-597(活路径):
|
||||||
|
// - sharefriend == "1" → SharePanel 三选一(微信/QQ/抖音)
|
||||||
|
// - 其他 → WechatShare.share() 朋友圈 timeline
|
||||||
|
//
|
||||||
|
// • dispatchLobby — 对齐 msext NewRootVC.m:453-537:直发微信,无 SharePanel
|
||||||
|
// - sharefriend == "1" → WXSceneSession(好友)
|
||||||
|
// - 其他 → WXSceneTimeline(朋友圈)
|
||||||
|
// - type 3 分支由 WechatShare.shareLobby 内部处理
|
||||||
//
|
//
|
||||||
// fire-and-forget:H5 端 sharesuccess 已在 FriendsShareHandler 立即触发,
|
// fire-and-forget:H5 端 sharesuccess 已在 FriendsShareHandler 立即触发,
|
||||||
// 这里只负责拉起 UI / SDK,不需要回传结果。
|
// 这里只负责拉起 UI / SDK,不需要回传结果。
|
||||||
@@ -15,19 +23,23 @@ import Foundation
|
|||||||
@MainActor
|
@MainActor
|
||||||
public enum ShareCenter {
|
public enum ShareCenter {
|
||||||
|
|
||||||
public static func dispatch(_ content: ShareContent) {
|
/// 子游戏页(SubGameViewController)路径:SharePanel + 朋友圈兜底
|
||||||
|
public static func dispatchSubGame(_ content: ShareContent) {
|
||||||
switch content.sharefriend {
|
switch content.sharefriend {
|
||||||
case "1":
|
case "1":
|
||||||
// 好友/私聊 → SharePanel 三选一
|
// 好友/私聊 → SharePanel 三选一
|
||||||
SharePanel.show(content: content)
|
SharePanel.show(content: content)
|
||||||
|
|
||||||
case "2":
|
|
||||||
// 朋友圈 → 直接 WechatShare(timeline 场景)
|
|
||||||
WechatShare.shared.share(content, scene: .timeline)
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// 未知 sharefriend:msext 沿用第二条分支兜底(朋友圈微信)
|
// sharefriend == "2" 或缺失或其他 → msext WechatShareManager
|
||||||
|
// 内部 [sharefriend intValue] != 1 → WXSceneTimeline 兜底
|
||||||
WechatShare.shared.share(content, scene: .timeline)
|
WechatShare.shared.share(content, scene: .timeline)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 大厅页(WebContainerViewController)路径:直发微信,无 SharePanel
|
||||||
|
public static func dispatchLobby(_ content: ShareContent) {
|
||||||
|
let scene: ShareScene = content.sharefriend == "1" ? .friend : .timeline
|
||||||
|
WechatShare.shared.shareLobby(content, scene: scene)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,20 @@
|
|||||||
// WechatShare.swift
|
// WechatShare.swift
|
||||||
// ylgamehall
|
// ylgamehall
|
||||||
//
|
//
|
||||||
// 微信分享 SharePlatform 实现,1:1 对齐 daoqi msext WechatShareManager
|
// 微信分享 SharePlatform 实现 + 大厅专用 shareLobby() 路径。
|
||||||
// `shareWithContent:completion:`(仅两个分支):
|
|
||||||
// - type == "2" → 截图分享(getImageWithFullScreenshot + JPEG 0.6 + sendImageData)
|
|
||||||
// - else → 链接分享(sendLinkURL + webpageUrl + title + desc)
|
|
||||||
//
|
//
|
||||||
// 缩略图:app icon(与原 `[self getAppIconImage]` 同源策略,不用 sharelogo)。
|
// 两条路径对应原 msext 两个 ViewController 中同名 handler 的差异行为:
|
||||||
|
//
|
||||||
|
// • share() — 对齐 daoqi msext `WechatShareManager.shareWithContent:`
|
||||||
|
// (子游戏 gameController.m 活路径)2 type 分支:
|
||||||
|
// - type == "2" → 截图分享(thumb = app icon)
|
||||||
|
// - else → 链接分享(thumb = app icon)
|
||||||
|
//
|
||||||
|
// • shareLobby() — 对齐 daoqi msext `NewRootVC.m:471-534` 3 type 分支:
|
||||||
|
// - type == "1" → 链接分享(thumb = app icon;原 msext
|
||||||
|
// 用 sharelogo.png,按用户决定 fallback 到 app icon)
|
||||||
|
// - type == "2" → 截图分享(thumb = 截图 40% 缩放)
|
||||||
|
// - 其他 → 远端图分享(NSData 直发 + thumb = 远端图 40% 缩放)
|
||||||
//
|
//
|
||||||
// fire-and-forget:H5 端的 sharesuccess 已在 FriendsShareHandler 立即触发,
|
// fire-and-forget:H5 端的 sharesuccess 已在 FriendsShareHandler 立即触发,
|
||||||
// 此处不再回传结果(与原 dispatch_after 1s completion(YES) 实质等价)。
|
// 此处不再回传结果(与原 dispatch_after 1s completion(YES) 实质等价)。
|
||||||
@@ -69,6 +77,69 @@ public final class WechatShare: SharePlatform {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - 大厅路径(NewRootVC.m)
|
||||||
|
|
||||||
|
/// 大厅页 H5 调 friendsShare 的微信分享路径,对齐 msext NewRootVC.m
|
||||||
|
/// :471-534 完整 3 分支结构。直发微信无 SharePanel。
|
||||||
|
public func shareLobby(_ content: ShareContent, scene: ShareScene) {
|
||||||
|
guard WXApi.isWXAppInstalled() else { return }
|
||||||
|
|
||||||
|
let wxScene: WeChatManager.ShareScene = (scene == .timeline) ? .timeline : .session
|
||||||
|
let appIcon = Self.appIconImage()
|
||||||
|
|
||||||
|
Task { @MainActor in
|
||||||
|
do {
|
||||||
|
switch content.type {
|
||||||
|
case "1":
|
||||||
|
// 链接分享:原 msext 用 sharelogo.png;用户决定 fallback 到 app icon
|
||||||
|
try await WeChatManager.shared.shareLink(
|
||||||
|
.init(
|
||||||
|
url: content.webpageUrl,
|
||||||
|
title: content.title,
|
||||||
|
desc: content.desc,
|
||||||
|
thumb: appIcon,
|
||||||
|
mediaTagName: "\(Self.appTagPrefix)游戏下载链接"
|
||||||
|
),
|
||||||
|
scene: wxScene
|
||||||
|
)
|
||||||
|
case "2":
|
||||||
|
// 截图分享:thumb = 截图 40% 缩放(对齐 msext imageByScalingAndCroppingForSize:0.4x)
|
||||||
|
let shot = try ImageProvider.captureScreenshot()
|
||||||
|
guard let imageData = shot.jpegData(compressionQuality: 0.6) else { return }
|
||||||
|
try await WeChatManager.shared.shareImage(
|
||||||
|
.init(
|
||||||
|
imageData: imageData,
|
||||||
|
thumb: ImageProvider.scaledThumb(shot, scale: 0.4),
|
||||||
|
messageExt: content.desc,
|
||||||
|
mediaTagName: "\(Self.appTagPrefix)游戏截图分享"
|
||||||
|
),
|
||||||
|
scene: wxScene
|
||||||
|
)
|
||||||
|
default:
|
||||||
|
// 远端图分享(type == "" / "3" / 其他):下载 NSData 直发 +
|
||||||
|
// thumb = 远端图 40% 缩放。messageExt/mediaTagName 都是固定
|
||||||
|
// 字面(msext NewRootVC.m:530 字面,非 H5 desc)
|
||||||
|
guard let url = URL(string: content.webpageUrl) else { return }
|
||||||
|
let (data, _) = try await URLSession.shared.data(from: url)
|
||||||
|
guard let image = UIImage(data: data) else { return }
|
||||||
|
try await WeChatManager.shared.shareImage(
|
||||||
|
.init(
|
||||||
|
imageData: data,
|
||||||
|
thumb: ImageProvider.scaledThumb(image, scale: 0.4),
|
||||||
|
messageExt: "\(Self.appTagPrefix)公众号二维码分享",
|
||||||
|
mediaTagName: "\(Self.appTagPrefix)公众号二维码分享"
|
||||||
|
),
|
||||||
|
scene: wxScene
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// 与子游戏路径同样吞掉错误(sharesuccess 已乐观发出)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - 共享常量 / 工具
|
||||||
|
|
||||||
/// msext WechatShareManager 字面常量 "进贤聚友棋牌"(与 daoqi
|
/// msext WechatShareManager 字面常量 "进贤聚友棋牌"(与 daoqi
|
||||||
/// SGDefineInfo.h gamehallname 同源),用于 WXMediaMessage.mediaTagName 拼接。
|
/// SGDefineInfo.h gamehallname 同源),用于 WXMediaMessage.mediaTagName 拼接。
|
||||||
private static let appTagPrefix = "进贤聚友棋牌"
|
private static let appTagPrefix = "进贤聚友棋牌"
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ public final class SubGameViewController: UIViewController {
|
|||||||
)
|
)
|
||||||
|
|
||||||
AccreditLoginHandler.register(on: bridge)
|
AccreditLoginHandler.register(on: bridge)
|
||||||
FriendsShareHandler.register(on: bridge)
|
FriendsShareHandler.register(on: bridge, mode: .subGame) // 子游戏路径:SharePanel 三选一 + 朋友圈兜底(对齐 msext gameController.m 活路径)
|
||||||
|
|
||||||
// OpenurlTitleData 在子游戏中也可能调(threeView 弹层 push 自子游戏页),保留 stub
|
// OpenurlTitleData 在子游戏中也可能调(threeView 弹层 push 自子游戏页),保留 stub
|
||||||
OpenurlTitleDataHandler.register(on: bridge)
|
OpenurlTitleDataHandler.register(on: bridge)
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ public final class WebContainerViewController: UIViewController {
|
|||||||
|
|
||||||
// Phase 4.A 登录 + 分享 stub(Phase 4.B 微信 SDK / Phase 4.C QQ URL Scheme 后升级)
|
// Phase 4.A 登录 + 分享 stub(Phase 4.B 微信 SDK / Phase 4.C QQ URL Scheme 后升级)
|
||||||
AccreditLoginHandler.register(on: bridge) // §3.1 [1]Phase 4.E 完整微信 SDK
|
AccreditLoginHandler.register(on: bridge) // §3.1 [1]Phase 4.E 完整微信 SDK
|
||||||
FriendsShareHandler.register(on: bridge) // §3.1 [2]Phase 4.B 完整框架(QQ/抖音 已 4.C/4.D 落地)
|
FriendsShareHandler.register(on: bridge, mode: .lobby) // §3.1 [2]大厅路径:直发微信,3 type 分支(对齐 msext NewRootVC.m)
|
||||||
|
|
||||||
// Phase 6.4 / 7 子游戏 + 弹层入口 stub(让 H5 业务期调时不报 "no handler")
|
// Phase 6.4 / 7 子游戏 + 弹层入口 stub(让 H5 业务期调时不报 "no handler")
|
||||||
SwitchOverGameHandler.register(on: bridge) // §3.1 [17]Phase 6 完整实现
|
SwitchOverGameHandler.register(on: bridge) // §3.1 [17]Phase 6 完整实现
|
||||||
|
|||||||
Reference in New Issue
Block a user