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) {
    // ...
}

@oronbz
Copy link

oronbz commented Oct 15, 2024

Amazing work, very useful!

@JacksonUtsch
Copy link

JacksonUtsch commented Apr 11, 2025

FYI: Some reason my coordinators webView was nil and had to be set elsewhere...

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