PhoneGap, iframe not work on iOS but do on Android - ios

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.

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.

cordova ios device ready not fire until tap

I use cordova regular on ubuntu for android.
I compile with build.phonegap.com for ios, uploading zip project.
with Android all fine, but with ios deviceready not fire until i tap or change the focus to other thing.
Mi index is simple:
<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' https://ssl.gstatic.com data:* gap://* file://* tel:* 'unsafe-inline' 'unsafe-eval' ;
style-src 'self' 'unsafe-inline';
frame-src 'self' s-static.ak.facebook.com static.ak.facebook.com www.facebook.com;
connect-src 'self' https://app.mypage.es/ connect.facebook.net www.facebook.com;
media-src *;
img-src 'self' www.google-analytics.com www.facebook.com;
script-src 'self' 'unsafe-inline' www.google-analytics.com connect.facebook.net www.facebook.com">
<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">
</div>
<script type="text/javascript" src="jquery-3.2.1.min.js"></script>
<script src="fastclick.js"></script>
<script type="text/javascript" src="cordova.js"></script>
<script type="text/javascript" src="js/index.js"></script>
</body>
</html>
and the index.js
document.addEventListener("deviceready", onDeviceReady, false);
function onDeviceReady() {....stuff}
i try diferent alternatives to content-policy and diferent ways to atach event
What is the correct way?
finally removing all platforms and plugins, and adding them after, solve my problems.
have you tried restarting?

Phonegap 6.4.2 iframe on iOS10 not loading

I recently found a bug on my phonegap application.
So, I decided to correct it (nice!) and I needed to update phonegap client to the new version 6.4.2.
Once done, I ran my application via "phonegap serve" and test my app on Android device and an iPhone device (with iOS 10).
Our application is a simple HTML page with an iframe inside in order to encapsulate our responsive design website.
Everything works great on Android AND on old iPhone (iOS 7.1.2) but on the new iPhone with iOS 10, the iframe doesn't load !!!
I search for a long time why... I do not understand...
So, I planned to create a new application
phonegap create TestApp
Here is the index.html code
<html>
<head>
<meta charset="utf-8" />
<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" />
<meta http-equiv="Content-Security-Policy" content="default-src gap://ready file://* *; style-src * 'unsafe-inline'; script-src * 'unsafe-inline' 'unsafe-eval'; frame-src *; ">
<link rel="stylesheet" type="text/css" href="css/index.css" />
<script type="text/javascript" src="js/index.js"></script>
<script type="text/javascript" src="js/jquery-1.7.1.min.js"></script>
<title>Hello World</title>
</head>
<body>
<iframe id="webview" src="https://www.google.com" onload="checkPage();">
</iframe>
<script type="text/javascript" src="cordova.js"></script>
<script type="text/javascript">
app.initialize();
</script>
</body>
</html>
It's really the started page with an iframe inside and this iframe doesn't load and the checkPage() is never fired.
I tried to change "Content-Security-Policy" but... did not work...
I'm out of ideas, so, if somebody had the same issue and know how to resolve this... You're welcome !
Thanks,
I can provide you more code if you want
Laurent
The answer can be found in this question:
Cordova iOS blank iframe
Simply add the following to your config.xml file:
<allow-navigation href="*" />

Why do none of my plugins work for Apache Cordova?

I am using cordova to load plugins into my app. Here is the simplified reproduceable issue:
cordova create foo
cordova plugin add pluginname --save
cordova platform add android --save
cordova build android --verbose
I can run this app using phonegap and see it on my phone. The app reports deviceready as the basic starter app is supposed to. All looks great so far.
If I look in the plugin folder I can see my plugin there. In this case my plugin is called bluetoothle.
I edit the index.js file at a location that fires after the deviceready occurs and add "alert ( typeof (bluetoothle));"
I expect that when the alert fires it should report "object". It does not do this. It reports "undefined".
I have tried this with several other plugins and I always get the same result. So it would seem that no matter what plugin I install I cannot access any of the functions within the plugin.
I do have the same Problem. But I'm using the Phonegap CLI. And the following plugin: https://github.com/randdusing/cordova-plugin-bluetoothle
I add the plugin using the command:
$ phonegap plugin add cordova-plugin-bluetoothle
I've added platform android and ios.
So in the plugins folder there is the cordova-plugin-bluetoothle folder most probably being a valid plugin packet.
Also in the plugins folder there is the android.json and ios.json file containing the section:
"cordova-plugin-bluetoothle": {
"PACKAGE_NAME": "com.phonegap.helloworld"
},
in plaforms/android there is the android.json file containing:
{
"xml": "<feature name=\"BluetoothLePlugin\"><param name=\"android-package\" value=\"com.randdusing.bluetoothle.BluetoothLePlugin\" /></feature>",
"count": 1
},
in platforms/ios there is the ios.json file containing:
{
"xml": "<feature name=\"BluetoothLePlugin\"><param name=\"ios-package\" value=\"BluetoothLePlugin\" /></feature>",
"count": 1
},
I've targeted Android SDK API 23. As the readme tells...
As I have just modified the hello-world example to call bluetoothle initialize on after the deviceready event has fired.
So where could the problem be so that the bluetoothle variable is not defined in the index.js code, when the device is ready?
So here the complete code of index.js:
var bluetoothle;
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');
console.log("platform: " + device.platform);
if(bluetoothle) {
console.log("bluetooth is not defined!");
} else {
console.log("bluetooth is not defined!");
}
console.log("yhea managed to initialize Bluetooth LE!");
},
// 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);
}
};
And the complete code of index.html:
<html>
<head>
<meta charset="utf-8" />
<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" />
<!-- This is a wide open CSP declaration. To lock this down for production, see below. -->
<meta http-equiv="Content-Security-Policy" content="default-src * 'unsafe-inline'; style-src 'self' 'unsafe-inline'; media-src *" />
<!-- Good default declaration:
* 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 eval() and inline scripts in order to mitigate risk of XSS vulnerabilities. To change this:
* Enable inline JS: add 'unsafe-inline' to default-src
* Enable eval(): add 'unsafe-eval' to default-src
* Create your own at http://cspisawesome.com
-->
<!-- <meta http-equiv="Content-Security-Policy" content="default-src 'self' data: gap: 'unsafe-inline' https://ssl.gstatic.com; style-src 'self' 'unsafe-inline'; media-src *" /> -->
<link rel="stylesheet" type="text/css" href="css/index.css" />
<title>Hello World</title>
</head>
<body>
<div class="app">
<h1>PhoneGap</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>
<script type="text/javascript">
app.initialize();
</script>
</body>
</html>
Sooo,
The Issue I had before I just "worked around" by using a different Plugin for my Bluetooth Low Energy stuff.
Later I ran into the same Problem again with another Plugin.
And then I finally got the picture where it all makes sense:
I was mainly using the Phonegap Developer App to test on-the-fly.
The Phonegap Developer App comes bundled with all the Core Plugins and some others.
!! Those plugins which are not bundled already, will never be accessible for your Phonegap Developer App for testing !!
phonegap plugin add cordova-plugin-new-unbundled
Will not make it available to the App. Only download and prebuild the files for a potential real build.
To make this work in the Phonegap Developer App you would need to build your own Phonegap Developer App adding the Plugins you need.
Otherwise your Plugins are only available in a real build.

Cordova iOS blank iframe

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';">

Resources