mcpField
B
browserenginekit

browserenginekit

github.com/dpearson2699开发1.2k3.1k 次安装13 周前更新
代码仓库

关于 browserenginekit

BrowserEngineKit 技能面向构建 iOS 和 iPadOS 替代浏览器引擎的开发者,介绍进程隔离、扩展通信、能力管理及系统集成。它也说明地区与设备资格、权限配置和安全要求。

主要功能

  1. 01划分网页内容、网络和渲染扩展
  2. 02通过 XPC 协调独立进程
  3. 03为扩展授予运行能力
  4. 04托管渲染层级并同步更新
  5. 05集成文本交互与下载监控
  6. 06配置沙盒及引擎权限

适用场景

  1. 01构建使用自有 HTML 引擎的浏览器
  2. 02隔离网页内容与网络处理进程
  3. 03管理跨进程渲染和媒体功能
  4. 04检查替代引擎的资格与安全配置

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/dpearson2699/swift-ios-skills --skill browserenginekit

安装后在 Claude Code 中输入/browserenginekit确认已加载。

附带文件evals/evals.jsonreferences/browserenginekit-patterns.md

详细介绍

BrowserEngineKit

用于在 iOS 和 iPadOS 上使用替代(非 WebKit)渲染引擎构建 Web 浏览器的框架。它为实现自有 HTML/CSS/JavaScript 引擎的浏览器应用提供进程隔离、XPC 通信、功能管理和系统集成。示例面向 Swift 6.3 和当前 Apple SDK。

BrowserEngineKit 是一个专用框架。替代浏览器引擎只能通过 Apple 批准的权限配置文件,以及符合支持地区条件的设备使用。欧盟支持适用于 iOS 17.4+ 和 iPadOS 18+ 上符合条件的用户;日本支持从 iOS 26.2 开始,并对浏览器应用增加了明确的 PAC/MIE 安全要求。开发和测试可在任何地区进行。配套框架 BrowserEngineCore(底层原语)和 BrowserKit(资格检查、数据传输)支持整个工作流。

目录

概述与资格

资格检查

使用 BrowserKit 框架中的 BEAvailability 检查设备是否符合使用替代浏览器引擎的条件。BEAvailability 适用于 iOS/iPadOS 18.4+:

import BrowserKit

do {
    let eligible = try await BEAvailability.isEligible(for: .webBrowser)
    guard eligible else { return /* fall back or explain */ }
    // Device supports alternative browser engines
} catch {
    // Handle eligibility lookup failure
}

资格取决于设备所在地区和操作系统版本。不要将地区检查硬编码;应依赖系统 API。

可用性版本:进程 API 适用于 iOS/iPadOS 17.4+,BEDownloadMonitor 适用于 iOS 18.2+,受限沙盒 .revision2 适用于 iOS 26+,RenderingExtensionFeature.coreML 适用于 iOS 26.2+。

权限

浏览器应用(宿主)

宿主应用需要两项权限:

权限用途
com.apple.developer.web-browser允许申请默认浏览器资格
com.apple.developer.web-browser-engine.host允许使用替代引擎扩展

两项权限都必须向 Apple 申请。申请流程因地区而异。

扩展权限

每个扩展目标都需要将对应类型的权限设为 true:

扩展类型权限
Web 内容com.apple.developer.web-browser-engine.webcontent
网络com.apple.developer.web-browser-engine.networking
渲染com.apple.developer.web-browser-engine.rendering
可选权限
权限扩展用途
com.apple.security.cs.allow-jitWeb 内容脚本的 JIT 编译
com.apple.developer.kernel.extended-virtual-addressingWeb 内容必须与 JIT 一同使用
com.apple.developer.memory.transfer_send渲染发送内存归属信息;值为宿主应用的 bundle ID
com.apple.developer.memory.transfer_acceptWeb 内容接受内存归属信息;值为宿主应用的 bundle ID
com.apple.developer.web-browser-engine.restrict.notifydWeb 内容限制对通知守护进程的访问
嵌入式浏览器引擎(非浏览器应用)

