Cordova iOS blank iframe - ios

In a Cordova app that I am working on there is an iframe. The problem is that when testing the app (both simulator and on device) the iframe is blank. On Android the iframe works perfectly however.
The iframe is loaded dynamicly in an Angular directive.
Within the directive link function the following code is used to load and append the iframe to the directive's element:
var iframe = angular.element('<iframe class="widget" width="' + widgetWidth + '" height="' + widgetHeight + '"></iframe>');
iframe.attr('src', url);
element.append(iframe);
I have also tried using something in the following lines:
var iframe = document.createElement('iframe');
iframe.src = url;
This results in somthing like the following (using Safari web inspector):
<iframe class="widget" width="384" height="505" src="http://hostname/correct/uri"></iframe>
In my index.html file I have the following set:
<meta http-equiv="Content-Security-Policy" content="script-src * 'unsafe-eval'; connect-src * 'unsafe-eval'; object-src 'self'; style-src * 'unsafe-inline';">
I also have the following lines in my cordova config.xml:
<access origin="*" subdomains="true" />
<allow-intent href="http://*/*" />
<allow-intent href="https://*/*" />
There is also no errors or warnings in Safari Web Inspector.
So my question is, is there some trickery to get iFrames to work in Cordova iOS apps that I am missing. Or what is wrong with my current config/code?
I am using angularjs 1.5.3 and have jquery 2.2.1 (loaded before angularjs) in case that helps.

The problem was the allow-navigation tag. So to solve it I only had to put the <allow-navigation href="*" /> tag into the project's config.xml file.
I came to the solution through the output box in xcode while the simulator was running. There was a message containing the url of the iframe in question and something about "internal navigation rejected".

Have you tried setting child-src and/or frame-ancestors in the Content-Security-Policy meta tag? These may need setting to * also or something more restrictive like just the iframe source URL(s) you are using.
There's information about this at content-security-policy.com
Example based on your content security policy:
<meta http-equiv="Content-Security-Policy" content="script-src * 'unsafe-eval'; child-src *; connect-src * 'unsafe-eval'; object-src 'self'; style-src * 'unsafe-inline';">

Related

In Cordova app, physical iPhone SE can't display images from "file://" URLs; OK in iOS simulator and Android

