如何在WKWebView中捕获通知? [英] How to capture notifications in a WKWebView?

查看:134
本文介绍了如何在WKWebView中捕获通知?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Swift 4中的macOS桌面应用程序.
它具有WKWebView,可加载发送通知的网页.
默认情况下,不会显示任何通知,也没有权限请求.

I'm working on a macOS desktop app in Swift 4.
It has a WKWebView which loads up a web page that sends notifications.
None of the notifications are shown by default and there's also no permission request.

我需要一种显示通知并拦截它们的方法,以便我可以显示一个计数器.

I need a way to show the notifications and intercept them, so that I can show a counter.

任何想法如何实现这一目标?

Any idea how to achieve this?

推荐答案

我也面临同样的挑战,并通过注入脚本(

I was facing the same challenge and solved it by injecting a script (WKUserScript) which overrides the web notification API with a custom implementation that leverages the WKUserContentController to send messages to the native app code which posts the final notifications in the end.

据我所知,使用自定义WKWebViewConfiguration进行程序化创建WKWebView是必需的.创建一个新的macOS应用程序项目,我在ViewController函数中扩展我的viewDidLoad,如下所示:

Programmatic creation of a WKWebView is necessary to use a custom WKWebViewConfiguration as far as I know. Creating a new macOS app project I extend my viewDidLoad in the ViewController function like this:

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视图.

First I load the user script from the app bundle and add it to the user content controller. I also add a message handler called notify which can be used to phone back from the JavaScript context to native code. At the end I load an example HTML document from the app bundle and present the web view using the whole area available in the window.

这是注入的用户脚本,是Web的部分覆盖通知API .足以处理典型的通知许可请求流程并在此一般性问题的范围内发布通知.

This is the injected user script and a partial override of the web Notification API. It is sufficient to handle the typical notification permission request process and posting of notifications in scope of this generic question.

/**
 * 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上下文中创建新通知时,都会调用用户内容控制器消息处理程序.

Every time a new notification is created in the JavaScript context, the user content controller message handler is invoked.

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

The ViewController (or whatever else should handle the script messages) needs to conform to WKScriptMessageHandler and implement the following function to handle invocations:

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中创建本地本地通知的.但是,如果不付出额外的努力,它仍然无法工作.

The whole implementation is about the creation of a local, native notification in macOS. It does not work yet without additional effort, though.

在允许macOS应用发布通知之前,它必须先请求权限,例如网站.

Before a macOS app is allowed to post notifications, it must request the permissions to do so, like a website.

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

如果应在应用程序处于前台状态时显示通知,则必须进一步扩展应用程序委托以符合

If notifications should be presented while the app is in the foreground, the app delegate must be extended further to conform to UNUserNotificationCenterDelegate and implement:

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

这需要在applicationDidFinishLaunching(_:)中进行委托分配:

which requires the delegate assignment in applicationDidFinishLaunching(_:):

UNUserNotificationCenter.current().delegate = self

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

The UNNotificationPresentationOptions may vary according to your requirements.

我创建了在GitHub上可用的示例项目,该渲染了整个图片.

I created an example project available on GitHub which renders the whole picture.

这篇关于如何在WKWebView中捕获通知?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