并非浏览器、但在应用内浏览功能中嵌入替代引擎的应用需使用不同的权限:

权限用途
com.apple.developer.embedded-web-browser-engine启用嵌入式引擎
com.apple.developer.embedded-web-browser-engine.engine-association声明引擎归属

engine-association 从 iOS/iPadOS/Mac Catalyst 26.2 起可用;若引擎由你所有,则设为 first-party,若由其他开发者所有,则设为 third-party。嵌入式引擎仅使用 arm64(不使用 arm64e),不能包含浏览器扩展,也不能使用 JIT 编译。

日本特定要求

在日本分发的浏览器应用支持 iOS 26.2+,并且必须采用 Apple 针对日本列出的最新安全缓解措施,包括对相关分配器和扩展进程启用指针身份验证码和内存完整性强制。使用 com.apple.security.hardened-process.checked-allocations 启用硬件内存标记;Apple 也强烈建议在欧盟启用此功能。

架构

使用 BrowserEngineKit 构建的浏览器由四个在独立进程中运行的组件组成:

Host App (UI, coordination)
  |
  |-- XPC --> Web Content Extension (HTML parsing, JS, DOM)
  |-- XPC --> Networking Extension (URLSession, sockets)
  |-- XPC --> Rendering Extension (Metal, GPU, media)

宿主应用会启动并管理所有扩展。扩展无法启动其他扩展。扩展通过由宿主应用中介的匿名 XPC 端点相互通信。

引导序列
  1. 宿主启动网页内容、网络和渲染扩展
  2. 宿主为每个扩展创建 XPC 连接
  3. 宿主向网络和渲染扩展请求匿名 XPC 端点
  4. 宿主通过引导消息将两个端点都发送给网页内容扩展
  5. 网页内容扩展直接连接到网络和渲染扩展

这种架构遵循最小权限原则:网页内容扩展处理不可信数据,但无法直接访问 OS 资源。

进程管理

启动扩展

宿主应用中的每种扩展类型都有对应的进程类:

import BrowserEngineKit

// Web content (one per tab or iframe)
let contentProcess = try await WebContentProcess(
    bundleIdentifier: nil,
    onInterruption: {
        // Handle crash or OS interruption
    }
)

// Networking (typically one instance)
let networkProcess = try await NetworkingProcess(
    bundleIdentifier: nil,
    onInterruption: {
        // Handle interruption
    }
)

// Rendering / GPU (typically one instance)
let renderingProcess = try await RenderingProcess(
    bundleIdentifier: nil,
    onInterruption: {
        // Handle interruption
    }
)

将 bundleIdentifier 设为 nil,即可使用默认扩展目标。如果扩展崩溃或被 OS 终止,中断处理程序就会触发。

创建 XPC 连接
let connection = try contentProcess.makeLibXPCConnection()
// Use connection for inter-process messaging

每种进程类型都提供 makeLibXPCConnection(),用于创建供通信使用的 xpc_connection_t。

停止扩展
contentProcess.invalidate()

调用 invalidate() 后,不能再对进程对象调用任何方法。

扩展类型

网页内容扩展

承载浏览器引擎的 HTML 解析器、CSS 引擎、JavaScript 解释器和 DOM。遵循 WebContentExtension,以处理传入的 XPC 连接:

import BrowserEngineKit

@main
struct MyWebContentExtension: WebContentExtension {
    func handle(xpcConnection: xpc_connection_t) {
        // Set up message handlers on the connection
    }
}

通过扩展的 EXAppExtensionAttributes 中的 WebContentExtensionConfiguration 进行配置。

网络扩展

使用 URLSession 或套接字 API 处理所有网络请求。一个实例服务于所有标签页:

import BrowserEngineKit

@main
struct MyNetworkingExtension: NetworkingExtension {
    func handle(xpcConnection: xpc_connection_t) {
        // Handle network request messages
    }
}

通过 NetworkingExtensionConfiguration 进行配置。

渲染扩展

通过 Metal 访问 GPU,以进行视频解码、合成和复杂渲染。一个实例通常服务于整个浏览器:

import BrowserEngineKit

@main
struct MyRenderingExtension: RenderingExtension {
    init() {
        if #available(iOS 26.2, macOS 26.2, *) {
            enableFeature(.coreML)
        }
    }

    func handle(xpcConnection: xpc_connection_t) {
        // Handle rendering commands
    }
}

通过 RenderingExtensionConfiguration 进行配置。

功能

为扩展授予功能,以便 OS 适当地调度它们:

// Grant foreground priority to an extension
let grant = try contentProcess.grantCapability(.foreground)

// ... extension does foreground work ...

// Relinquish when done
grant.invalidate()
可用功能
功能用途
.foreground活动标签页渲染、可见内容
.background后台任务、预取
.suspended最少活动、等待清理
.mediaPlaybackAndCapture(environment:)音频/视频播放、摄像头/麦克风采集
媒体环境

对于媒体功能,请创建与页面 URL 关联的 MediaEnvironment。 该环境支持用于摄像头/麦克风访问的 AVCaptureSession,并且可通过 XPC 序列化以便跨进程传输:

let mediaEnv = MediaEnvironment(webPage: pageURL)
let grant = try contentProcess.grantCapability(
    .mediaPlaybackAndCapture(environment: mediaEnv)
)
try mediaEnv.activate()
let captureSession = try mediaEnv.makeCaptureSession()
可见性传播

将可见性传播交互附加到浏览器视图,以便扩展了解内容何时显示在屏幕上。WebContentProcess 和 RenderingProcess 都提供 createVisibilityPropagationInteraction()。

图层托管与视图协调

渲染扩展绘制到 LayerHierarchy 中,宿主应用通过 LayerHierarchyHostingView 显示其中的内容。句柄通过 XPC 传递。使用 LayerHierarchyHostingTransactionCoordinator,跨进程原子同步图层更新。

有关图层托管和事务协调的详细示例,请参阅 references/browserenginekit-patterns.md。

文本交互

在自定义文本视图上采用 BETextInput,以接入 UIKit 的文本 系统。这样可以实现标准的文本选择、自动更正、听写和键盘交互。

集成要点:

  • 使用 asyncInputDelegate 与系统通信并传递文本更改
  • 使用 handleKeyEntry(_:completionHandler:) 处理键盘事件
  • 使用 BETextInteraction 处理选择手势、编辑菜单和上下文菜单
  • 使用 BEScrollView 和 BEScrollViewDelegate 处理自定义滚动

详细的文本交互实现请参阅 references/browserenginekit-patterns.md。

沙盒与安全

受限沙盒

初始化后,使用受限沙盒锁定内容扩展:

// In the web content extension, after setup:
if #available(iOS 26.0, macOS 26.0, *) {
    applyRestrictedSandbox(revision: .revision2)
} else {
    applyRestrictedSandbox(revision: .revision1)
}

这会移除扩展在启动期间使用、但之后不再需要的资源访问权限。请使用最新的可用修订版,以实现最严格的限制。

JIT 编译

使用 JIT 编译 JavaScript 的网页内容扩展必须通过 BrowserEngineKit 的有见证 API 转换页面:

import BrowserEngineCore

be_memory_inline_jit_restrict_rwx_to_rw_with_witness(...)
// write generated code
be_memory_inline_jit_restrict_rwx_to_rx_with_witness(...)

仅网页内容扩展需要 com.apple.security.cs.allow-jit 和 com.apple.developer.kernel.extended-virtual-addressing 权限。如果实现改用 pthread_jit_write_with_callback_np,还需要 JIT 写入允许列表权限;不要将 BE_JIT_WRITE_PROTECT_TAG 单独描述为完整的保护策略。

arm64e 要求

