I am new in developing on PhoneGap Build. While testing some basic app functionalities I experience a timeout problem when doing a simple geolocation request on my Iphone 6 / IOS 10 / PhoneGap Build 6.3.0.
After re-installing the app I start it and initiate the geolocation by onclick -> geolocation().
Only when I turn the app to the background, I receive the IOS request to allow the location request (should come when I first do the onclick -> geolocation while having the app in the foreground).
Sometimes I get a geolocation result after a long time, sometimes not. I've tried all possible combinations on the three PositionOptions.
When I ask the Google Maps app it shows me the location immediately.
Any idea what I am doing wrong?
Thank you, Kim
function do_geolocation(){
alert('do geoloc');
navigator.geolocation.getCurrentPosition(geo_onSuccess, geo_onError, {maximumAge:120000, enableHighAccuracy:false} );
}
onclick=do_geolocation();
function geo_onSuccess(position){
alert('Latitude: ' + position.coords.latitude + '\n' +
'Longitude: ' + position.coords.longitude + '\n' +
'Altitude: ' + position.coords.altitude + '\n' +
'Accuracy: ' + position.coords.accuracy + '\n' +
'Altitude Accuracy: ' + position.coords.altitudeAccuracy + '\n' +
'Heading: ' + position.coords.heading + '\n' +
'Speed: ' + position.coords.speed + '\n' +
'Timestamp: ' + position.timestamp + '\n');
var arr = new Array();
arr['lat'] = position.coords.latitude;
arr['lng'] = position.coords.longitude;
var x = new Date();var cb = x.getTime();
}
function geo_onError(position){
alert('code: '+error.code+'\nmessage: '+error.message+'\n');
return false;
}
<?xml version="1.0" encoding="UTF-8" ?>
<widget xmlns = "http://www.w3.org/ns/widgets"
xmlns:gap = "http://phonegap.com/ns/1.0"
id = "de.vvvvvv.secapp"
versionCode = "10"
version = "1.0.0" >
<!-- versionCode is optional and Android only -->
<name>vvvvvvv</name>
<description>
vvvvvvvvvvvv
</description>
<author href="http://vvvvvvv.de" email="info#vvvvvv.de">
Kim
</author>
<plugin name="cordova-plugin-geolocation" spec="2.4.1" />
<plugin name="cordova-plugin-whitelist" spec="1.3.1" />
<access origin="*"/>
<allow-intent href="http://*/*"/>
<allow-intent href="https://*/*"/>
<preference name="orientation" value="portrait" />
<!-- https://makeappicon.com/ios10icon -->
<icon src="res/icons/ios/Icon-App-20x20#2x.png" platform="ios" width="20" height="20" />
<icon src="res/icons/ios/Icon-App-20x20#3x.png" platform="ios" width="40" height="40" />
...
Only when I turn the app to the background, I receive the IOS request to allow the location request (should come when I first do the onclick -> geolocation while having the app in the foreground).
The activation only on backgrounding the app sounds sympomatic of a Content-Security-Policy issue (here's another example).
To resolve, ensure that your Content-Security-Policy meta tag contains gap://ready and file: entries for default-src. For example:
<meta http-equiv="Content-Security-Policy" content="default-src * gap://ready file:; style-src 'self' 'unsafe-inline'; img-src 'self' data:; script-src * 'unsafe-inline' 'unsafe-eval'">
Sometimes I get a geolocation result after a long time, sometimes not. I've tried all possible combinations on the three PositionOptions.
Setting maximumAge to 120000 means a position up to 2 minutes old (cached by the OS) can be used. To force a fresh position, set it to zero:
{
enableHighAccuracy: false
maximumAge: 0,
timeout: 2000
}
If setting enableHighAccuracy to true, this engages GPS hardware to get a lock, so set a sufficient timeout to allow it to lock enough satellites:
{
enableHighAccuracy: true
maximumAge: 0,
timeout: 30000
}
For a full explanation of PositionOptions, see the Mozilla docs
Related
The code I have used to work on both Android and IOS, until I had to make the IOS version on ionic use WKWebViewOnly.
This is the code that was working on IOS (still works on Android):
var type = window.PERSISTENT;
var size = 50*1024*1024; // 50MB
window.requestFileSystem(type, size, successCallback, errorCallback);
function successCallback(fs) {
window.resolveLocalFileSystemURL(app.folder, function(dirEntry) {
dirEntry.getFile(mix_name, {create: true}, function(fileEntry) {
fileEntry.createWriter(function(fileWriter) {
fileWriter.onwriteend = function(e) {
alert('Write success');
};
fileWriter.onerror = function(e) {
alert('Write failed: ' + e.toString());
};
var oReq = new XMLHttpRequest();
// Make sure you add the domain name to the Content-Security-Policy <meta> element.
oReq.open("GET", "https://domain-to-get-file.com/path/to/file.mp3", true);
// Define how you want the XHR data to come back
oReq.responseType = "blob";
oReq.onload = function (oEvent) {
var blob = oReq.response; // Note: not oReq.responseText
blob = blobToFile(blob, fileName);
fileWriter.write(blob);
};
oReq.send(null);
}, errorCallback);
}, errorCallback);
}, errorCallback);
}
function errorCallback(error) {
alert("ERROR: " + error.code)
}
function blobToFile(theBlob, fileName) {
// A Blob() is almost a File() - it's just missing the two properties below which we will add
theBlob.lastModifiedDate = new Date();
theBlob.name = fileName;
return theBlob;
}
In my index.html I have the meta tag:
<meta http-equiv="Content-Security-Policy" content="
default-src * data: cdvfile: gap: blob:;
script-src 'self' 'unsafe-inline' *.domain-to-get-file.com;
style-src 'self' 'unsafe-inline';">
And the plugins I have used are:
<plugin name="cordova-plugin-wkwebview-engine" source="npm" />
<plugin name="cordova-plugin-wkwebview-file-xhr" spec="~2.1.4" />
Works fine on Android but not on IOS 13.
I think i'm missing a security thing, but I have no idea how to fix that.
Thanks :)
This was a miss leading issue, but for anyone stumbling upon it.
The fix was to switch from using XMLHttpRequest to Fetch: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
I had no clue about Fetch until I saw this video: https://www.youtube.com/watch?v=tc8DU14qX6I&list=PLRqwX-V7Uu6YxDKpFzf_2D84p0cyk4T7X
and you will also need this: https://www.youtube.com/watch?v=zswi0cPMxsU to solve the CORS issue
I also did removed the plugins:
<plugin name="cordova-plugin-wkwebview-engine" source="npm" />
<plugin name="cordova-plugin-wkwebview-file-xhr" spec="~2.1.4" />
and adding this all-in-one plugin seemed to fix the issue.
https://www.npmjs.com/package/cordova-plugin-wkwebview-ionic-xhr
Added these two preferences in the ios platform in config.xml
<preference name="allowFileAccessFromFileURLs" value="true" />
<preference name="allowUniversalAccessFromFileURLs" value="true" />
I created an iOS (iPhone) App using Cordova and want to only allow the following orientations:
Portrait
Landscape Left
Landscape Right
This also means that "upside down" should not be allowed:
I know that I can set this in Xcode but when ever I start a new Cordova build this setting gets overwritten.
So I checked Cordova docs and found this: http://cordova.apache.org/docs/en/5.1.1/config_ref_index.md.html#The%20config.xml%20File
It says that I can set orientation in config.xml like this:
<preference name="Orientation" value="landscape" />
But I don't see how I can set a more fine granular setting as I described above. How can this be done?
Note: I am on Cordova 5.1.1
You can use config.xml'
<platform name="ios">
<preference name="Orientation" value="all" />
</platform>
along with shouldRotateToOrientation(degrees) callback as stated in the docs like this:
onDeviceReady: function() {
app.receivedEvent('deviceready');
window.shouldRotateToOrientation = function(degrees) {
return degrees !== 180;
};
},
You can use an after_prepare hook which will apply the settings after the cordova prepare and therefore avoid them getting overwritten on each cordova build. Place the following code in <your_project>/hooks/after_prepare/some_file.js:
#!/usr/bin/env node
// Set support for all orienations in iOS .plist - workaround for this cordova bug: https://issues.apache.org/jira/browse/CB-8953
var platforms = process.env.CORDOVA_PLATFORMS.split(',');
platforms.forEach(function(p) {
if (p == "ios") {
var fs = require('fs'),
plist = require('plist'),
xmlParser = new require('xml2js').Parser(),
plistPath = '',
configPath = 'config.xml';
// Construct plist path.
if (fs.existsSync(configPath)) {
var configContent = fs.readFileSync(configPath);
// Callback is synchronous.
xmlParser.parseString(configContent, function (err, result) {
var name = result.widget.name;
plistPath = 'platforms/ios/' + name + '/' + name + '-Info.plist';
});
}
// Change plist and write.
if (fs.existsSync(plistPath)) {
var pl = plist.parseFileSync(plistPath);
configure(pl);
fs.writeFileSync(plistPath, plist.build(pl).toString());
}
process.exit();
}
});
function configure(plist) {
var iPhoneOrientations = [
'UIInterfaceOrientationLandscapeLeft',
'UIInterfaceOrientationLandscapeRight',
'UIInterfaceOrientationPortrait'
];
var iPadOrientations = [
'UIInterfaceOrientationLandscapeLeft',
'UIInterfaceOrientationLandscapeRight',
'UIInterfaceOrientationPortrait'
];
plist["UISupportedInterfaceOrientations"] = iPhoneOrientations;
plist["UISupportedInterfaceOrientations~ipad"] = iPadOrientations;
}
Note: you'll need to install the plist and xml2js node modules if you don't already have them.
I'm new to android, so this might be prety basic.
I'm trying to write data into a file, yet I can not find the file in the device.
I'm trying to get the file in the following directory:
"Computer\Nexus 5\Internal storage\Android\data\application name"
I have tried different method but none of them has worked:
FileOutputStream stream;
try {
stream = openFileOutput(filename,Context.MODE_APPEND | Context.MODE_WORLD_READABLE);
stream.write(string.getBytes());
stream.close();
}catch(IOException e){
}}
and
String path = Environment.getExternalStorageDirectory().getAbsolutePath()+"/Android/data/" + packageName + "/files/";
try {
boolean exists = (new File(path )).exists();
if (!exists) {
new File(path ).mkdirs();
}
// Open output stream
FileOutputStream fOut = new FileOutputStream(path + filename,true);
// write integers as separated ascii's
fOut.write((Integer.valueOf(content).toString() + " ").getBytes());
// Close output stream
fOut.flush();
fOut.close();
} catch (IOException e) {
e.printStackTrace();
}
I have added the permission in the manifest :
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.proLeague"
android:versionCode="1"
android:versionName="1.0" >
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE"/>
<group gid="sdcard_rw" />
<group gid="media_rw" />
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="21" />
<application
android:allowBackup="true"
android:debuggable= "true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
I thought maybe the file is logged properly but I need to pull it out from the ADB, is that possible?
I had manage to solve my issues on my own :
Evantually the code was fine, the problem was that on my nexus 5 phone I need to reboot the phone before I search for new files in the flash storage.
I saw in some blogs it is pretty common.
im trying to use the generic push for my app. it works on android but on ios i get the error msg: no valid aps-environment
i have added support to push notifications in apple provisioning
profile
i created and downloaded the provisioning profile after enabling the push
i have <key>aps-environment</key> in mobileprovision
i have installed the mobile provision and app on my phone
i have checked and tested every solution
my config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<widget xmlns = "http://www.w3.org/ns/widgets"
xmlns:gap = "http://phonegap.com/ns/1.0"
id = "---.-------.-----"
versionCode="10"
version = "1.1.0">
<!-- versionCode is optional and Android only -->
<name>PhoneGap push Example</name>
<description>
An example for phonegap build docs.
</description>
<author href="http://-----------" email="---------------">------</author>
<access origin="*" />
<!--DEVICE FEATURES ACCESS-->
<feature name="http://api.phonegap.com/1.0/camera"/>
<feature name="http://api.phonegap.com/1.0/file"/>
<feature name="http://api.phonegap.com/1.0/geolocation"/>
<feature name="http://api.phonegap.com/1.0/media"/>
<feature name="http://api.phonegap.com/1.0/network"/>
<feature name="http://api.phonegap.com/1.0/notification"/>
<gap:plugin name="GenericPush" /> <!-- latest release -->
</widget>
my js
<script type="text/javascript" charset="utf-8" src="phonegap.js"></script>
<script type="text/javascript" charset="utf-8" src="jquery_1.5.2.min.js"></script>
<script type="text/javascript" src="PushNotification.js"></script>
<script type="text/javascript">
var pushNotification;
function onDeviceReady() {
$("#app-status-ul").append('<li>deviceready event received</li>');
pushNotification = window.plugins.pushNotification;
if (device.platform == 'android' || device.platform == 'Android') {
pushNotification.register(successHandler, errorHandler, {"senderID":"661780372179","ecb":"onNotificationGCM"});
} else {
pushNotification.register(tokenHandler, errorHandler, {"badge":"true","sound":"true","alert":"true","ecb":"onNotificationAPN"});
}
}
// handle APNS notifications for iOS
function onNotificationAPN(event) {
if (event.alert) {
$("#app-status-ul").append('<li>push-notification: ' + event.alert + '</li>');
navigator.notification.alert(event.alert);
}
if (event.sound) {
var snd = new Media(event.sound);
snd.play();
}
if (event.badge) {
pushNotification.setApplicationIconBadgeNumber(successHandler, event.badge);
}
}
// handle GCM notifications for Android
function onNotificationGCM(e) {
$("#app-status-ul").append('<li>EVENT -> RECEIVED:' + e.event + '</li>');
switch( e.event )
{
case 'registered':
if ( e.regid.length > 0 )
{
$("#app-status-ul").append('<li>REGISTERED -> REGID:' + e.regid + "</li>");
// Your GCM push server needs to know the regID before it can push to this device
// here is where you might want to send it the regID for later use.
console.log("regID = " + regID);
}
break;
case 'message':
$("#app-status-ul").append('<li>MESSAGE -> MSG: ' + e.message + '</li>');
$("#app-status-ul").append('<li>MESSAGE -> MSGCNT: ' + e.msgcnt + '</li>');
break;
case 'error':
$("#app-status-ul").append('<li>ERROR -> MSG:' + e.msg + '</li>');
break;
default:
$("#app-status-ul").append('<li>EVENT -> Unknown, an event was received and we do not know what it is</li>');
break;
}
}
function tokenHandler (result) {
$("#app-status-ul").append('<li>token: '+ result +'</li>');
// Your iOS push server needs to know the token before it can push to this device
// here is where you might want to send it the token for later use.
}
function successHandler (result) {
$("#app-status-ul").append('<li>success:'+ result +'</li>');
}
function errorHandler (error) {
$("#app-status-ul").append('<li>error:'+ error +'</li>');
}
document.addEventListener('deviceready', onDeviceReady, true);
</script>
<div id="app-status-div">
<ul id="app-status-ul">
<li>Cordova PushNotification Plugin Demo</li>
</ul>
</div>
According to the Phonegap Build community forums, you need to use a distribution provision certificate for the APS registration to work : http://community.phonegap.com/nitobi/topics/ios_problem_with_push_notification_plugin_for_phonegap_build
Some people have succeeded after switching to production certificates.
However, I have the same problem and still cannot get it working with production certificates.
after long research and trial and error. i found out that i need to use:
on IOS (adhoc provision profile) and on push server(production aps cert and key)
I have used "Android Cloud to Device Messaging (C2DM) - Tutorial" by Lars Vogel.
When i start my applcation, registration response never received.
How It can be solved?
my Manifest file:
<?xml version="1.0" encoding="utf-8"?>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<application android:icon="#drawable/appicon" android:label="#string/app_name" android:debuggable="true">
<activity android:name=".activities.MainActivity"
android:label="#string/app_name"
android:theme="#android:style/Theme.NoTitleBar.Fullscreen"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".ui.DailyTripList" android:screenOrientation="portrait" />
<activity android:name=".ui.TripActivity" android:screenOrientation="portrait" />
<activity android:name=".ui.StationsList" android:screenOrientation="portrait" />
<activity android:name=".ui.StationActivity" android:screenOrientation="portrait" />
<activity android:name=".ui.PassengerList" android:screenOrientation="portrait" />
<activity android:name=".ui.DriverMsgList" android:screenOrientation="portrait" />
<service android:name=".services.SecurityReqestTransmitter" android:exported="false"/>
<service android:name=".services.LocationTransmitter" android:exported="false"/>
<activity android:name=".cardReader.IDTUniMagActivity" android:screenOrientation="portrait" />
<receiver android:name="com.google.android.c2dm.C2DMBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND">
<!-- Receive the actual message -->
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="com.em_projects.MyWay.receivers" />
</intent-filter>
<!-- Receive the registration id -->
<intent-filter>
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="com.em_projects.MyWay.receivers" />
</intent-filter>
</receiver>
</application>
CatLog
08-15 23:57:41.624: WARN/KeyCharacterMap(959): No keyboard for id 0
08-15 23:57:41.634: WARN/KeyCharacterMap(959): Using default keymap: /system/usr/keychars/qwerty.kcm.bin
08-15 23:57:44.645: DEBUG/dalvikvm(150): GC_EXTERNAL_ALLOC freed 698 objects / 37712 bytes in 273ms
08-15 23:58:01.374: DEBUG/SntpClient(70): request time failed: java.net.SocketException: Address family not supported by protocol
08-15 23:58:17.365: INFO/EventLogService(236): Aggregate from 1313450896472 (log), 1313450896472 (data)
08-15 23:58:22.704: DEBUG/dalvikvm(236): GC_EXPLICIT freed 473 objects / 120056 bytes in 276ms
08-15 23:58:29.744: DEBUG/dalvikvm(150): GC_EXTERNAL_ALLOC freed 611 objects / 29936 bytes in 198ms
08-15 23:58:32.754: DEBUG/MainActivity(959): onClick
08-15 23:58:33.944: INFO/global(959): Default buffer size used in BufferedReader constructor. It would be better to be explicit if an 8k-char buffer is required.
08-15 23:58:33.974: DEBUG/Communicator(959): # parseData <?xml version="1.0" encoding="UTF-8"?><root><row internal_code="644" external_code="1442" ws_string="http://wap.y-it.co.il:8080/wapdb/ws_redirect/http://localhost:8080/fltctrl_11" report_location_period="60" reject_mission="1"/></root>
08-15 23:58:34.124: DEBUG/MainActivity(959): Rows counter = 1
08-15 23:58:34.155: DEBUG/MainActivity(959): handleMessage
08-15 23:58:34.184: INFO/ActivityManager(70): Starting activity: Intent { flg=0x4000000 cmp=com.em_projects.MyWay/.ui.DailyTripList }
08-15 23:58:34.494: DEBUG/DailyTripList(959): onCreate
08-15 23:58:35.444: DEBUG/dalvikvm(959): GC_FOR_MALLOC freed 7436 objects / 493624 bytes in 90ms
08-15 23:58:43.254: ERROR/C2DMRegistrar(236): [C2DMReg] handleRequest caught java.io.IOException: SSL shutdown failed: I/O error during system call, Broken pipe
08-15 23:58:43.534: DEBUG/SecurityReqestTransmitter(959): onCreate
08-15 23:58:43.584: DEBUG/SecurityReqestTransmitter(959): initServiceThread
08-15 23:58:43.624: DEBUG/SecurityReqestTransmitter(959): run
08-15 23:58:43.634: DEBUG/SecurityReqestTransmitter(959): onStartCommand
08-15 23:58:43.875: DEBUG/LocationTransmitter(959): onCreate
08-15 23:58:43.944: DEBUG/LocationTransmitter(959): spd = 0.0
08-15 23:58:44.024: WARN/GpsLocationProvider(70): Duplicate add listener for uid 10040
08-15 23:58:44.224: WARN/ActivityManager(70): Launch timeout has expired, giving up wake lock!
08-15 23:58:44.414: INFO/global(959): Default buffer size used in BufferedReader constructor. It would be better to be explicit if an 8k-char buffer is required.
08-15 23:58:44.454: WARN/ActivityManager(70): Activity idle timeout for HistoryRecord{44ec58c0 com.em_projects.MyWay/.ui.DailyTripList}
08-15 23:58:44.534: DEBUG/Communicator(959): # parseData <?xml version="1.0" encoding="UTF-8"?><root><row line_code="90476" acc_name="אי סי אי" order_start_time="08:00" order_end_time="08:30" line_description="איסוף עובדים איזור הדרום" line_status="-1" t_Pass_QTY="4" Pass_QTY="4" group_name="שם הקבוצה" department_name="שם המחלקה" line_date="2011-08-15" long_remarks="הערות ארוכות...
שורה שניה
שורה שלישית
שורה רביעית
שורה אחרונה !" short_remarks="הערות קצרות של הנסיעה"/><row line_code="90377" acc_name="מפעל תע"ש רכש" order_start_time="12:00" order_end_time="12:45" line_description="מרוחובות+נס ציונה לתע"ש" line_status="-1" t_Pass_QTY="0" Pass_QTY="0" line_date="2011-08-15" long_remarks="" short_remarks=""/><row line_code="90406" acc_name="משתלת ציפורן" order_start_time="15:00" order_end_time="15:40" line_description="הסעות עובדים אמצע שבוע" line_status="5" t_Pass_QTY="0" Pass_QTY="0" department_name="מחלקה 1" line_date="2011-08-15" long_remarks="על הנהג להתקשר לשלמה 050-3344334 בעל המשתלה
כל יום לאחר סיום ההסעה." short_remarks="הערה ליום ב'"/><row line_code="90439" acc_name="טבע כפר סבא" order_start_time="18:00" order_end_time="18:00" line_description="נתב"ג כ"ס" line_status="-1" t_Pass_QTY="0" Pass_QTY="0" line_date="2011-08-15" long_remarks="" short_remarks=""/></root>
08-15 23:58:47.554: INFO/ActivityManager(70): Displayed activity com.em_projects.MyWay/.ui.DailyTripList: 13122 ms (total 13122 ms)
Is your app package name com.em_projects.MyWay.receivers?
If no, try to use only your package name instead of com.em_projects.MyWay.receivers in categories
<receiver android:name="com.google.android.c2dm.C2DMBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND">
<!-- Receive the actual message -->
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="***your_app_package_name***" />
</intent-filter>
<!-- Receive the registration id -->
<intent-filter>
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="***your_app_package_name***" />
</intent-filter>
</receiver>