You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Mac Catalyst应用中使用AppKit的WKWebView?

在Mac Catalyst应用中使用AppKit的WKWebView替代UIKit版本

核心思路

Mac Catalyst支持通过条件编译调用AppKit框架的API,我们可以利用这一点,在Mac平台加载AppKit的WKWebView,iOS/iPadOS端保留UIKit版本,既解决Mac端的交互异常问题,又保证跨平台兼容性。

具体实现步骤

1. 配置项目编译环境

在项目Build Settings中,确保TARGETED_DEVICE_FAMILY包含Mac(值设为1,2,6),开启Mac Catalyst支持。

2. 封装统一的WebView接口

由于UIKit和AppKit的WKWebView分属不同框架,先创建协议统一核心方法,再分别实现对应平台的封装类:

import UIKit
import WebKit

// 定义统一的WebView功能协议
protocol WebViewProtocol: AnyObject {
    var url: URL? { get set }
    func load(_ request: URLRequest)
    func reload()
    // 按需添加更多需要的方法
}

// UIKit版本的WebView封装
class UIKitWebViewWrapper: UIView, WebViewProtocol {
    private let webView: WKWebView
    
    var url: URL? {
        get { webView.url }
        set { if let url = newValue { webView.load(URLRequest(url: url)) } }
    }
    
    init() {
        webView = WKWebView()
        super.init(frame: .zero)
        addSubview(webView)
        webView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            webView.topAnchor.constraint(equalTo: topAnchor),
            webView.leadingAnchor.constraint(equalTo: leadingAnchor),
            webView.trailingAnchor.constraint(equalTo: trailingAnchor),
            webView.bottomAnchor.constraint(equalTo: bottomAnchor)
        ])
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func load(_ request: URLRequest) {
        webView.load(request)
    }
    
    func reload() {
        webView.reload()
    }
}

// AppKit版本的WebView封装(仅Mac Catalyst环境编译)
#if targetEnvironment(macCatalyst)
import AppKit

class AppKitWebViewWrapper: UIView, WebViewProtocol {
    private let webView: WKWebView
    
    var url: URL? {
        get { webView.url }
        set { if let url = newValue { webView.load(URLRequest(url: url)) } }
    }
    
    init() {
        webView = WKWebView()
        super.init(frame: .zero)
        // 将AppKit视图包装到UIKit视图容器中
        let hostingView = NSHostingView(rootView: webView)
        addSubview(hostingView)
        hostingView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            hostingView.topAnchor.constraint(equalTo: topAnchor),
            hostingView.leadingAnchor.constraint(equalTo: leadingAnchor),
            hostingView.trailingAnchor.constraint(equalTo: trailingAnchor),
            hostingView.bottomAnchor.constraint(equalTo: bottomAnchor)
        ])
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func load(_ request: URLRequest) {
        webView.load(request)
    }
    
    func reload() {
        webView.reload()
    }
}
#endif

3. 在视图控制器中加载对应版本的WebView

根据当前运行环境,初始化并添加对应的WebView实例:

class ViewController: UIViewController {
    private var webView: WebViewProtocol!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 按环境初始化WebView
        #if targetEnvironment(macCatalyst)
        let webViewWrapper = AppKitWebViewWrapper()
        #else
        let webViewWrapper = UIKitWebViewWrapper()
        #endif
        
        webView = webViewWrapper
        view.addSubview(webViewWrapper as! UIView)
        (webViewWrapper as! UIView).translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            (webViewWrapper as! UIView).topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
            (webViewWrapper as! UIView).leadingAnchor.constraint(equalTo: view.leadingAnchor),
            (webViewWrapper as! UIView).trailingAnchor.constraint(equalTo: view.trailingAnchor),
            (webViewWrapper as! UIView).bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
        ])
        
        // 加载测试页面
        if let url = URL(string: "https://www.example.com") {
            webView.load(URLRequest(url: url))
        }
    }
}

4. 交互细节适配

AppKit的WKWebView会自动使用Mac原生的文本选择、复制粘贴逻辑,无需额外处理。如果需要自定义交互逻辑,可在封装类中传递WKUIDelegate和WKNavigationDelegate代理方法,保持跨平台行为一致。

注意事项

  • 仅在Mac Catalyst环境下导入AppKit框架,避免编译错误
  • 使用NSHostingView包装AppKit视图,确保与UIKit布局系统兼容
  • 分别在iOS/iPadOS和Mac端测试功能,验证跨平台一致性

内容的提问来源于stack exchange,提问作者Rohit Vishwakarma

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 22:45:32