分发版本必须满足当前替代浏览器权限配置文件对设备架构、PAC 和 MIE 的要求。确保主机与扩展配置一致,包含所需的设备切片,并在符合条件的设备上测试已签名的归档文件。嵌入式引擎有所不同:它们仅支持 arm64,且无法使用 JIT。不要将 arm64e 强行用于 Simulator 版本,也不要复制会移除必需切片的单行 ARCHS 覆盖设置。

下载

使用 BEDownloadMonitor 向系统报告下载进度。创建访问令牌,使用源 URL、目标 URL 和 Progress 对象初始化监视器,然后调用 beginMonitoring() 以显示系统下载界面。使用 resumeMonitoring(placeholderURL:) 恢复中断的下载。 BEDownloadMonitor 适用于 iOS 18.2 及更高版本。

完整的下载管理示例请参阅 references/browserenginekit-patterns.md。

常见错误

不要:跳过引导序列
// WRONG - content extension has no path to other extensions
let contentProcess = try await WebContentProcess(
    bundleIdentifier: nil, onInterruption: {}
)
// Immediately start sending work without connecting to networking/rendering

// CORRECT - broker connections through the host app
let networkEndpoint = try await networkProxy.getEndpoint()
let renderEndpoint = try await renderProxy.getEndpoint()
try await contentProxy.bootstrap(
    renderingExtension: renderEndpoint,
    networkExtension: networkEndpoint
)
不要:从其他扩展启动扩展
// WRONG - extensions cannot launch other extensions
// (inside a WebContentExtension)
let network = try await NetworkingProcess(...)

// CORRECT - only the host app launches extensions
// Host app creates all processes, then brokers connections
不要:在扩展进程对象失效后继续使用
// WRONG
contentProcess.invalidate()
let conn = try contentProcess.makeLibXPCConnection()  // Error

// CORRECT - create a new process if needed
let newProcess = try await WebContentProcess(
    bundleIdentifier: nil, onInterruption: {}
)
不要:将 JIT 权限用于非内容扩展

JIT 编译权限(com.apple.security.cs.allow-jit)仅适用于网页内容扩展。将其添加到主机应用、渲染扩展或网络扩展会导致 App Store 拒绝上架。

不要:对地区资格进行硬编码
// WRONG
if Locale.current.region?.identifier == "DE" {
    useAlternativeEngine()
}

// CORRECT - use the system eligibility API
let eligible = try await BEAvailability.isEligible(for: .webBrowser)
if eligible {
    useAlternativeEngine()
}
不要:忘记设置 UIRequiredDeviceCapabilities

如果 UIRequiredDeviceCapabilities 中没有 web-browser-engine,不受支持设备上的用户可能会下载应用并遇到运行时故障。

审查清单

  • 宿主应用已配置 com.apple.developer.web-browser-engine.host 权限
  • 每个扩展都配置了其类型对应的权限
  • UIRequiredDeviceCapabilities 包含 web-browser-engine
  • 为所有 iOS 设备目标配置了 arm64e 指令集
  • 未为模拟器目标设置 arm64e
  • 使用工作区设置 iOSPackagesShouldBuildARM64e 构建 Swift 包
  • 每个扩展的 Info.plist 中都正确设置了扩展点标识符
  • 为所有进程类型实现了中断处理程序
  • 引导序列会将内容扩展连接到网络和渲染功能
  • 在开始工作前授予功能权限,并在完成后使其失效
  • 在浏览器内容视图中添加了可见性传播交互
  • 初始化后,对内容扩展应用受限沙盒
  • 使用 BEAvailability 检查资格,而非手动处理地区逻辑
  • 内存归属权限使用宿主应用的 Bundle ID 作为值
  • 对于 iOS 18.2 及更高版本上的活动下载,通过 BEDownloadMonitor 报告下载进度
  • 对于 iOS 26.2 及更高版本上在日本发布的应用,启用内存标记(建议在欧盟启用)

参考资料

评论

支持 Markdown