In WKWebView we can call ObjectiveC/swift code using webkit message handlers eg: webkit.messageHandlers.<handler>.pushMessage(message)
It works well for simple javascript functions without parameters. But;
Unfortunately I couldn't find a native solution.
But the following workaround solved my problem
Use javascript promises & you can call the resolve function from your iOS code.
UPDATE
This is how you can use promise
In JS
this.id = 1; this.handlers = {}; window.onMessageReceive = (handle, error, data) => { if (error){ this.handlers[handle].resolve(data); }else{ this.handlers[handle].reject(data); } delete this.handlers[handle]; }; } sendMessage(data) { return new Promise((resolve, reject) => { const handle = 'm'+ this.id++; this.handlers[handle] = { resolve, reject}; window.webkit.messageHandlers.<yourHandler>.postMessage({data: data, id: handle}); }); }
in iOS
Call the window.onMessageReceive
function with appropriate handler id
There is a way to get a return value back to JS from the native code using WkWebView. It is a little hack but works fine for me without problems, and our production app uses a lot of JS/Native communication.
In the WKUiDelegate assigned to the WKWebView, override the RunJavaScriptTextInputPanel. This uses the way that the delegate handles the JS prompt function to accomplish this:
public override void RunJavaScriptTextInputPanel (WebKit.WKWebView webView, string prompt, string defaultText, WebKit.WKFrameInfo frame, Action<string> completionHandler) { // this is used to pass synchronous messages to the ui (instead of the script handler). This is because the script // handler cannot return a value... if (prompt.StartsWith ("type=", StringComparison.CurrentCultureIgnoreCase)) { string result = ToUiSynch (prompt); completionHandler.Invoke ((result == null) ? "" : result); } else { // actually run an input panel base.RunJavaScriptTextInputPanel (webView, prompt, defaultText, frame, completionHandler); //MobApp.DisplayAlert ("EXCEPTION", "Input panel not implemented."); } }
In my case, I am passing data type=xyz,name=xyz,data=xyz to pass the args in. My ToUiSynch() code handles the request and always returns a string, which goes back to the JS as a simple return value.
In the JS, I am simply calling the prompt() function with my formatted args string and getting a return value:
return prompt ("type=" + type + ";name=" + name + ";data=" + (typeof data === "object" ? JSON.stringify ( data ) : data ));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With