We have a web app that's using LoopBack from Strongloop for the API and backend, and Angular on the frontend, with Cordova used to package for mobile. The web app and iOS target from Cordova work great as expected, but when we try to build for an Android device the app server is unreachable from the device. More specifically, after loading the client app and trying to log in, the device makes a POST to my API but never receives a response (and as far as I can tell the request never actually hits the server).
Here's what I've tried so far:
Make sure that access is set to origin="*" in config.xml
Make sure that a Content-Security-Policy meta tag is set in my (single-page) app's index.html, allowing remote network
Make sure that the INTERNET permission is being correctly set in the Android Manifest
Make sure that the app server is reachable from the device in browser
Make sure the generated lb-services.js Angular service has the correct API address
Try generating an Ionic Framework app and dropping my app code into that in case it generates something I need
Since I'm able to get my app running in iOS using Cordova without any issues, I'm thinking there must be something particular to my Android configuration here. I did encounter a separate issue where a plugin that was installed was not compatible with the latest Cordova, but removing that plugin seems to have resolved that. What is different about building for Android that would keep this from working?
EDIT:
I've switched to using Phonegap Build in the hopes that it would be an easier workflow, but I still see the same issues.. Here is the whitelist/CORS configuration that I'm doing:
meta tag in index.html:
<meta http-equiv="Content-Security-Policy" content="default-src *; style-src * 'self' 'unsafe-inline'; script-src * 'self' 'unsafe-inline' 'unsafe-eval'">
config.xml (Phonegap Build, identifiable info removed):
<?xml version="1.0" encoding="UTF-8" ?>
<widget xmlns="http://www.w3.org/ns/widgets" xmlns:gap="http://phonegap.com/ns/1.0" id="..." version="1.0.0">
<name ... />
<description ... />
<author ... />
<icon src="icon.png" />
<gap:splash src="splash.png" />
<preference name='phonegap-version' value='cli-5.1.1' />
<gap:plugin name="com.indigoway.cordova.whitelist.whitelistplugin" version="1.1.1" />
</widget>
Install https://github.com/apache/cordova-plugin-whitelist since Cordova 5.0.0 is mandatory for CORS query.
Have you installed it ?
If not, this is certainly your issue ;)
It turns out that I was setting <access origin="*" /> in my original Phonegap configuration, but not in my Phonegap Build settings. Making sure that <access origin="*" /> is present in the config.xml used by Phonegap Build seems to fix this.
Related
When I ran the project on Chrome browser the ajax requests worked fine but when I installed the app on Android the requests are not working anymore.
This is the code:
var xhr=new XMLHttpRequest()
xhr.onerror=function(){
var message=alert(txt('Please turn on mobile data or Wi-Fi','Ligue os dados moveis ou Wi-Fi'))
}
xhr.onreadystatechange=function (){
if (this.status== 200 && this.readyState == 4){
alert("trye")
eval(xhr.responseText)
}
}
xhr.open("POST",`http://dpreaction.ml?i=js`)
xhr.setRequestHeader('Content-type','application/x-www-form-urlencoded')
xhr.send()
the config.xml file
<?xml version='1.0' encoding='utf-8'?>
<widget id="com.teste.teste" version="1.0.0" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
<name>DP Reaction</name>
<description>Inrease your things</description>
<author email="gilluisfrancisco70#gmail.com" href="http://dpreaction.ml">
DP Reaction
</author>
<content src="index.html" />
<allow-intent href="*" />
<access origin="*" />
<allow-naviation href="*" />
</widget>
And this is my tag:
<meta http-equiv="Content-Security-Policy" content="default-src * 'unsafe-inline' 'unsafe-eval' data: gap: https://ssl.gstatic.com 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *; img-src 'self' data: content:;">
According to https://github.com/apache/cordova-android/issues/1354:
Content-Security-Policy is a different security mechanism than CORS (Cross-Origin Resource Sharing).
In cordova-android#10, they implemented a WebAssetLoader, which proxies requests through the https://localhost protocol. The WebAssetLoader acts like a private web server only accessible to your app. This was done because some web view features require you to be in a "secure context" (e.g. HTTPS) for the features to be enabled. In doing so, it does enable CORS enforcement.
Cordova android 9.x uses the plain old file system (file://), which didn't enforce CORs. This is why you see the XHR request work in 9. x but not in 10. x. You can make 10. x behave like 9. x by enabling the AndroidInsecureFileModeEnabled
So if you are using cordova-android#10 just add the following preference at config.xml:
<preference name="AndroidInsecureFileModeEnabled" value="true" />
I had the same problem and it solved it for me. :)
I copied my angular2 folder to a new folder, ran npm I etc. in Angular it runs fine.
I created a Cordova folder in my folder with
cordova create cordova be.volckaertachiel.be "volckaertAchiel"
then:
cd cordova
cordova platform add browser
cordova run browser
rm -r www
cd ..
build it in the corodova folder with:
ng build --target=production --environment=prod --output-path cordova/www/
And then ran it in the browser with Cordova run browser
After I changed my backend(node.js API) to accept port 8000 it ran like it was running in angular2
After this Cordova platform add android and then Cordova build android
it launched the Android SDK, it launched the app, but it has a white screen...
My issue in short: I build my web with Cordova -> runs fine, on android I just get a white screen.
Updated Issue: compiled js files aren't found in android
The issue with not finding the files is fixed by setting from this <base href="/"> to this <base href="./"> it's also explained here: https://github.com/electron/electron/issues/1769
This is solution may be application if you want are running on android 8.0 emulator/device with angular 8.
For android 8.0 emulators, it does not support ES2015 which is ES6.
Go to your angular project
Then edit the target to "es5" in tsconfig.json
Just in case someone else get here with this problem without lucky: in my case, i had to change the script in index.html, removing the scripts wicht type was "module" and removing the attribute "nomodule".
In other words, i changed from this:
<script src="runtime-es2015.js" type="module"></script>
<script src="polyfills-es2015.js" type="module"></script>
<script src="main-es2015.js" type="module"></script>
<script src="runtime-es5.js" nomodule></script>
<script src="polyfills-es5.js" nomodule></script>
<script src="main-es5.js" nomodule></script>
<script src="scripts.js"></script>
To this:
<script src="runtime-es5.js"></script>
<script src="polyfills-es5.js"></script>
<script src="main-es5.js"></script>
<script src="scripts.js"></script>
It looks like it has something to do with what mingliang94 said, but my emulator is android 9.
There are two possibilities for this type of behavior:
1. Splash screen misconfiguration
Check your config.xml and verify that you have:
Configured your splash screen to hide automatically
Specified valid splash screen images.
Here's a sample config for Android that will hide the splash screen after 10 seconds:
<preference name="SplashScreen" value="screen" />
<preference name="SplashScreenDelay" value="10000" />
<platform name="android">
<preference name="android-minSdkVersion" value="16" />
<preference name="android-targetSdkVersion" value="22" />
<allow-intent href="market:*" />
<icon density="ldpi" src="res/icons/android/ldpi.png" />
<icon density="mdpi" src="res/icons/android/mdpi.png" />
<icon density="hdpi" src="res/icons/android/hdpi.png" />
<icon density="xhdpi" src="res/icons/android/xhdpi.png" />
<icon density="xxhdpi" src="res/icons/android/xxhdpi.png" />
<splash density="port-hdpi" src="res/screen/android/splash-port-hdpi.png" />
<splash density="port-ldpi" src="res/screen/android/splash-port-ldpi.png" />
<splash density="port-mdpi" src="res/screen/android/splash-port-mdpi.png" />
<splash density="port-xhdpi" src="res/screen/android/splash-port-xhdpi.png" />
</platform>
2. Index page bug
Check your index.html stored in www. Is it missing? Is it empty? Does it load a white page when you open it in a browser?
If the index.html file is present and loading properly in a web browser then you will need to inspect the app while it's running on your Android device. It's likely throwing a JavaScript error during page load that's preventing anything from being displayed. To do so, follow these steps:
Enable developer mode debugging on your Android.
Connect your device to your computer via USB.
Compile the app for debug and run it on your Android device: cordova run android --debug --target=YOURDEVICEIDHERE
Open up Chrome on your desktop and navigate to chrome://inspect
You can live inspect your app just like you would a regular web page. Hitting the refresh button will re-run the initial load and allow you to log any errors.
The app gets json data from a php script on some server. it workes fine on my laptop, but does not work on the android phone.
I have this in my config.xml file
<access origin="*"/>
<allow-intent href="*"/>
<allow-navigation href="*"/>
It looks like the whitelist does not work.. What am i doing wrong?
Firstly remove whitelist plugin by cordova plugin remove cordova-plugin-whitelist, then install by cordova plugin add cordova-plugin-whitelist. Finally, add these tag in your index.html file
<meta http-equiv="Content-Security-Policy" content="default-src *; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'">
A while ago cordova changed to a more restrictive whitelisting method.
Since then you need to install cordova-plugin-whitelist to be able to access external resources.
The fact that things are working on your labtop and not on the mobile points in this direction as well.
I am trying to integrate google recaptcha with cordova html5 application. But cordova uses file protocol in the application. So using captcha in the app gives "Error: invalid domain for site key".
I am using cordova 3.5.0 for building the application and <access origin="*" /> is added in config.xml.
Is recaptcha can be used only for web applications and not for hybrid/native aapplications?
I successfully made it working by using cordova-plugin-ionic-webview
Note that my project was not a Ionic project, so any cordova project can use it
What I did :
Configure Re-Captcha admin console to allow myapp.local domain
Configure cordova-plugin-ionic-webview preferences :
Add a <preference name="Hostname" value="myapp.local" /> in config.xml file
Add a <allow-navigation href="https://www.google.com/recaptcha/*" /> in config.xml file
Add a <allow-navigation href="http://myapp.local/*" /> in android's specific section in config.xml file
Install ionic webview plugin : cordova plugin add cordova-plugin-ionic-webview#4.1.3
Add recaptcha (v3 in my case) to your index.html file : <script type="text/javascript" src="https://www.google.com/recaptcha/api.js?render=MY_RECAPTCHA_KEY_HERE"></script>
Call recaptcha API in your JS code :
grecaptcha.ready(function() {
grecaptcha.execute("MY_RECAPTCHA_KEY_HERE", {action: 'my-page'}).then(function(token) {
console.log("Acquired recaptcha token : ", token);
}, function() {
console.error("ReCaptcha token acquisition failed", arguments);
});
});
reCaptcha cannot be used directly in a cordova project because of protocol issues. Either
-we have to load reCaptcha url in a separate webview
-Use secure token way of loading reCaptcha that they introduced recently (https://developers.google.com/recaptcha/docs/secure_token)
You should now use your App package name (November 2017). As part of your reCaptcha configuration you specify the domains or mobile package names that will use the service. If you use "localhost" for development, you must add it to the list of domains.
For mobile users, the API key pair is only unique to the specified package names (for example, com.google.recaptcha.test).
However, if your domain or package name list is extremely long, fluid, or unknown, you have the option to turn off the domain or package name checking on reCAPTCHA's end, and instead check on your server.
Use of secure tokens is not advised as this is now a depricated feature.
Reference:
Domain/Package Name Validation
I am new to Ionic.
I am using Ionic Framework (1.3.20), Angular JS, Cordova 5.0.0
Template file browse.html code:
<div class="col-50"><img ng-src="{{availableImages[currentImage].src}}" /></div>
app.js code:
.state('app.browse', {
url: "/browse",
views: {
'menuContent': {
templateUrl: "templates/browse.html",
controller: 'Ctrl'
}
}
})
controller.js code
.controller('Ctrl',function($scope) {
$scope.currentImage = 0;
$scope.availableImages = [
{
src: "http://lorempixel.com/160/160/people/3"
}
];
console.log("reading image in controller !!!");
})
Header details:
Request URL:http://lorempixel.com/160/160/people/3
Request Method:GET
Status Code:404 Not Found (from cache)
Response Headers
Client-Via:shouldInterceptRequest
Request Headers
Provisional headers are shown
Accept:image/webp,*/*;q=0.8
User-Agent:Mozilla/5.0 (Linux; Android 5.0.2; XT1033 Build/LXB22.46-28; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/42.0.2311.129 Mobile Safari/537.36
Config.xml file:
<access origin="*"/>
Error on console:
GET http://lorempixel.com/160/160/people/3 404 (Not Found)
I verified the url http://lorempixel.com/160/160/people/3 is showing image in my mobile browser. but the image is not coming on the app.
Whitelisting the domains using cordova-plugin-whitelist solves the issue.
Add the plugin via CLI:
cordova plugin add cordova-plugin-whitelist
and then add the following line of code to your app's config.xml:
<allow-navigation href="http://*/*" />
and
this meta tag in your index.html
<meta http-equiv="Content-Security-Policy" content="default-src *; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'">
EDIT: The reason for this issue:
From Cordova 4.0.0 for Android's update:
Whitelist functionality is revamped
You will need to add the new cordova-plugin-whitelist plugin to continue using a whitelist
Setting a Content-Security-Policy (CSP) is now supported and is the recommended way to whitelist (see details in plugin readme)
Network requests are blocked by default without the plugin, so install this plugin even to allow all requests, and even if you are
using CSP.
This new whitelist is enhanced to be more secure and configurable, but the Legacy whitelist behaviour is still available via a separate
plugin (not recommended).
Note: while not strictly part of this release, the latest default app
created by cordova-cli will include this plugin by default.
Build this plnkr: http://plnkr.co/edit/GprtU3r8NDgYwO6jGRkp?p=preview
My html file:
<div><img ng-src="{{ availableImages[currentImage].src }}" /></div>
Javascript:
$scope.currentImage = 0;
$scope.availableImages = [{
src: "http://lorempixel.com/160/160/people/3"
}];
It seems that everything is alright...
Tested with angularjs 1.3.15