I'm writing an app with Cordova 11.0.0, cordova-ios 6.2.0, and Xcode 13.3 that sets the background image to the user's choice. Everything works fine on Android and on the iOS simulator. However, when running on a physical iPhone SE (2022) with iOS 15.4, the background image is not displayed, though it seems to set style.backgroundImage correctly on the element, and I'm able to read the image file correctly using a standard FileReader object. It appears that any local images using a file:// URL are not displayed. I'm loading them from under cordova.file.dataDirectory, so I can't just convert to a relative http:// URL. I believe my Content-Security-Policy is permissive enough (?) (see index.html below).
I made a small demo of this; the only plugin it uses is cordova-plugin-file 6.0.2. My config.xml contains:
<content src="index.html" />
<allow-intent href="http://*/*" />
<allow-intent href="https://*/*" />
<platform name="ios">
<preference name="allowFileAccessFromFileURLs" value="true" />
<preference name="allowUniversalAccessFromFileURLs" value="true" />
</platform>
My index.html is:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Security-Policy"
content="default-src * file: filesystem: ; img-src * file: filesystem: ; style-src * file: filesystem: 'unsafe-eval' ;">
<meta name="viewport" content="initial-scale=1, width=device-width, viewport-fit=cover">
<link rel="stylesheet" href="css/index.css">
<title>Hello World</title>
<script src="cordova.js"></script>
<script src="js/index.js"></script>
</head>
<body>
<h1>Background image should show up</h1>
</body>
</html>
My index.js is:
// Wait for the deviceready event before using any of Cordova's device APIs.
document.addEventListener('deviceready', onDeviceReady, false);
async function onDeviceReady() {
try{
// this block just copies file from under cordova.file.applicationDirectory
// to under cordova.file.dataDirectory, for this demo
// FileEntry.copyTo() throws error on ios if file already exists, so use try/catch
try {
let entry= await new Promise((resolve, reject) =>
resolveLocalFileSystemURL(cordova.file.applicationDirectory + 'www/img/home_bg.jpg',
resolve, reject) ) ;
let dest_dir= await new Promise((resolve, reject) =>
resolveLocalFileSystemURL(cordova.file.dataDirectory, resolve, reject) ) ;
await new Promise((resolve, reject) =>
entry.copyTo(dest_dir, undefined, resolve, reject) ) ;
} catch(e) {}
// set full background property
let full_url= cordova.file.dataDirectory + 'home_bg.jpg' ;
document.body.style.background= 'url(' + full_url + ') center/cover' ;
// this shows the correct 'url("file:///Users/.../Library/NoCloud/home_bg.jpg")'
alert('computed backgroundImage=[' + getComputedStyle(document.body).backgroundImage + ']') ;
} catch(e) {
alert('in odr(): '+e) ;
}
}
My index.css is simply:
body {
height:100vh;
width:100vw;
}
h1 {
font-size:24pt;
margin:3rem;
text-align:center;
}
And finally, I have a background image in img/home_bg.jpg that is copied to be under cordova.file.dataDirectory.
I've read many questions here about file:// URLs, but none of the solutions have worked and are appropriate (e.g. using data: URLs for the images is impractical and unscalable). I know that the app paths change for every install on an iPhone, but the code above should still work.
How can I get images to display on a physical iPhone using file:// URLs? Am I missing some setting in Xcode or elsewhere?
Thanks for any help!
Thanks to this answer by #jcbdrn, I managed to work around this by using blob: URLs for all displayed images:
let blob= new Blob([await read_file_binary(file_entry)]) ;
img.src= URL.createObjectURL(blob) ;
... where read_file_binary() reads a file as an arrayBuffer. Note that the Content Security Policy must include blob: in the img-src directive.
This isn't as efficient as just using file: URLs, but it's much better than using data: URLs. It does seem like a bug in either cordova-ios (?) or in WKWebView (?), but I'm set for now.

Ionic 4 - InAppBrowser with target "_blank" doesn't work on IOS?

I'm new to ionic developement, and have been facing some problem with InAppBrowser.
My app is suposed to be a WebView, running on InAppBrowser, the target that i'm providing is "_blank" because i need the events to detect when a pdf url gonna be open, so i can open that url with browserTabs, it's works fine on android.
But i can't make it work on IOS, when i set the target as "_blank", i get a white screen, it's only works with target as "_self" but from what i could see the events doesn't work with "_self".
I've tried add in these tags on my config.xml:
<allow-intent href="*" />
<allow-navigation href="*" />
<access origin="*" />
I've tried add in the CSP on my index.html
<meta http-equiv="Content-Security-Policy" content="default-src *; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'">
None of theses tags worked.
So, if anyone has a light of what i could do, i would be very thankfull.
Edit 1: Codes:
browserOptions: string = "location=no,beforeload=yes,toolbar=no";
openInAppBrowser(urlToOpen: string) {
this.browser = this._inAppBrowser.create(urlToOpen, '_blank',this.browserOptions );
this.browser.on("beforeload").subscribe( event => {
if(event.url.match("/report") || event.url.indexOf("/relatorio")>0) {
this._browserTab.isAvailable()
.then(isAvailable => {
if (isAvailable) {
this._browserTab.openUrl(event.url);
}
});
}
});
}

PhoneGap, iframe not work on iOS but do on Android

