We currently have one of the most popular extensions in across all browsers. We reuse a majority of our codebase to support them all. Switching to the safari app extension would require us to rewrite all of our background scripts to support only a small percentage of our users. Instead we would like to leverage a WKWebView and run our current background scripts inside it, with swift acting as a bridge between the WKWebView javascript and our content scripts. Is this possible and how would this WKWebView be implemented? Currently we're running into this issue - https://stackoverflow.com/questions/31169884/wkwebkit-javascript-execution-when-not-attached-to-a-view-hierarchy
Replies
Not sure you solved your problem, anyway giving my reply so that others can use it.
here is content of Background.swift file.
==============================
import Foundation
import WebKit
class Background : NSObject, WKScriptMessageHandler
{
private var _webView: WKWebView?;
public static let shared = Background();
private var _bSetupInvoked = false;
override init() {
super.init();
}
private func readFile(_ url: URL) -> String {
do {
return try String(contentsOf: url, encoding: .utf8)
}
catch {
let message = "Could not load file at: \(url)"
fatalError(message)
}
}
public func setup ()
{
if(self._bSetupInvoked == true)
{
return;
}
let webConfiguration = WKWebViewConfiguration()
let startScript = Bundle(for: Background.self).url(forResource: "bg_script", withExtension: "js")!
let scripts = readFile(startScript)
let script = WKUserScript(source: scripts, injectionTime: WKUserScriptInjectionTime.atDocumentStart, forMainFrameOnly: true)
let contentController: WKUserContentController = WKUserContentController()
contentController.addUserScript(script)
contentController.add(self, name: "backgroundListener")
webConfiguration.userContentController = contentController
self._webView = WKWebView(frame: .zero, configuration: webConfiguration)
self._webView!.customUserAgent = "my-Bridge"
let html : String = """
<html>
<head></head>
<body></body>
</html>
""";
self._webView!.loadHTMLString(html, baseURL: nil)
self._bSetupInvoked = true;
}
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
//Here we will recieve data from background js script
let val1 = message.name;
let val2 = message.body as! String;
NSLog(val1);
NSLog(val2);
}
func sendMessage(payload : String)
{
self._webView?.evaluateJavaScript("handleMessage('\(payload)');", completionHandler: { result, error in
if let val = result as? String {
NSLog(val)
}
else {
NSLog("result is NIL")
}
});
}
}
----------------------------------------------------------------------------------------------------------------------------------------------------------------
Here is content of bg_script.js
========================
window.addEventListener("load", async ()=>{
webkit.messageHandlers.backgroundListener.postMessage("Background webview - javascript loaded successfully");
});
function handleMessage(data) {
webkit.messageHandlers.backgroundListener.postMessage("Reply from background script : " + data);
}
----------------------------------------------------------------------------------------------------------------------------------------------------------------
Here is the content of SafariExtensionHandler.swift
========================================
class SafariExtensionHandler: SFSafariExtensionHandler {
override init() {
super.init()
//Initializing necessary classes
Background.shared.setup()
}
....
....
....
}
----------------------------------------------------------------------------------------------------------------------------------------------------------------
below code sends data to background script loaded in WKView
---------------------------------------------------------------------------
//Sending message to background page
Background.shared.sendMessage( payload: DateFormatter.localizedString(from: Date() as Date, dateStyle: .medium, timeStyle: .medium) );