6

I have a WKWebView to load a website that has a custom url scheme (mycustomurl://) implemented with WKURLScheme, which the website will call using GET. Everything works as expected when the website is in http://, but breaks when I switch to https:// with the following error:

[blocked] The page at https:// (url snipped) was not allowed to display insecure content from mycustomurl://(url snipped). 

The WKURLScheme callback was never hit, so I suspect Safari or higher power blocked it :/

I already comb through SO discussions on ATS, none of it worked. I did saw some discussions like this one that mentioned this is because Safari blocks mixed content, and when I tried it directly on Safari it did generate the same result (blocked).

There seems to be no solution to this? It seems we can't turn off Safari's mixed content restriction. Then how should custom URL scheme be used and implemented because https should always a better choice than http?

I did notice most custom URL scheme tutorials have http instead of https...

bkaooo
  • 73
  • 1
  • 4
  • Is this possibly something you could try tpo explicitly allow in `-(void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler`? Try implementing it and see if you can call `decisionHandler(WKNavigationActionPolicyAllow);` – wottle Apr 16 '18 at 18:13
  • I am thinking of how to maybe load the insecure resource locally to the app and then have the webview load the resource from there using something along the lines of `[_webView loadFileURL:fileURL allowingReadAccessToURL:baseURL]` Not sure how to implement though, tell me if this makes sense and if someone can help me hash out this solution – illis69 Jun 28 '18 at 19:18
  • Did you find a solution to this problem? – Tako Mar 08 '19 at 20:00
  • @Tako - for a usable workaround see my answer – Shirkrin Aug 14 '19 at 06:28

3 Answers3

7

Not sure this answer is still relevant but an actual working solution is to use a custom WKUrlSchemeHandler to load the initial https-page from.

I recently faced a similar issue (trying to connect to a WebSocket server on device from a https-page) and the only way I found to get this working while still keeping the application secured by https was the following not-so-nice workaround:

  • register your custom WKUrlSchemeHandler for mycustomurl://
  • register a second custom WKUrlSchemeHandler, let's say myapp-remote://
  • inside webView:startURLSchemeTask::
    • retrieve the request url from the urlSchemeTask.Request
    • replace myapp-remote:// with https://
    • create a NSURLDataRequest with the https-url
    • return the response and fetched data to the urlSchemeTask

With this setup you can fetch your https-Page by using myapp-remote:// as schema for the initial load, keeping TLS security as well as validation and also have working mycustomurl:// references that your WKWebView won't block.

My implementation is in C# for Xamarin but I can provide it for clarity if it's needed.

Shirkrin
  • 3,993
  • 1
  • 29
  • 35
  • Would be great if you could share your code. We're also using Xamarin and encounter the same issue. Don't need a working sample. Just some bits as a Github Gist would already be greatly appreciated. – Ramon de Klein Jun 28 '23 at 12:33
0

According to apple office Demo: https://developer.apple.com/videos/play/wwdc2017/220/

1,add the code

+(NSDictionary *)cacheDicSchema {
    return @{@"mwweb-local":@"http",
             @"mwweb-locals":@"https"};
}

-(void)hk_setPreferences:(WKPreferences *)perferences {
    [self hk_setPreferences:perferences];

    if (@available(iOS 11.0, *)) {
        for (NSString *key in [[[self class] cacheDicSchema] allKeys]) {
            [self setURLSchemeHandler:[[WeakSchemeHandler alloc] init]  forURLScheme:key];
        }
    }
}

2, the contentRuleList as the value, and compile into the wkwebview

[
 {
 "trigger":
    { "url-filter" : ".*"
    },
 "action": {
    "type" : "make-https"
    }
 }
 }
]

compile into the WKWebView

   if (@available(iOS 11.0, *)) {
        [[WKContentRuleListStore defaultStore]
         compileContentRuleListForIdentifier:@"MWWKWebViewContentRules" encodedContentRuleList:contentRuleList
         completionHandler:^(WKContentRuleList *contentRuleList, NSError *error) {
             if (error == nil) {
                 [config.userContentController addContentRuleList:contentRuleList];
             }else{
                MWHYLog(@"compileContentRuleListForIdentifier Error == %@",[error description]);
             }
         }];

}

3,in html

 <!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0">
    <meta name="apple-mobile-web-app-capable" content="yes" />
    <meta nemo name="basepath" content="/c_mboss/smartcloud">

    <script nonce="abc">
        var domDoc = document.documentElement;
        var domMeta = document.querySelector('meta[name="viewport"]');
        var dpr = window.devicePixelRatio || 1;
        //        var dpr = 1;
        var scale = 1 / dpr;
        var rem = domDoc.clientWidth * dpr / 7.5;
        var content = 'width=' + domDoc.clientWidth * dpr +
            ', initial-scale=' + scale +
            ', maximum-scale=' + scale +
            ', minimum-scale=' + scale +
            ', user-scalable=no';

        domMeta.setAttribute('content', content);
        domDoc.style.fontSize = rem + 'px';
      </script>
    <title>XXX</title>
    <link href="https://webresource.mwee.cn/c_mboss/smartcloud/v_20180515163218/css/dist/main.min.css" rel="stylesheet">
</head>

<body>
    <div id="appview"></div>
    <input id="umengId" value="1264335506" style="display:none;" />

    <img> src="mwweb-locals://XXXXX/index/kdxz.png"/>

    <script type="text/javascript" src="mwweb-locals://XXXXX/js/mmm.js"></script>
    <script type="text/javascript" src="mwweb-locals://XXXXX/js/app.js"></script>
</body>
</html>

<img> do work as the apple said.

<script> never work, I try again and again ............

With the Error in safari

[Warning] The page at https://10.88.3.95:3334/c_mboss/smartcloud/index/index was allowed to display insecure content from mwweb-locals://XXXXX/index/kdxz.png. (index, line 44)

[Warning] [blocked] The page at https://10.88.3.95:3334/c_mboss/smartcloud/index/index was not allowed to run insecure content from mwweb-locals://XXXXX/js/mmm.js.

[Warning] [blocked] The page at https://10.88.3.95:3334/c_mboss/smartcloud/index/index was not allowed to run insecure content from mwweb-locals://XXXXX/js/app.js.

I guess the Content Securiy Policy do conflict with WKSchemeHandler in WKWebView, the Content Securiy Policy will block the process of loading static resouces before the WKSchemeHandler.

Here it is strange that why it blocked <img> but not <script> once you add contentRuleList into the WKWebView which loadRequest website https://XXXXX.

aiquantong
  • 71
  • 3
0

It is possible to set a WKURLSchemeHandler to be considered secure but only via a private API (with an example scheme of resources://:

let pool = WKProcessPool()
let selector = NSSelectorFromString("_registerURLSchemeAsSecure:")
pool.perform(selector, with: NSString(string: "resources"))

I’ve tested this out and it allows CORS requests from https:// -> resources://. But the app won’t be approved for App Store distribution.

(more details here: https://dev.to/alastaircoote/getting-wkwebview-to-treat-a-custom-scheme-as-secure-3dl3)

Alastair
  • 5,894
  • 7
  • 34
  • 61