I try this way:
<div id="contenedor">
</div>
</body>
<script>
$('<iframe src="http://XXXXX.org/" height="100%" width="100%" frameborder="0"></iframe>').appendTo('#contenedor');
</script>
or this way:
<body>
<div id="contenedor">
<iframe src="http://XXXXX.org/" style="width:100%; height:100%;">
</div>
</body>
Both works perfectly on Android but not on iOS. I'm using phonegap desktop 4.2.
I read all post about it here and changed config.xml many many times according the answers but nothing works on iOS.
Like:
<access origin="*"/>
<allow-intent href="http://*/*"/>
I changed this line too according other post but doesn't work too.
> <meta http-equiv="Content-Security-Policy" content="default-src *
> 'unsafe-inline'; style-src 'self' 'unsafe-inline'; media-src *; " />
I'm super stuck because works on Android but not in iOS.

phonegap app freeze in ios10

I have a phonegap application, that was working properly until last friday, when it stoped from being accept in apple store with the following message:
This app attempts to access privacy-sensitive data without a usage description. The app's Info.plist must contain an NSPhotoLibraryUsageDescription key with a string value explaining to the user how the app uses this data.
This app attempts to access privacy-sensitive data without a usage description. The app's Info.plist must contain an NSBluetoothPeripheralUsageDescription key with a string value explaining to the user how the app uses this data.
This app attempts to access privacy-sensitive data without a usage description. The app's Info.plist must contain an NSMicrophoneUsageDescription key with a string value explaining to the user how the app uses this data.
To correct this issue, after some research, I come to the following solution, to add some cordova plugins in my config.xml file:
<plugin name="cordova-plugin-media-capture" source="npm" spec="1.4.0">
<variable name="MICROPHONE_USAGE_DESCRIPTION" value="App would like to access your microphone." />
<variable name="CAMERA_USAGE_DESCRIPTION" value="App would like to access the camera." />
<variable name="PHOTOLIBRARY_USAGE_DESCRIPTION" value="App would like to access the library." />
</plugin>
<plugin name="cordova-plugin-ios-ble-permissions" source="npm" spec="*">
<variable name="BLUETOOTH_USAGE_DESCRIPTION" value="App would like to access your bluetooth." />
</plugin>
This solved the problem in the apple store, and I confirmed that the Info.plist file have all this variables there.
But now the app freezes/crashes in, and only in iOs10 devices.
I'm asking for some guidance/help to identify what could be this problem source.
Thank you all in advance.
EDIT:
Finnaly was able to debug the app remotely and find out some errors like this:
[Error] Refused to load data:text/javascript;charset=utf-(...)-app-shell.html-170.js%0A because it does not appear in the script-src directive of the Content Security Policy
My current meta tag has this values:
<meta http-equiv="Content-Security-Policy" content="default-src gap://ready file://* *; script-src 'self' 'unsafe-inline' 'unsafe-eval' *; style-src 'self' 'unsafe-inline' *; img-src 'self' data: blob: *; media-src 'self' mediastream: blob:; connect-src * blob:">
and whitelist configuration:
<plugin name="cordova-plugin-whitelist" spec="1.3.1"/>
<access origin="*"/>
<allow-navigation href="*"/>
<allow-intent href="http://*/*"/>
<allow-intent href="https://*/*"/>
<allow-intent href="tel:*"/>
<allow-intent href="sms:*"/>
<allow-intent href="mailto:*"/>
<allow-intent href="geo:*"/>
any tip of what im doing wrong?
It might be caused by Content-Security-Policy.
try to add the default-src gap: in the <meta> tag.
e.g:
<head>
<meta http-equiv="Content-Security-Policy" content="default-src * 'self' gap: wss: ws:; font-src * data:; img-src * data:; style-src 'self' https: 'unsafe-inline'; script-src 'self' https: 'unsafe-inline' 'unsafe-eval'">
</head>
ref:
"No Content-Security-Policy meta tag found." error in my phonegap application
Solved it!
In the meta tag instead of:
script-src 'self' 'unsafe-inline' 'unsafe-eval' *
I added:
script-src 'self' 'unsafe-inline' 'unsafe-eval' data: *;

