swift 如何在WKWebView中捕获通知?

bejyjqdl  于 12个月前  发布在  Swift
关注(0)|答案(1)|浏览(177)

我正在使用Swift 4开发macOS桌面应用程序。
它有一个WKWebView,可以加载一个发送通知的网页。
默认情况下不会显示任何通知,也没有权限请求。
我需要一种方法来显示通知并拦截它们,这样我就可以显示计数器。
你知道怎么做到吗?

h6my8fg2

h6my8fg21#

我面临着同样的挑战,并通过注入一个脚本(WKUserScript)来解决它,该脚本使用自定义实现覆盖Web通知API,该自定义实现利用WKUserContentController向本地应用代码发送消息,最终发布最终通知。

设置WKWebView

据我所知,要使用自定义WKWebViewConfiguration,必须以编程方式创建WKWebView。创建一个新的macOS应用程序项目,我在ViewController函数中扩展了viewDidLoad,如下所示:

override func viewDidLoad() {
    super.viewDidLoad()

    let userScriptURL = Bundle.main.url(forResource: "UserScript", withExtension: "js")!
    let userScriptCode = try! String(contentsOf: userScriptURL)
    let userScript = WKUserScript(source: userScriptCode, injectionTime: .atDocumentStart, forMainFrameOnly: false)
    let configuration = WKWebViewConfiguration()
    configuration.userContentController.addUserScript(userScript)
    configuration.userContentController.add(self, name: "notify")
    
    let documentURL = Bundle.main.url(forResource: "Document", withExtension: "html")!
    let webView = WKWebView(frame: view.frame, configuration: configuration)
    webView.loadFileURL(documentURL, allowingReadAccessTo: documentURL)
    
    view.addSubview(webView)
}

字符串
首先,我从应用程序包中加载用户脚本并将其添加到用户内容控制器中。我还添加了一个名为notify的消息处理程序,它可以用于从JavaScript上下文回调到本地代码。最后,我从应用程序包中加载了一个示例HTML文档,并使用窗口中的整个可用区域呈现Web视图。

覆盖通知API

这是注入的用户脚本和web Notification API的部分覆盖。它足以处理此一般问题范围内的典型通知权限请求过程和通知发布。

/**
 * Incomplete Notification API override to enable native notifications.
 */
class NotificationOverride {
    // Grant permission by default to keep this example simple.
    // Safari 13 does not support class fields yet, so a static getter must be used.
    static get permission() {
        return "granted";
    }
    
    // Safari 13 still uses callbacks instead of promises.
    static requestPermission (callback) {
        callback("granted");
    }
    
    // Forward the notification text to the native app through the script message handler.
    constructor (messageText) {
        window.webkit.messageHandlers.notify.postMessage(messageText);
    }
}

// Override the global browser notification object.
window.Notification = NotificationOverride;


每次在JavaScript上下文中创建新通知时,都会调用用户内容控制器消息处理程序。

脚本消息处理

ViewController(或其他应该处理脚本消息的东西)需要符合WKScriptMessageHandler并实现以下函数来处理调用:

func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        let content = UNMutableNotificationContent()
        content.title = "WKWebView Notification Example"
        content.body = message.body as! String
        
        let uuidString = UUID().uuidString
        let request = UNNotificationRequest(identifier: uuidString, content: content, trigger: nil)

        let notificationCenter = UNUserNotificationCenter.current()
        notificationCenter.add(request) { (error) in
            if error != nil {
                NSLog(error.debugDescription)
            }
        }
    }


整个实现是关于在macOS中创建本地的本机通知。但是,如果不进行额外的工作,它还无法工作。

App委托调整

在允许macOS应用发布通知之前,它必须像网站一样请求权限。

func applicationDidFinishLaunching(_ aNotification: Notification) {
        UNUserNotificationCenter.current().requestAuthorization(options: [.alert]) { (granted, error) in
            // Enable or disable features based on authorization.
        }
    }


如果应用程序处于前台时应显示通知,则应用程序委托必须进一步扩展以符合UNUserNotificationCenterDelegate并实现:

func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        completionHandler(UNNotificationPresentationOptions.alert)
    }


这需要applicationDidFinishLaunching(_:)中的委托赋值:

UNUserNotificationCenter.current().delegate = self


UNNotificationPresentationOptions可能会根据您的要求而有所不同。

相关问题