Skip to content

Instantly share code, notes, and snippets.

@JSerZANP
Created March 4, 2021 14:01
Show Gist options
  • Save JSerZANP/ea300d419bfafa79e4f8c0af42d8fec6 to your computer and use it in GitHub Desktop.
Save JSerZANP/ea300d419bfafa79e4f8c0af42d8fec6 to your computer and use it in GitHub Desktop.
communication between native(swiftUI) and wkwebview
import SwiftUI
import WebKit
struct WebView: UIViewRepresentable {
class Coordinator: NSObject, WKNavigationDelegate, WKScriptMessageHandler {
var webView: WKWebView?
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
self.webView = webView
}
// receive message from wkwebview
func userContentController(
_ userContentController: WKUserContentController,
didReceive message: WKScriptMessage
) {
print(message.body)
let date = Date()
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
self.messageToWebview(msg: "hello, I got your messsage: \(message.body) at \(date)")
}
}
func messageToWebview(msg: String) {
self.webView?.evaluateJavaScript("webkit.messageHandlers.bridge.onMessage('\(msg)')")
}
}
func makeCoordinator() -> Coordinator {
return Coordinator()
}
func makeUIView(context: Context) -> WKWebView {
let coordinator = makeCoordinator()
let userContentController = WKUserContentController()
userContentController.add(coordinator, name: "bridge")
let configuration = WKWebViewConfiguration()
configuration.userContentController = userContentController
let _wkwebview = WKWebView(frame: .zero, configuration: configuration)
_wkwebview.navigationDelegate = coordinator
return _wkwebview
}
func updateUIView(_ webView: WKWebView, context: Context) {
guard let path: String = Bundle.main.path(forResource: "index", ofType: "html") else { return }
let localHTMLUrl = URL(fileURLWithPath: path, isDirectory: false)
webView.loadFileURL(localHTMLUrl, allowingReadAccessTo: localHTMLUrl)
}
}
struct ContentView: View {
var body: some View {
VStack {
Text("hello?")
WebView()
}
}
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1, minimum-scale=1, viewport-fit=cover">
</head>
<body>
<button>click me</button>
<hr/>
<div id="log"></div>
<script>
const log = (msg) => {
const p = document.createElement('p')
p.textContent = msg
document.querySelector('#log').append(p)
}
// to receive messages from native
webkit.messageHandlers.bridge.onMessage = (msg) => {
log('from native:' + msg)
}
document.querySelector('button').addEventListener('click', () => {
log(typeof webkit.messageHandlers.bridge.postMessage)
// send messages to native
webkit.messageHandlers.bridge.postMessage('{"msg": "hello?","id": ' + Date.now() + '}')
})
</script>
</body>
</html>
@burhanyilmaz
Copy link

@JSerZANP thanks for the script!

@AlejandroPerezAnuncibay
Copy link

Thanks dude, really good and clean code! Nice job!

@liaowd
Copy link

liaowd commented Sep 21, 2022

Thanks, it works!

@IhwanID
Copy link

IhwanID commented Dec 16, 2022

Thanks!

@yuriteixeira
Copy link

The best example I've found so far. Great job!

@HongShiun-Ye
Copy link

HongShiun-Ye commented Nov 8, 2023

Excuse me, I have a problem. In line 17. "print(message.body)". When I build I can get msg and id's information.
How can I get the "msg" information only and I need to store it to "MSG" to use.

@day-trip
Copy link

Thanks! This helps out a ton

@NikcN22
Copy link

NikcN22 commented Jul 18, 2024

func makeCoordinator automatically executed before makeUIView, so there must be

   func makeUIView(context: Context) -> WKWebView {
        ------> let coordinator =  context.coordinator   <-------
        let userContentController = WKUserContentController()
        userContentController.add(coordinator, name: "bridge")
        .....
        return _wkwebview
    }

@no-today
Copy link

// to receive messages from native
webkit.messageHandlers.bridge.onMessage = (msg) => {
  log('from native:' + msg)
}

There is a problem when handling SwiftUI's javascript instructions
First, initialization is good, but then when I update the view I get an error

WKJavaScriptExceptionLineNumber=1, WKJavaScriptExceptionMessage=TypeError: webkit.messageHandlers.bridge.onMessage is not a function.

Finally I used other people's method to solve it

https://stackoverflow.com/a/56325336/12679246

window.onMessage = function(msg) {
    // ...
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment