Implement JavaScript Alert and Confirm on Wkuidelegate Swiftui

How to implement WKUIDelegate into SwiftUI WKWebView?

You need to use Coordinator and then conform to WKUIDelegate:

class Coordinator: NSObject, WKUIDelegate {
var parent: Webview

init(_ parent: Webview) {
self.parent = parent
}

// Delegate methods go here
func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {
// alert functionality goes here
}
}

func makeCoordinator() -> Coordinator {
Coordinator(self)
}

Then ensure your updateUIView(..) sets the uiDelegate to the context.coordinator:

func updateUIView(_ uiView: WKWebView, context: Context) {
uiView.uiDelegate = context.coordinator
[...]
}

If you want to conform to WKNavigationDelegate then conform to it and set the navigationDelegate to the context.coordinator as well.

Full code here:

import SwiftUI
import WebKit

struct Webview : UIViewRepresentable {
let request: URLRequest
var webview: WKWebView?

init(web: WKWebView?, req: URLRequest) {
self.webview = WKWebView()
self.request = req
}

class Coordinator: NSObject, WKUIDelegate {
var parent: Webview

init(_ parent: Webview) {
self.parent = parent
}

// Delegate methods go here

func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {
// alert functionality goes here
}
}

func makeCoordinator() -> Coordinator {
Coordinator(self)
}

func makeUIView(context: Context) -> WKWebView {
return webview!
}

func updateUIView(_ uiView: WKWebView, context: Context) {
uiView.uiDelegate = context.coordinator
uiView.load(request)
}

func goBack(){
webview?.goBack()
}

func goForward(){
webview?.goForward()
}

func reload(){
webview?.reload()
}
}

WKWebView - Javascript Confirm and Alert not working

A little late but I would like to add my experience for future reference. The answer of @Bon Bon brought me on the path to the solution while I was trying to make things work with Swift 3 and IOS 10, in which case the code needs some modifications.
Firstly you need to implement also WKUIDelegate, so add it to the ViewController declaration:

class ViewController: UIViewController, WKUIDelegate {

Then when you instantiate the WKWebView object, as for example like so:

self.webView = WKWebView(frame: self.view.frame)

you need also to assign the correct value to the uiDelegate property of the instance:

self.webView?.uiDelegate = self

Then finally you can use the code provided by @Bon Bon, but note that there are some little differences required by Swift 3, as for example, the name of the presentViewController method becomes present :

func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {

let alertController = UIAlertController(title: nil, message: message, preferredStyle: .actionSheet)

alertController.addAction(UIAlertAction(title: "Ok", style: .default, handler: { (action) in
completionHandler()
}))

self.present(alertController, animated: true, completion: nil)
}

func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {

let alertController = UIAlertController(title: nil, message: message, preferredStyle: .actionSheet)

alertController.addAction(UIAlertAction(title: "Ok", style: .default, handler: { (action) in
completionHandler(true)
}))

alertController.addAction(UIAlertAction(title: "Cancel", style: .default, handler: { (action) in
completionHandler(false)
}))

self.present(alertController, animated: true, completion: nil)
}

func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (String?) -> Void) {

let alertController = UIAlertController(title: nil, message: prompt, preferredStyle: .alert)

alertController.addTextField { (textField) in
textField.text = defaultText
}

alertController.addAction(UIAlertAction(title: "Ok", style: .default, handler: { (action) in
if let text = alertController.textFields?.first?.text {
completionHandler(text)
} else {
completionHandler(defaultText)
}

}))

alertController.addAction(UIAlertAction(title: "Cancel", style: .default, handler: { (action) in

completionHandler(nil)

}))

self.present(alertController, animated: true, completion: nil)
}

That made alert, confirmation and text input to work correctly within WKWebView, without any compiler warning in Xcode 8. I'm not an expert Swift programmer, so any useful comment about correctness of the code would be very appreciated.

iOS WKWebView not showing javascript alert() dialog

To solve this you need a WKUIDelegate for your web view. It is the duty of the delegate to decide if an alert should be displayed, and in what way. You need to implement this for alert, confirm and text input (prompt).

Here is sample code without any validation of the page url or security features:

- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler
{
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:message
message:nil
preferredStyle:UIAlertControllerStyleAlert];
[alertController addAction:[UIAlertAction actionWithTitle:@"OK"
style:UIAlertActionStyleCancel
handler:^(UIAlertAction *action) {
completionHandler();
}]];
[self presentViewController:alertController animated:YES completion:^{}];
}

More in the Official Documentation

Why is WKWebView not opening links with target=_blank?

My solution is to cancel the navigation and load the request with loadRequest: again. This will be come the similar behavior like UIWebView which always open new window in the current frame.

Implement the WKUIDelegate delegate and set it to _webview.uiDelegate. Then implement:

- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures
{
if (!navigationAction.targetFrame.isMainFrame) {
[webView loadRequest:navigationAction.request];
}

return nil;
}

WKWebView loads HTML and Javascript but fails to load CSS files

The answer to this is add the following line of code to override func loadView() before creating the web view.

webConfiguration.preferences.setValue(true, forKey: "allowFileAccessFromFileURLs");

WKWebView popup not showing up

I also faced similar issue, mine was popup for connecting facebook won't show in WKWebView but works fine on safari browser.

This code was causing the issue.

- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures {
//This condition was causing the problem while trying to get popup
if (!navigationAction.targetFrame.isMainFrame) {
[webView loadRequest:navigationAction.request];
}
return nil;
}

I changed it to following code and it worked

- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures {
if (navigationAction.targetFrame == nil) {
NSURL *tempURL = navigationAction.request.URL;
NSURLComponents *URLComponents = [[NSURLComponents alloc] init];
URLComponents.scheme = [tempURL scheme];
URLComponents.host = [tempURL host];
URLComponents.path = [tempURL path];
if ([URLComponents.URL.absoluteString isEqualToString:@"https://example.com/Account/ExternalLogin"]) {
WKWebView *webViewtemp = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:configuration];
webViewtemp.UIDelegate = self;
webViewtemp.navigationDelegate = self;
[self.view addSubview:webViewtemp];
return webViewtemp;
} else {
[webView loadRequest:navigationAction.request];
}
}
return nil;
}

Swift version:

func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
if navigationAction.targetFrame == nil {
let tempURL = navigationAction.request.url
var components = URLComponents()
components.scheme = tempURL?.scheme
components.host = tempURL?.host
components.path = (tempURL?.path)!
if components.url?.absoluteString == "https://example.com/Account/ExternalLogin" {
let webViewtemp = WKWebView(frame: self.view.bounds, configuration: configuration)
webViewtemp.uiDelegate = self
webViewtemp.navigationDelegate = self
self.view.addSubview(webViewtemp)
return webViewtemp
} else {
webView.load(navigationAction.request)
}
}
return nil
}

Hope this helps you

alert() not working in WKWebview evaluateJavaScript()

There is a working example in this answer. It seems you mightn't have implemented the WKUIDelegate method correctly.



Related Topics



Leave a reply



Submit