移动/游戏
在 iOS/iPadOS 上构建非 WebKit…
用 BrowserEngineKit 在受支持地区开发替代浏览器引擎,管理 Web 内容/网络/渲染扩展进程、权限、XPC 通信与安全加固。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 59/100 ×0.15
适用场景
在 iOS/iPadOS 上构建非 We特定
解决思路
- 用 BrowserKit 的 `BEAvailability.isEligible(for: .webBrowser)` 检查设备是否支持替代浏览器引擎,不要硬编码地区判断;该方法在 iOS/iPadOS 18.4+ 可用。
- 为主机 App 申请两个 entitlement:`com.apple.developer.web-browser`(默认浏览器候选资格)和 `com.apple.developer.web-browser-engine.host`(启用替代引擎扩展),两者都需向 Apple 申请。
- 为每个扩展 target 设置对应 entitlement 为 true:Web 内容用 `com.apple.developer.web-browser-engine.webcontent`,网络用 `com.apple.developer.web-browser-engine.networking`,渲染用 `com.apple.developer.web-browser-engine.rendering`。
- 按需添加可选 entitlement:Web 内容可加 `com.apple.security.cs.allow-jit`(JIT 编译)和 `com.apple.developer.kernel.extended-virtual-addressing`(与 JIT 配套);渲染扩展用 `com.apple.developer.memory.transfer_send`、Web 内容用 `com.apple.developer.memory.transfer_accept`(值均为主机 App bundle ID);Web 内容可加 `com.apple.developer.web-browser-engine.restrict.notifyd`。
- 非浏览器 App 内嵌替代引擎时改用 `com.apple.developer.embedded-web-browser-engine` 和 `com.apple.developer.embedded-web-browser-engine.engine-association`(iOS/iPadOS/Mac Catalyst 26.2+,值为 `first-party` 或 `third-party`);内嵌引擎仅支持 arm64、不能含浏览器扩展、不能用 JIT。
- 日本地区分发的浏览器 App 需 iOS 26.2+,并采用 Apple 列出的安全缓解措施(PAC、MIE),启用 `com.apple.security.hardened-process.checked-allocations` 硬件内存标记;EU 也强烈建议启用。
- 按四进程架构组织:主机 App(UI/协调)通过 XPC 连接 Web 内容扩展(HTML 解析、JS、DOM)、网络扩展(URLSession、socket)、渲染扩展(Metal、GPU、媒体);扩展之间不能互相启动,只能通过主机 App 中转的匿名 XPC endpoint 通信。
- 按 bootstrap 顺序启动:主机先启动 Web 内容、网络、渲染扩展;建立到各扩展的 XPC 连接;向网络和渲染扩展请求匿名 XPC endpoint;通过 bootstrap 消息把两个 endpoint 发给 Web 内容扩展;Web 内容扩展再直连网络和渲染扩展。
- 在主机 App 中用对应进程类启动扩展:`WebContentProcess`(每个 tab 或 iframe 一个)、`NetworkingProcess`(通常一个)、`RenderingProcess`(通常一个),`bundleIdentifier` 传 `nil` 使用默认扩展 target,并实现 `onInterruption` 处理崩溃或系统终止。
- 用 `process.makeLibXPCConnection()` 创建 `xpc_connection_t` 进行进程间通信。
- 停止扩展时调用 `process.invalidate()`,之后不得再对该进程对象调用任何方法。
- Web 内容扩展用 `@main struct ...: WebContentExtension` 实现 `handle(xpcConnection:)`,并通过 `WebContentExtensionConfiguration` 在 `EXAppExtensionAttributes` 中配置。
- 网络扩展用 `@main struct ...: NetworkingExtension` 实现 `handle(xpcConnection:)`,通过 `NetworkingExtensionConfiguration` 配置,一个实例服务所有 tab。
- 渲染扩展用 `@main struct ...: RenderingExtension` 实现 `handle(xpcConnection:)`,通过 `RenderingExtensionConfiguration` 配置;iOS 26.2+ 可在 `init` 中调用 `enableFeature(.coreML)`。
- 用 `process.grantCapability(...)` 授予扩展能力:`.foreground`(活动 tab 渲染)、`.background`(后台任务/预取)、`.suspended`(最小活动)、`.mediaPlaybackAndCapture(environment:)`(音视频/摄像头麦克风);完成后调用 `grant.invalidate()` 释放。
- 媒体能力需用页面 URL 创建 `MediaEnvironment`,调用 `mediaEnv.activate()` 后用 `mediaEnv.makeCaptureSession()` 获取 `AVCaptureSession`;该对象可 XPC 序列化跨进程传输。
- 给浏览器视图附加可见性传播交互(`WebContentProcess` 和 `RenderingProcess` 都提供 `createVisibilityPropagationInteraction()`),让扩展知道内容是否在屏幕上。
- 渲染扩展绘制到 `LayerHierarchy`,主机 App 用 `LayerHierarchyHostingView` 显示,句柄经 XPC 传递;用 `LayerHierarchyHostingTransactionCoordinator` 跨进程原子同步图层更新。
- 在自定义文本视图上采用 `BETextInput` 以接入 UIKit 文本系统:用 `asyncInputDelegate` 传递文本变更、`handleKeyEntry(_:completionHandler:)` 处理键盘事件、`BETextInteraction` 处理选择手势/编辑菜单/上下文菜单、`BEScrollView` 和 `BEScrollViewDelegate` 处理自定义滚动。
- 初始化完成后对内容扩展应用受限沙箱:iOS 26.0+/macOS 26.0+ 用 `applyRestrictedSandbox(revision: .revision2)`,否则用 `.revision1`,以移除启动后不再需要的资源访问。
- JIT 编译 JavaScript 的 Web 内容扩展必须用 BrowserEngineKit 的见证 API 切换页面:`be_memory_inline_jit_restrict_rwx_to_rw_with_witness(...)` 写生成代码,再用 `be_memory_inline_jit_restrict_rwx_to_rx_with_witness(...)`;若改用 `pthread_jit_write_with_callback_np` 还需 JIT 写白名单 entitlement,不能只靠 `BE_JIT_WRITE_PROTECT_TAG`。
- 分发构建需满足当前替代浏览器 entitlement profile 的设备架构、PAC、MIE 要求,保持主机与扩展配置一致,包含所需设备切片,并在合格设备上测试签名归档;不要给 Simulator 构建强制 `arm64e`,也不要照抄会丢切片的 `ARCHS` 覆盖。
- 用 `BEDownloadMonitor`(iOS 18.2+)报告下载进度:创建 access token,用源/目标 URL 和 `Progress` 对象初始化,调用 `beginMonitoring()` 显示系统下载 UI;用 `resumeMonitoring(placeholderURL:)` 恢复中断的下载。
- 在 `UIRequiredDeviceCapabilities` 中加入 `web-browser-engine`,否则不支持设备上的用户能下载 App 并在运行时失败。
- 为所有进程类型实现中断处理器,并在开始工作前授予能力、完成后 invalidate。
- 内存归属 entitlement 的值使用主机 App bundle ID。
- 在每个扩展的 Info.plist 中正确设置 extension point 标识符。
- 用 `iOSPackagesShouldBuildARM64e` workspace 设置构建 Swift 包。
- 按 review checklist 逐项核对:主机 entitlement、各扩展类型 entitlement、`UIRequiredDeviceCapabilities`、arm64e 配置(设备 target 启用、Simulator 不启用)、extension point 标识符、中断处理器、bootstrap 连接、能力授予与释放、可见性传播、受限沙箱、`BEAvailability` 资格检查、内存归属 bundle ID、`BEDownloadMonitor`、日本分发的内存标记。
适用边界 · 注意事项
- 需要 Apple 批准的 entitlement profile 和受支持地区设备资格(EU 为 iOS 17.4+/iPadOS 18+,日本为 iOS 26.2+),未获批准或不在支持地区时不可用。
- 非浏览器 App 内嵌引擎场景不适用浏览器 App 的 entitlement 与 JIT 能力(内嵌引擎仅 arm64、不能含浏览器扩展、不能用 JIT)。
- 不要用硬编码地区判断或手动 `Locale` 检查替代 `BEAvailability`,也不要把 JIT entitlement 加到主机 App、渲染或网络扩展上(会导致 App Store 拒绝)。