Cordova/Phonegap Build geolocation on iOS timeout

I have been experiencing the same issue, and have tried in the past 2 weeks numerous solutions found online for this with no success, any help appreciated :)
I am writing a simple app using Cordova for IOS and Android and building it using Phonegap build. The problem is that I cannot get the "navigator.geolocation.getCurrentPosition" (or navigator.geolocation.watchPosition) calls to return anything except a timeout error on iOS. (works perfectly on Android)
Additionally, the location services dialog never appears (requesting user permission to allow GPS for the app)
To add to this strange behavior, it seems that i have to touch the screen after the app is loaded to initiate the geolocation call, on most cases the app just sits there and does nothing until the screen is touched.
Testing this on iPhone 5 with iOS 9
Things I tried:
Changing timeout settings (up to 30 seconds)
Setting enableHighAccuracy true/false
Running code with or without the geolocation plugin
Manually adding the NSLocationWhenInUseUsageDescription/NSLocationAlwaysUsageDescription settings (or both) to the plist file
Installing different plugin versions for the geolocation plugin
Changing Content Security Policy meta tag
Trying to add or remove the <plugin> declaration from root config.xml
Current plugins installed ($cordova plugin list):
cordova-plugin-dialogs 1.2.0 "Notification"
cordova-plugin-geolocation 1.0.1 "Geolocation"
cordova-plugin-whitelist 1.2.0 "Whitelist"
cordova.plugins.diagnostic 2.3.5 "Diagnostic"
Root config.xml:
<?xml version='1.0' encoding='utf-8'?>
<widget id="info.test" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
<name>App name</name>
<description>
App Name
</description>
<author email="test#test.com" href="http://test.com">
App Team
</author>
<content src="index.html" />
<plugin name="cordova-plugin-whitelist" spec="1" />
<access origin="*" />
<allow-intent href="http://*/*" />
<allow-intent href="https://*/*" />
<allow-intent href="tel:*" />
<allow-intent href="sms:*" />
<allow-intent href="mailto:*" />
<allow-intent href="geo:*" />
<platform name="android">
<allow-intent href="market:*" />
</platform>
<platform name="ios">
<allow-intent href="itms:*" />
<allow-intent href="itms-apps:*" />
</platform>
</widget>
index.js
var geo = {
getGeo: function() {
navigator.geolocation.getCurrentPosition(
geo.onSuccess,
geo.onError,
{maximumAge:0, timeout: 5000, enableHighAccuracy: false});
},
onSuccess: function(position) {
alert('GOT location');
alert(position.coords.latitude + ' --- ' + position.coords.longitude);
},
onError: function(error) {
alert('error getting geo!');
}
};
var app = {
// Application Constructor
initialize: function() {
this.bindEvents();
},
// Bind Event Listeners
//
// Bind any events that are required on startup. Common events are:
// 'load', 'deviceready', 'offline', and 'online'.
bindEvents: function() {
document.addEventListener('deviceready', this.onDeviceReady, false);
},
// deviceready Event Handler
//
// The scope of 'this' is the event. In order to call the 'receivedEvent'
// function, we must explicitly call 'app.receivedEvent(...);'
onDeviceReady: function() {
app.receivedEvent('deviceready');
},
// Update DOM on a Received Event
receivedEvent: function(id) {
var parentElement = document.getElementById(id);
var listeningElement = parentElement.querySelector('.listening');
var receivedElement = parentElement.querySelector('.received');
listeningElement.setAttribute('style', 'display:none;');
receivedElement.setAttribute('style', 'display:block;');
console.log('Received Event: ' + id);
geo.getGeo();
}
};
app.initialize();
iOS Plist file:
<key>NSLocationAlwaysUsageDescription</key>
<string>This app requires constant access to your location in order to track your position, even when the screen is off.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string/>
Index.html:
<html>
<head>
<!--
Customize this policy to fit your own app's needs. For more guidance, see:
https://github.com/apache/cordova-plugin-whitelist/blob/master/README.md#content-security-policy
Some notes:
* gap: is required only on iOS (when using UIWebView) and is needed for JS->native communication
* https://ssl.gstatic.com is required only on Android and is needed for TalkBack to function properly
* Disables use of inline scripts in order to mitigate risk of XSS vulnerabilities. To change this:
* Enable inline JS: add 'unsafe-inline' to default-src
-->
<meta http-equiv="Content-Security-Policy" content="default-src 'self' data: gap: https://ssl.gstatic.com 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *">
<meta name="format-detection" content="telephone=no">
<meta name="msapplication-tap-highlight" content="no">
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width">
<link rel="stylesheet" type="text/css" href="css/index.css">
<title>Hello World</title>
</head>
<body>
<div class="app">
<h1>Apache Cordova</h1>
<div id="deviceready" class="blink">
<p class="event listening">Connecting to Device</p>
<p class="event received">Device is Ready</p>
</div>
</div>
<script type="text/javascript" src="cordova.js"></script>
<script type="text/javascript" src="js/index.js"></script>
</body>
</html>
Any help in the right direction appreciated!
#daddio
Oh. that's it. I should be more dogmatic on this. This should take care of the problem.
It is not advisable to use Phonegap CLI to make your Phonegap Build build project. Phonegap build requires that index.html and config.xml both sit in the root directory. All the extra files that you are required to use with Phonegap CLI, never are created or needed with Phonegap Build.
So, I'm going to give you one of my working demos. Notice that all the files are in one (1) directory.
tutorial/blog entry - An HTML Boilerplate for Phonegap Build
source code Phonegap--Generic-Boilerplate
Notice how the compiler version is set to:
<preference name="phonegap-version" value="cli-5.2.0" />
Notice, if you change cli-5.2.0 to 3.7.0, nothing appears to change.
Basically for Phonegap Build, you need index.html and config.xml - that's it. Then for security reasons (as of Cordova Tools 5.0.0), it is advisable to create a css file and a javascript file. However, I'll show you how to get around this.
Here is my complete list of Demo Apps.
Phonegap Demo Apps
YOUR FIX
This is my working code, test with 3.5.0 and cli-5.1.1 and cli5.2.0
source code Phonegap-GPS-Test
On Your fix, notice how the version is set to: <preference name="phonegap-version" value="3.5.0" />
Okay, I trust all of this will work for you. As such, your documentation is here:
https://build.phonegap.com/docs
There are some special rules for adding plugins, but I'll give you those when your program is running.
How to add Plugins with Phonegap Build
FOR THE MOST IMMEDIATE FUTURE, get your *core* plugins from this list:
http://cordova.apache.org/docs/en/5.4.0/cordova/plugins/pluginapis.html
Get your 3rd-party plugin from this source:
http://cordova.apache.org/plugins/
When using Phonegap Build, sometimes the pluins get fixed (or updated) and this breaks Phonegap Build. This is because the "fixes" require the latest version of the compiler, and Phonegap Build is always at least one version behind.
There are two ways to deal with 3; see 4 and 5.
I have created this Worksheet. You may want to make a copy or just use it as a reference. I use this worksheet to create my demos, I so know the list is good. I am working on cli-5.2.0 right now. (Should finish by Monday or so.) However, I do not test ALL 3rd-party plugins; there are 800+ plugins.
If you fail to set the version number on a plugin, you will get the latest version. If your build fails, then set the version. If the build still fails, try the previous two or three version to find one that works. NOTE, these older plugins may have bugs that prevent you from using them. So, try an even earlier version.
Lastly, if you think you have hit a bug, then here is a page with links to the Bug respository for each plugin. Last Update is on the top left. Best of Luck.

Resources