I'm building an app which will list the nearest product dealers to the users current location.
When testing on my device iPhone 6 & iPhone 4S I can see that my app doesn't have permission to get the location but when I go to settings I can't see my test app listed to grant it that permission.
Is this due to the way the app is installed when "Run" via Appcelerator Studio? How can I grant a test app permission please?
My code is:
function getCurrentPhoneLocation(callback)
{
Titanium.API.info("get phone location " + Ti.Geolocation.locationServicesEnabled);
if(Ti.Geolocation.locationServicesEnabled)
{
Titanium.API.info("GPS permissions: " + Ti.Geolocation.locationServicesAuthorization + " (" + Ti.Geolocation.AUTHORIZATION_ALWAYS + " | " + Ti.Geolocation.AUTHORIZATION_AUTHORIZED + " | " + Ti.Geolocation.AUTHORIZATION_WHEN_IN_USE + ")");
if (Ti.Geolocation.locationServicesAuthorization == Ti.Geolocation.AUTHORIZATION_ALWAYS || Ti.Geolocation.locationServicesAuthorization == Ti.Geolocation.AUTHORIZATION_AUTHORIZED || Ti.Geolocation.locationServicesAuthorization == Ti.Geolocation.AUTHORIZATION_WHEN_IN_USE)
{
Titanium.API.info("Got permissions - lets go!");
Ti.Geolocation.purpose = 'Get current location';
var currentPhoneLocation = {};
Ti.Geolocation.getCurrentPosition(function(e){
Titanium.API.info("from pos: " + JSON.stringify(e));
if(e.success === false) {
Ti.API.error('Error:' + e.error);
alert("Location is currently unavailable");
callback( false );
} else {
currentPhoneLocation.longitude = e.coords.longitude;
currentPhoneLocation.latitude = e.coords.latitude;
Ti.API.info("Returned Cords: " + JSON.stringify(currentPhoneLocation));
callback();
}
});
}
else
{
Titanium.API.info("No APP permission");
Titanium.UI.createAlertDialog({title:'Location Service', message:'Please grant this app permission to get your location.'}).show();
callback( false );
}
}
else
{
Titanium.API.info("No GPS available");
Titanium.UI.createAlertDialog({title:'Location Service', message:'Please turn on your location services.'}).show();
callback( false );
}
}
You can see my trace code is showing that Ti.Geolocation.locationServicesAuthorization is returning '0'.
[INFO] : get phone location true
[INFO] : GPS permissions: 0 (3 | 3 | 4)
[INFO] : No APP permission
[INFO] : Recieved location: false
No matter how you install it, preferences work the same. You still have to authorise it.
However, a lot of things have changed for permissions in the latest release, and I recommend looking at the documentation to set it up properly. You can find an example app on GitHub
Best way to check if it has been granted is through:
Ti.Geolocation.hasLocationPermissions(Ti.Geolocation.AUTHORIZATION_ALWAYS);
Also, I recommend fetching location. The false is actually provided by you. If you granted the app permissions (verified in settings) this should work
Ti.GeoLocation.getCurrentPosition(callback(e){})
Related
Huawei HMS core on my huawei phone do not have defualt permission, I am coding my app using HMS location kit and always got a permission error for Location kit. I followed their development guide to set up the location permission in the Manifest file.
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
And followed their code samples:
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
Log.i(TAG, "sdk < 28 Q");
if (ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
|| ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
String[] strings =
{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION};
ActivityCompat.requestPermissions(this, strings, 1);
}
} else {
if (ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
|| ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED
|| ActivityCompat.checkSelfPermission(this,
"android.permission.ACCESS_BACKGROUND_LOCATION") != PackageManager.PERMISSION_GRANTED) {
String[] strings = {android.Manifest.permission.ACCESS_FINE_LOCATION,
android.Manifest.permission.ACCESS_COARSE_LOCATION,
"android.permission.ACCESS_BACKGROUND_LOCATION"};
ActivityCompat.requestPermissions(this, strings, 2);
}
}
Any advice?
The HMS permission must always be allowed. Otherwise, an error will be reported.
Ensure that the location permission has been assigned to HMS Core (APK). To do so, go to Settings > Apps > Apps and find HMS Core. (The menu path may vary depending on the operating system version. If HMS Core is not found, tap the menu icon in the upper right corner of Apps and tap Show system processes.) Then, tap the HMS Core (APK) icon, go to App info > Permissions > Location, and verify that the location permission is assigned to HMS Core. On a device running EMUI 10.0 or later, Location must be set to Always for HMS Core.
Ensure that the Location Info switch in the drop-down notification bar is turned on.
Simulate Location Requires Impersonation Permission. Otherwise, an error permission error will be reported.
Check whether Location Permission is enabled for your app.
Shirley's answer covers the device side of HMS location permission. To cover this type of scenario for all users with lower EMUI versions that HMS Core does not have location permissions by default, you can use the API "settingsClient.checkLocationSettings(…)" to obtain the device location permission. After that, even the location permission for the HMS Core App was disabled, your app will be able to prompt users to enable related permissions with one-click.
Please refer to HMS Location guide
Step 1: Obtain the service API of SettingsClient.
SettingsClient settingsClient = LocationServices.getSettingsClient(this);
Step 2: Call checkLocationSettings() to check the device settings.
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
mLocationRequest = new LocationRequest();
builder.addLocationRequest(mLocationRequest);
LocationSettingsRequest locationSettingsRequest = builder.build();
//check Location Settings
settingsClient.checkLocationSettings(locationSettingsRequest)
.addOnSuccessListener(new OnSuccessListener<LocationSettingsResponse>() {
#Override
public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
//Have permissions, send requests
fusedLocationProviderClient
.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.getMainLooper())
.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
//Interface call successfully processed
}
});
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(Exception e) {
//Settings do not meet targeting criteria
int statusCode = ((ApiException) e).getStatusCode();
switch (statusCode) {
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
try {
ResolvableApiException rae = (ResolvableApiException) e;
//Calling startResolutionForResult can pop up a window to prompt the user to open the corresponding permissions
rae.startResolutionForResult(MainActivity.this, 0);
} catch (IntentSender.SendIntentException sie) {
//…
}
break;
}
}
});
I really don't get it. I have the following code in a Meteor (v1.3.3, MongoDb v2.6.7) app running on my iPhone, and it does not always work. Sometimes it does, and other times it doesn't:
Places = new Mongo.Collection("places");
if(Meteor.isServer) {
Places._ensureIndex({'loc':'2dsphere', name: 1});
}
if(Meteor.isClient) {
var maxDistance = 50;
...
latLng = Geolocation.latLng();
if (! latLng)
{
console.warn('Could not get location!');
return;
}
console.log('location: ' + latLng.lat + ' (' + typeof latLng.lat + '), ' + latLng.lng + ' (' + typeof latLng.lng + ')');
var placeNearby = Places.findOne({
loc: {
$near: {
$geometry: {
type: "Point",
coordinates: [latLng.lng, latLng.lat]
},
$maxDistance: maxDistance //meters
}
}
});
...
}
After I fetch placeNearby, I do a console.log('placeNearby', placeNearby). There are times when it does find a place and some other times it does not.
I am running this on my iPhone 5s (iOS 9) though Xcode:
meteor run ios-device --mobile-server http://10.0.1.10:3000
I am always at the same place when I test this. I thought it might be because of GPS coordinates imprecision, so I increased maxDistance to 50000, but it did not change anything. The funny thing is that my console.log does not output undefined for placeNearby. It seems to be outputting an empty string.
However, if I enter the following query in MongoDb terminal, it retrieves some results:
db.places.find({
loc: {
$near: {
$geometry: {
type: "Point",
coordinates: [-73.56737205923496, 45.50178023952462]
},
$maxDistance: 50 //meters
}
}
})
It was a stupid error. I had forgotten that I had turned off wifi on the iPhone, so it was not able to communicate with the local server. This being said, I would not have thought that a connection with the server was necessary. I thought all the data was being copied to the minimongo database on the client side, and that the app could run independently.
I am wondering now if there is a way to publish a Meteor app that can run locally on the device all by itself. I read a bit about GroudDB, but was not able to find any documentation about geometry queries using $near with GroundDB.
I am building a food delivery app using Ionic. And I am having problems getting the app to work on mobile for the address creation step. After creating an account the user must create a delivery address, at which point the app figures out what delivery location to use.
Address creation works in Chrome (ionic serve) and in iOS simulator (ionic run ios -l -c -s).
However, once I've uploaded the app to my Ionic View iOS app for testing, it gets stuck at the Address creation step.
But at the address creation step, the Ionic loading wheel starts but it doesn't go away and there is no state transition to the menu.
Here is the implementation in the controller.
Address.create($scope.newAddress, $scope.user)
.then(function(response) { // never gets a response back in Ionic View
console.log("address created");
user.save(null,
{ success: function(user) {
// success callback
}, error: function(error) {
// throw error
}
});
}, function(error) {
// throw error
});
The Address.create() method I have implemented is fairly lengthy:
...
.factory('Address', ['$http', '$q', 'PARSE_HEADERS'
function ($http, $q, PARSE_HEADERS) {
return {
create: function(data, userID) {
var deferred = $q.defer();
var zipArray = ['1111','22222','33333'];
var inZone = false;
var restaurantCoords = {
latitude: 11.11111, longitude: 22.22222
};
for (var i=0, bLen=zipBrooklyn.length; i<bLen; i++) {
if(data.zipCode==zipArray[i]) {
inZone = true;
}
}
if (inZone == true ) { // valid zip
function onSuccess(coords) {
var limit = 3041.66;
var meters = getDistance(coords, restaurantCoords);
if (meters < limit) {
$http.post('https://api.parse.com/1/classes/Address', data, {
headers: PARSE_HEADERS
})
.success(function(addressData) {
deferred.resolve(addressData);
})
.error(function(error, addressData) {
deferred.reject(error);
});
}
function onError() {
deferred.reject("Unable to Geocode the coordinates");
}
// GET COORDS
navigator.geocoder.geocodeString(onSuccess, onError, data.address1 + ',' + data.zipCode);
}
}
return deferred.promise;
}]);
I've stripped out all of the code that I believe was working.
So a valid answer for this question could take multiple forms:
I'd accept an answer giving a decent way to debug apps IN Ionic View.
Or, if someone could provide an answer as to why it might be working in the browser and in iOS Simulator, but not iOS itself, that would be appreciated even more.
Ionic view doesn't support all the plugins yet. please take a look at this link for the list of supported plugins.
Device is always better (First Option). If you have a ios device and apple developer account. You can create and configure the required certificate with the device id and run the app using 'ionic run ios'. Second option is iOS simulator. You can use the simulator for your whole app, though few tasks would need a device.
Even if you use the simulator for the whole development, it is always advisable to test in the device before launcing the app.
Goal of the app: get geolocation on each move and log location either when app is in foreground and background.
I've tried so many code and combination but I can't manage to have it working (2 days from now...).
The classic geolocation (getCurrentPosition) is working fine but when we close the app the background geolocation is launched but nothing happen... Function "callbackFn" is never fired.
I'm testing on IOS with xcode > Capabilities Audio & location activated for background activity. I also made working the jQuery sample example given in plugin so I saw it working but never with ionic/angularjs.
Here is the current controller handling the background:
.controller('TestCtrl', function($scope, $timeout, $cordovaBackgroundGeolocation, $ionicPlatform, $window)
{
$scope.lat_geo = "loading lat...";
$scope.long_geo = "loading long...";
//-- Geolocal launch
var options = {
enableHighAccuracy : false,
desiredAccuracy: 0,
stationaryRadius: 1,
distanceFilter: 5,
notificationTitle: 'Background tracking', // <-- android only, customize the title of the notification
notificationText: 'ENABLED', // <-- android only, customize the text of the notification
activityType: 'AutomotiveNavigation',
debug: true, // <-- enable this hear sounds for background-geolocation life-cycle.
stopOnTerminate: false // <-- enable this to clear background location settings when the app terminates
};
$ionicPlatform.ready(function()
{
console.log("[IONIC PLATFORM IS NOW READY]");
//-- First launch a basic geolocalisation to get user acceptance of geosharing ;)
navigator.geolocation.getCurrentPosition(function(location) {
console.log('[GEOLOCAL JS1] Location from Phonegap');
},
function (error){
console.log('[GEOLOCAL JS1] error with GPS: error.code: ' + error.code + ' Message: ' + error.message);
},options);
//-- test adaptation depuis l'app jquery
var callbackFn = function(location) {
console.log('[BackgroundGeoLocation] Update callback: ' + location.latitude + ',' + location.longitude);
};
var failureFn = function(error) {
console.log('[BackgroundGeoLocation] Error: '+error);
};
$cordovaBackgroundGeolocation.configure(callbackFn, failureFn, options);
// Turn ON the background-geolocation system. The user will be tracked whenever they suspend the app.
$cordovaBackgroundGeolocation.start();
//-- Just a timeout to retreive long / lat
$timeout(function()
{
navigator.geolocation.getCurrentPosition(function(location)
{
console.log('[GEOLOCAL JS3] Location from Phonegap');
startPos = location;
$scope.$apply(function () {
$scope.lat_geo = startPos.coords.latitude;
$scope.long_geo = startPos.coords.longitude;
});
console.log("[GEOLOCAL BASIC] OK this time :)");
},
function (error){
console.log('[GEOLOCAL JS3] error with GPS: error.code: ' + error.code + ' Message: ' + error.message);
},options);
}, 3000);
});
//-- End Geolocal
})
I've put all my code (a complete ionic app starter) on github: https://github.com/Jeff86/ionic_ngcordova_backgroundgeo_test/tree/master
I read this article http://ngcordova.com/docs/plugins/backgroundGeolocation/
I see that you should put your code into
document.addEventListener("deviceready", function () { ... });
Do you find any solution?
You definitely don't want to use the std Cordova-geolocation plugin in the bg, it'll kill the battery in no time.
I'm the author of the underlying background-geolocation plugin for Ionic. I've created a New Ionic-based SampleApp.
https://github.com/transistorsoft/cordova-background-geolocation-SampleApp
I'm developing cross platform applications. I'm able to request access to location using the Phone Gap API. If the user clicks okay, then I'm able to get the latitude and longitude using PhoneGap API and send it to the server.
However, I'm facing issues if the user clicks "Don't Allow" initially. After that, if he tries to refresh page, I want the device to show the popup again to request access to the location.
How do we do that in Single Page Applications?
var loadPanelMessage = ko.observable("Sipping..."),
loadPanelVisible = ko.observable(false),
lat = ko.observable(''),
lon = ko.observable('');
navigator.geolocation.getCurrentPosition(onSuccess, onError);
var onSuccess = function (position) {
lat(position.coords.latitude);
lon(position.coords.longitude);
timestamp(position.timestamp);
};
function onError(error) {
alert('code: ' + error.code + '\n' +
'message: ' + error.message + '\n');
//How should I handle the error, so that it asks for Geolocation again?
}
You cannot reshow that popup, it is shown by iOS and once user click's "Don't Allow" you cannot force that popup. All you can do is to let your user know about the situation and direct the user to iOS settings to enable location services for your app.
Here is a nice read about the problem:
https://medium.com/on-startups/96fa4eb54f2c
Based on the cordova plugins here org.apache.cordova.geolocation
All you need to do is a watchPosition to check the PositionError, and use also the cordova-plugin-dialogs to show the native notification
navigator.geolocation.watchPosition((function(_this) {
return function(position) {
// Do something here
};
})(this), function(error) {
var errorButton, errorMsg, errorTitle;
errorTitle = "Location Services";
errorButton = "Ok";
if (error.code === 1) {
errorMsg = "\"AppName\" needs access to your location. Please turn on Location Services in your device settings.";
}
if (error.code === 2) {
errorMsg = "This device is unable to retrieve a position. Make sure you are connected to a network";
}
if (error.code === 3) {
errorMsg = "This device is unable to retrieve a position. Make sure you have Location Services enabled for \"AppName\"";
}
if (error.code === 1 || error.code === 2 || error.code === 3) {
return navigator.notification.alert(errorMsg, errorDismissed(), errorTitle, errorButton);
}
}, {
enableHighAccuracy: true,
maximumAge: 20000,
timeout: 10000
});