Phase 1.9:BridgedWebView 封装 WKWebView + JS 注入 + BridgeBus
WebContainerViewController(Phase 1.10)的视图层依赖项:把 WKWebView 配置 /
WVJB.js 注入 / 桥总线 / scrollView 契约配置 4 件事一锅端打包成单一 UIView,
后续大厅 / 子游戏 / 弹层 VC 直接 add 进自己的内容区即可。
- 新增 ylgamehall/Source/WebView/BridgedWebView.swift
- @MainActor final class,继承 UIView
- 内含 public let webView: WKWebView 与 public let bridge: BridgeBus
- init() 全自动:
- WKWebViewConfiguration 按契约 §4.1:
defaultWebpagePreferences.allowsContentJavaScript = true(iOS 14+
现代 API,替代已弃用的 preferences.javaScriptEnabled)、
javaScriptCanOpenWindowsAutomatically = NO、minimumFontSize = 10、
allowsInlineMediaPlayback = true、processPool = SharedProcessPool.shared
- 用 WKUserScript(.atDocumentStart) 把 WebViewJavascriptBridge.js 注入
所有加载的 H5 页面,确保 H5 业务代码运行前 bridge 已就绪
- 创建 BridgeBus,自动向 controller 注册 WVJBHandler 通道
- scrollView:bounces=NO / isScrollEnabled=NO(契约硬约束,漏则 H5
上下滑动失控)/ contentInsetAdjustmentBehavior=.never / 双向无指示器
- WebView 撑满 self,自动布局
- SharedProcessPool 命名空间:跨 WebView 共享 WKProcessPool,Cookie /
资源缓存复用,启动加速(Design §3.5)
- BuildProject 通过,下一步 Phase 1.10 WebContainerViewController 用
BridgedWebView 嵌入 + 16:9 letterbox + 加载 lobbyIndex
This commit is contained in:
@@ -0,0 +1,89 @@
|
|||||||
|
//
|
||||||
|
// BridgedWebView.swift
|
||||||
|
// ylgamehall
|
||||||
|
//
|
||||||
|
// WKWebView + WebViewJavascriptBridge.js 注入 + BridgeBus 一体封装。
|
||||||
|
// 详见 docs/H5-Native-Implementation-Design.md §3.3 / 契约 §4.1。
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import WebKit
|
||||||
|
|
||||||
|
/// 内嵌 H5 的 WebView 组件,已挂好桥与必要配置。WebContainerViewController(Phase 1.10)
|
||||||
|
/// 通过把本 view 嵌入自己的内容区,再加上 16:9 letterbox / 生命周期管理。
|
||||||
|
@MainActor
|
||||||
|
public final class BridgedWebView: UIView {
|
||||||
|
|
||||||
|
public let webView: WKWebView
|
||||||
|
public let bridge: BridgeBus
|
||||||
|
|
||||||
|
public init() {
|
||||||
|
// ── WKWebViewConfiguration(契约 §4.1)─────────────────
|
||||||
|
let configuration = WKWebViewConfiguration()
|
||||||
|
configuration.defaultWebpagePreferences.allowsContentJavaScript = true
|
||||||
|
configuration.preferences.javaScriptCanOpenWindowsAutomatically = false
|
||||||
|
configuration.preferences.minimumFontSize = 10
|
||||||
|
configuration.allowsInlineMediaPlayback = true
|
||||||
|
configuration.processPool = SharedProcessPool.shared
|
||||||
|
|
||||||
|
// ── 在 documentStart 注入 WebViewJavascriptBridge.js ─────
|
||||||
|
// .atDocumentStart 保证 H5 业务代码运行时 window.WebViewJavascriptBridge 已就绪
|
||||||
|
if let url = Bundle.main.url(forResource: "WebViewJavascriptBridge",
|
||||||
|
withExtension: "js"),
|
||||||
|
let source = try? String(contentsOf: url, encoding: .utf8) {
|
||||||
|
let userScript = WKUserScript(
|
||||||
|
source: source,
|
||||||
|
injectionTime: .atDocumentStart,
|
||||||
|
forMainFrameOnly: true
|
||||||
|
)
|
||||||
|
configuration.userContentController.addUserScript(userScript)
|
||||||
|
} else {
|
||||||
|
// 编译期保证文件存在;运行时若缺,留 print 便于排查
|
||||||
|
print("[BridgedWebView] ERROR: WebViewJavascriptBridge.js 未在 Bundle 找到")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── 创建 WKWebView + BridgeBus ─────────────────────────
|
||||||
|
let webView = WKWebView(frame: .zero, configuration: configuration)
|
||||||
|
let bridge = BridgeBus(webView: webView,
|
||||||
|
controller: configuration.userContentController)
|
||||||
|
|
||||||
|
self.webView = webView
|
||||||
|
self.bridge = bridge
|
||||||
|
|
||||||
|
super.init(frame: .zero)
|
||||||
|
|
||||||
|
// ── ScrollView 配置(契约 §4.1,禁手势滚动 / 弹性 / 自动 inset)──
|
||||||
|
let scroll = webView.scrollView
|
||||||
|
scroll.bounces = false
|
||||||
|
scroll.isScrollEnabled = false // ⚠️ 漏则 H5 上下滑动失控(契约硬约束)
|
||||||
|
scroll.contentInsetAdjustmentBehavior = .never
|
||||||
|
scroll.showsVerticalScrollIndicator = false
|
||||||
|
scroll.showsHorizontalScrollIndicator = false
|
||||||
|
|
||||||
|
// ── 布局:WebView 撑满 self ─────────────────────────────
|
||||||
|
webView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
addSubview(webView)
|
||||||
|
NSLayoutConstraint.activate([
|
||||||
|
webView.topAnchor.constraint(equalTo: topAnchor),
|
||||||
|
webView.bottomAnchor.constraint(equalTo: bottomAnchor),
|
||||||
|
webView.leadingAnchor.constraint(equalTo: leadingAnchor),
|
||||||
|
webView.trailingAnchor.constraint(equalTo: trailingAnchor)
|
||||||
|
])
|
||||||
|
|
||||||
|
backgroundColor = .black
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(*, unavailable)
|
||||||
|
public required init?(coder: NSCoder) {
|
||||||
|
fatalError("BridgedWebView does not support init(coder:)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - 跨 WebView 共享的进程池
|
||||||
|
|
||||||
|
/// 大厅 / 子游戏 / 弹层共用同一 WKProcessPool,共享 Cookie / 资源缓存,
|
||||||
|
/// 启动加速。详见 Design §3.5。
|
||||||
|
@MainActor
|
||||||
|
public enum SharedProcessPool {
|
||||||
|
public static let shared = WKProcessPool()
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user