Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cordova, iOS and iframe won't load content unless I allow-access href="*"

I have a web app, which has an embedded map field, which is implemented using an iframe to https://maps.google.com/...

I am porting our app (which runs as a home screen icon currently) to Cordova on iOS, so adding a Cordova wrapper. We already run the app via Cordova on Android.

I have a div, with a child element

<iframe src="https://maps.google.com/?iwloc=&output=embed&q=something"></iframe>

Initially, when the Cordova project was concerned only with Android, I had in config.xml

<access origin="*" />
<access origin="file://*" />
<access origin="http://*" />
<allow-navigation href="http://*" />

However, this does not work. The iframe with the map url doesn't even attempt to load, and there is no indication why.

So I started reading up and playing around with these settings, and on iOS basically, all they do is map to NSAppTransportSecurity settings in Info.plist.

Turns out that <allow-navigation href="http://*" /> is ignored completely, only allow-navigation that specify domains or just * are supported, so I tried the more specific domain based ones, such as

<allow-navigation href="http://maps.google.com/*" />

Which does create a domain entry for maps.google.com and sets NSExceptionAllowsInsecureHTTPLoads to true but still the iframe won't load.

The ONLY thing I can find that allows the iframe to load the maps URL is by adding

<allow-navigation href="*"/>

Which essentially sets NSAllowsArbitraryLoads to true which basically turns TLS off, and will trigger an app review and require justification.

SideNote: <access origin="*"/> also sets NSAllowsArbitraryLoads to true but alone prevents the initial URL from loading inside the webview (it loads externally).

I am at a bit of a loss as to what combination of config.xml or NSAppTransportSecurity settings I need to get this working without just allowing everything and the app review issues that will undoubtedly trigger.

Note: These requests don't trigger a CSP warning, I don't think the webview is even getting that far, and if I set allow-navigation to * it works, which would suggest CSP is fine.

When it fails, all I get in web debugger for that request is 'an error occurred trying to load the resource', and nothing in XCode console.

like image 454
Austin France Avatar asked Aug 17 '17 17:08

Austin France


People also ask

Does Cordova support iframe?

Iframes and the Callback Id MechanismIf content is served in an iframe from a whitelisted domain, that domain will have access to the native Cordova bridge.

What browser does Cordova use on iOS?

Ionic apps deployed using Cordova run within low-level, bare bones web browsers called “webviews”. Cordova utilizes each platform's native webview in order to deploy the webapp within a native app wrapper. iOS's default web browser is Safari.


1 Answers

After struggling with the same problem, I found a configuration that worked for me!

I want my app to include Google Calendar in an iframe, which means I need to specify for Cordova that the URL of Google Calendar should be handled within the app's webview.

Having <allow-navigation href="*" /> makes it work, but it has the side effect that all links the user clicks will be handled inside the web view as well (my app has functionality for giving the user a feed of news, and sometimes there are links in the text for the user to click). Having arbitrary web pages inside my app's fullscreen web view rendered no way for the user to navigate back to my app. On Android there is always a "back button", but on iOS there is none, forcing the user to quit the application.

My solution was two-fold: specify URLs in allow-navigation and setup a CSP that will allow content and scripts:

In config.xml:

<access origin="*"/>
<allow-navigation href="https://calendar.google.com/*" />
<allow-navigation href="https://apis.google.com/*" />
<allow-navigation href="https://clients6.google.com/*" />

On iOS it was not enough to have calendar.google.com; I had to find all the domains that was accessed by the iframe, hence the need for the three URLs above. I used the network log in Chrome's inspect tool to find these domains. For Android this was not necessary.

I could have set <allow-navigation href="https://*.google.com/* />, but that would have opened up too broadly for my needs (e.g. links to "www.google.com" would have been handled in webview instead of external browser).

In index.html:

<head>
...
    <meta http-equiv="Content-Security-Policy"
          content="default-src * 'self' data: gap: 'unsafe-inline' 'unsafe-eval';
          style-src * 'self' 'unsafe-inline' 'unsafe-eval' gap:;
          script-src * 'self' 'unsafe-inline' 'unsafe-eval' gap:;">
...

Note - the CSP above is probably allowing way too much. But this is a starting point and then you can narrow the access according to your app's needs.

Now the app renders the iframe with Google Calender URL correctly on both iOS and Android, and lets other links invoke the device's browser, i.e. outside the app.

like image 83
Leif John Avatar answered Oct 25 '22 23:10

Leif John