3

On iOS versions previous to 10, I was able to send information from the JavaScript/HTML loaded into a UIWebView back to my application by creating an iFrame on the document or setting document.location.href to a custom URL which the web view would tried to load:

<html>
<body><input id="clickMe" type="button" value="clickme" onclick="changeWindow();" /></body>
<script type="text/javascript">
    function changeWindow() {
        //create temp frame
        iFrame = this.createIFrame('onStatusChange://eyJ1c2VyTmFtZSI6IkpBTCIsLCJwcm92aWRlciI6IkVtYWlsIn0=');
        //remove the frame now
        iFrame.parentNode.removeChild(iFrame);
    }

    function createIFrame(src) {
      var rootElm = document.documentElement;
      var newFrameElm = document.createElement('IFRAME');
      newFrameElm.setAttribute('src', src);
      rootElm.appendChild(newFrameElm);
      return newFrameElm;
    }
</script>
</html>

Then on the client, I would just listen for the UIWebViewDelegate callback webView:shouldStartLoadWithRequest:navigationType:, and check to see if the request.URL.scheme was equal to my custom scheme (in this case onStatusChange).

This is a popular way of communicating between the JavaScript and an iOS app, as seen in popular questions such as How to invoke Objective C method from Javascript and send back data to Javascript in iOS?.

This works on any app built with Xcode 7 (Objective-C or Swift) on iOS 9 and 10 devices. I'm running into an issue where the delegate method is not called on any applications built with Xcode 8. It's as if the web view isn't even trying to load the URL, which in turn is not triggering the delegate callback.

Were there any changes to UIWebView or WebKit from Xcode 7 to 8 or iOS 9 to 10 which would cause this not to work? What's really puzzling to me is that a production app I have built with Objective-C in Xcode 7 targeting iOS 8 works on an iOS 10 device, but a debug build built with Xcode 8 of the exact same codebase does not work.

Community
  • 1
  • 1
JAL
  • 41,701
  • 23
  • 172
  • 300

2 Answers2

2

Ok, long story short we use a special URL scheme onStatusChange:// to send Base64 encoded data from the web view back to our iOS application. I believe UIWebView on iOS 10 chokes when trying to load a URL that ends in one or more equals sign characters, and loads about:blank instead of the actual URL.

Since this works perfectly on iOS 9, I'm assuming this is a defect with iOS 10 and have opened rdar://29035522. A full reproducible example of the issue is available in the body of that radar.

I am reading through the Base-N encoding RFC to determine if it is acceptable to remove the padding = characters at the end of my data string, or if they need to be removed from the web and added on the client before decoding the data.

The solution I ended up implementing was percent-escaping the Base64 encoded data, and unescaping it on the client. Not the most elegant solution, but probably the best for safety.

Community
  • 1
  • 1
JAL
  • 41,701
  • 23
  • 172
  • 300
  • any updates with the rdar? I see it still happening on iOS 10.2.1 , also it happens to us without the special char as well. – Aviel Feb 12 '17 at 20:04
  • @Aviel Sadly nothing to report, my radar is still marked as "open" with no update or rank. You could consider duplicating the bug report and filing a new radar to show Apple that more than one person has this issue. – JAL Feb 13 '17 at 00:21
  • @Aviel Did you duplicate the bug report and also post on OpenRadar so other developers can see the report? – JAL Feb 22 '17 at 21:51
  • Yep my teammate added a radar : http://openradar.appspot.com/radar?id=4955577910296576 – Aviel Feb 23 '17 at 23:45
  • @JAL How do you call your custom URL scheme (onStatusChange://) from within the web view? A JS way would be best for me as I'm building my url dynamically. – DwarDoh Aug 11 '17 at 23:31
  • @DwarDoh look at the code I use in the question, `this.createIFrame`. – JAL Aug 12 '17 at 19:48
  • @JAL Thanks, didn't realize you had answered your own question. Why not just use window.open(src)? I am trying to go across apps and both of these scheme launchings fail silently. Any thoughts? tia – DwarDoh Aug 14 '17 at 20:26
  • @DwarDoh I didn't answer my own question, the code in the question reproduces an issue that's different from yours. You should ask a new question. – JAL Aug 14 '17 at 22:36
0

Thats because iOS now blocks http requests by default. You have to reenable it in your info.plist.

https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW33

Josh Homann
  • 15,933
  • 3
  • 30
  • 33
  • This isn't an HTTP request (this test file is run locally), and I've also already configured ATS to allow loads from white listed domains. – JAL Oct 27 '16 at 17:43