I have a WKWebView in my application. I don't use UIWebView, because for some strange reason it doesn't open properly a web page with a lot of JS code in it.
When I tap on the link with custom url scheme "scm://", it does nothing...
My code:
- (void)viewDidLoad {
// ...
WKWebViewConfiguration *configuration = [WKWebViewConfiguration new];
if ([configuration respondsToSelector:@selector(setDataDetectorTypes:)])
[configuration setDataDetectorTypes:WKDataDetectorTypeLink];
myWebView = [[WKWebView alloc] initWithFrame:webFrame configuration:configuration];
myWebView.navigationDelegate = self;
[self.view addSubview:myWebView];
}
#pragma mark - WKNavigationDelegate
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
NSURL *requestURL = navigationAction.request.URL;
UIApplication *app = [UIApplication sharedApplication];
if ([requestURL.scheme.lowercaseString isEqualToString:@"scm"] && [app canOpenURL:requestURL]) {
[app openURL:requestURL];
decisionHandler(WKNavigationActionPolicyCancel);
}
else
decisionHandler(WKNavigationActionPolicyAllow);
}
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
{
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}
- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error
{
[self handleError:error];
}
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error
{
[self handleError:error];
}
#pragma mark - Handle web view errors.
- (void)handleError:(NSError *)error
{
UIApplication *app = [UIApplication sharedApplication];
app.networkActivityIndicatorVisible = NO;
NSURL *failedUrl = error.userInfo[NSURLErrorFailingURLErrorKey];
if ([failedUrl.scheme.lowercaseString isEqualToString:@"scm"]) {
[app openURL:failedUrl];
}
}
When I click custom url, handleError() is never called, neither decidePolicyForNavigationAction().
Ok, figured this out... happens that the link was opening in new window, so adding next code along with setting UIDelegate made it work
// Somewhere in viewDidLoad()...
myWebView.UIDelegate = self;
}
- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures
{
NSLog(@"createWebViewWithConfiguration %@ %@", navigationAction, windowFeatures);
if (!navigationAction.targetFrame.isMainFrame) {
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
[(WKWebView *)_webView loadRequest:navigationAction.request];
}
return nil;
}
-(void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{
NSURLRequest *request = navigationAction.request;
if(![request.URL.absoluteString hasPrefix:@"http://"] && ![request.URL.absoluteString hasPrefix:@"https://"]) {
if([[UIApplication sharedApplication] canOpenURL:request.URL]) {
//urlscheme, tel, mailto, etc.
[[UIApplication sharedApplication] openURL:request.URL];
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
}
decisionHandler(WKNavigationActionPolicyAllow);
}
Note: This answer is just focus on urlscheme, but maybe lead to other problems. Thanks for your feedback!
The following works in Swift 5.1 on iOS 13.1.3 (variation of @hstdt's answer) for WKWebView handling minimally the following (tested) schemas: sms:
, tel:
, and mailto:
.
Add the following to whereever you're setting up your WKWebView
.
// assign the delegate
webView.navigationDelegate = self
Then, add the following function somewhere in your class.
func webView(_ webView: WKWebView,
decidePolicyFor navigationAction: WKNavigationAction,
decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
// if the request is a non-http(s) schema, then have the UIApplication handle
// opening the request
if let url = navigationAction.request.url,
!url.absoluteString.hasPrefix("http://"),
!url.absoluteString.hasPrefix("https://"),
UIApplication.shared.canOpenURL(url) {
// have UIApplication handle the url (sms:, tel:, mailto:, ...)
UIApplication.shared.open(url, options: [:], completionHandler: nil)
// cancel the request (handled by UIApplication)
decisionHandler(.cancel)
}
else {
// allow the request
decisionHandler(.allow)
}
}
Explanation:
Note: Comment if you find other schemas working or not working using this solution.
Again, this solution was sourced and modified from @hstdt's answer.
Solution for Swift 5: The following is a variation of mattblessed's answer for WKWebView which works for all application URL-Schemes not only the system URL-Schmes like "sms:", "tel:", and "mailto:"
This solution will work without adding custom URL Schemes to your apps plist file via LSApplicationQueriesSchemes
. (Which is necessary since iOS 10 - for detail see this article: canOpenURL not working in ios 10)
Add the following implementation of WKNavigationDelegate
to your class:
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
if let requestUrl = navigationAction.request.url, requestUrl.isCustomUrlScheme() {
decisionHandler(.cancel)
// try to open URLs like e.g. "whatsapp://"
UIApplication.shared.open(requestUrl, options: [:]) { success in
if !success {
//TODO
// add your code for handling URLs that can't be opened here -
// maybe show an error alert
}
}
} else {
// allow the request
decisionHandler(.allow)
}
}
Add the following Extension of URL
to your class:
extension URL {
func isCustomUrlScheme() -> Bool {
let webUrlPrefixes = ["http://", "https://", "about:"]
let urlStringLowerCase = self.absoluteString.lowercased()
for webUrlPrefix in webUrlPrefixes {
if urlStringLowerCase.hasPrefix(webUrlPrefix) {
return false
}
return urlStringLowerCase.contains(":")
}
}
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