In iOS8, Apple has changed how geo location permissions work. This gist outlines an approach to fix this so Geo will continue to work in iOS8.
Before getting started with the code change, we need to update the tiapp.xml with a few keys.
If you wish to have Geo always run, you need to add the below key. The key NSLocationAlwaysUsageDescription is used when requesting permission to use location services whenever the app is running. To enable this, add the below to the tiapp.xml:
NSLocationAlwaysUsageDescription Reason that appears in the authorization prompt
If you wish to use Geo when your app is in the foreground, you need to add the below key. The key NSLocationWhenInUseUsageDescription is used when requesting permission to use location services while the app is in the foreground. To enable this, add teh below to the tiapp.xml
NSLocationWhenInUseUsageDescription Reason that appears in the authorization prompt
What happens if I add both NSLocationAlwaysUsageDescription and NSLocationWhenInUseUsageDescription keys to my tiapp.xml? In this case we assume you want the highest level access right and use the NSLocationAlwaysUsageDescription key.
Now to the code changes, first... we need to open GeolocationModule.m
Next we need to add some default behavior to the -(CLLocationManager*)locationManager method.
To do this scroll down to where you see the purpose logic in your method, and replace that block with the one below. This will kill two birds with one stone and remove the purpse section if you are running iOS8. You will notice we will automatically add the correct permission based on their tiapp.xml entries. This makes it easy for backwards compatability.
if ([TiUtils isIOS8OrGreater]) {
if([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"]){
[locationManager requestAlwaysAuthorization];
}else if ([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"]){
[locationManager requestWhenInUseAuthorization];
}else{
NSLog(@"[ERROR] The keys NSLocationAlwaysUsageDescription or NSLocationWhenInUseUsageDescription are not defined in your tiapp.xml. Starting with iOS8 this are required.");
}
}else{
if (purpose==nil)
{
DebugLog(@"[WARN] The Ti.Geolocation.purpose property must be set.");
}
else
{
[locationManager setPurpose:purpose];
}
}
Next we need to add some properties. The developer will be able to use this when checking their permission status. In the GeolocationModule.m file scroll to the property section and add the below.
-(NSNumber*)AUTHORIZATION_ALWAYS
{
if ([TiUtils isIOS8OrGreater]) {
return NUMINT(kCLAuthorizationStatusAuthorizedAlways);
}
return NUMINT(0);
}
-(NSNumber*)AUTHORIZATION_WHEN_IN_USE
{
if ([TiUtils isIOS8OrGreater]) {
return NUMINT(kCLAuthorizationStatusAuthorizedWhenInUse);
}
return NUMINT(0);
}
Finally, we need to listen for the authorization change event. Scroll towards the end of the file and you will see all of the delegate methods. Add the below to this section of your code. This will fire an event off the Ti.Geolocation namespace called authorization.
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
NSDictionary *event = [NSDictionary dictionaryWithObjectsAndKeys:
NUMINT([CLLocationManager authorizationStatus]),@"authorizationStatus",nil];
if ([self _hasListeners:@"authorization"])
{
[self fireEvent:@"authorization" withObject:event];
}
}
Test Plan
How to test:
Testing Geo AlwaysUsage: ++++++++++++++++++++++++
- Using an Ti SDK with this patch applied create a test app ( in classic mode )
- Update the app.js with this sampel https://gist.github.com/benbahrenburg/c4c992c8c61d197510ea#how-to-test-this
- Open the tiapp.xml in the ios / plist / dict section add the below:
<key>NSLocationAlwaysUsageDescription</key> <string>Test NSLocationAlwaysUsageDescription</string>
- Compile and push to your device or the simulator. Please note you must target iOS8.
- Press the btnAuthorization button, you should see a message that says Ti.Geolocation.AUTHORIZATION_UNKNOWN
- Press the btnGeoTest button, you should now see the permission box with the message Test NSLocationAlwaysUsageDescription
- Press the approve button
- You should now see the event below fire
Ti.Geolocation.addEventListener('authorization',function(e){ Ti.API.info('authorization event:' + JSON.stringify(e)); });
- Press the btnAuthorization button, you should now see an alert with Ti.Geolocation.AUTHORIZATION_ALWAYS or Ti.Geolocation.AUTHORIZATION_AUTHORIZED
Testing Geo In Usage Permission: ++++++++++++++++++++++++
- Next reset your simulator or uninstall the app from your device
- Remove the NSLocationAlwaysUsageDescription settings from your tiapp.xml
- Open the tiapp.xml in the ios / plist / dict section add the below:
<key>NSLocationWhenInUseUsageDescription</key> <string>Test NSLocationWhenInUseUsageDescription</string>
- Compile and push to your device or the simulator. Please note you must target iOS8.
- Press the btnAuthorization button, you should see a message that says Ti.Geolocation.AUTHORIZATION_UNKNOWN
- Press the btnGeoTest button, you should now see the permission box with the message Test NSLocationWhenInUseUsageDescription
- Press the approve button
- You should now see the event below fire
Ti.Geolocation.addEventListener('authorization',function(e){ Ti.API.info('authorization event:' + JSON.stringify(e)); });
- Press the btnAuthorization button, you should now see an alert with Ti.Geolocation.AUTHORIZATION_WHEN_IN_USE
- Next reset your simulator or uninstall the app from your device
Testing what happens if you have both NSLocationWhenInUseUsageDescription and NSLocationAlwaysUsageDescription ++++++++++++++++++++++++
- Next reset your simulator or uninstall the app from your device
- Open the tiapp.xml in the ios / plist / dict section add the below:
<key>NSLocationWhenInUseUsageDescription</key> <string>Test NSLocationWhenInUseUsageDescription</string> <key>NSLocationAlwaysUsageDescription</key> <string>Test NSLocationAlwaysUsageDescription</string>
- Compile and push to your device or the simulator. Please note you must target iOS8.
- Press the btnAuthorization button, you should see a message that says Ti.Geolocation.AUTHORIZATION_UNKNOWN
- Press the btnGeoTest button, you should now see the permission box with the message Test NSLocationAlwaysUsageDescription
- Press the approve button
- You should now see the event below fire
Ti.Geolocation.addEventListener('authorization',function(e){ Ti.API.info('authorization event:' + JSON.stringify(e)); });
- Press the btnAuthorization button, you should now see an alert with Ti.Geolocation.AUTHORIZATION_ALWAYS or Ti.Geolocation.AUTHORIZATION_AUTHORIZED
- Next reset your simulator or uninstall the app from your device
Testing iOS7 Support ++++++++++++++++++++++++
- Next reset your simulator or uninstall the app from your device
- Open the tiapp.xml in the ios / plist / dict section add the below:
<key>NSLocationWhenInUseUsageDescription</key> <string>Test NSLocationWhenInUseUsageDescription</string> <key>NSLocationAlwaysUsageDescription</key> <string>Test NSLocationAlwaysUsageDescription</string>
- Compile and push to your device or the simulator. Please note you must target iOS7.
- Press the btnAuthorization button, you should see a message that says Ti.Geolocation.AUTHORIZATION_UNKNOWN
- Press the btnGeoTest button, you should now see the permission box with the text provided as part of the purpose
- Press the approve button
- You should now see the event below fire
Ti.Geolocation.addEventListener('authorization',function(e){ Ti.API.info('authorization event:' + JSON.stringify(e)); });
- Press the btnAuthorization button, you should now see an alert with Ti.Geolocation.AUTHORIZATION_ALWAYS or Ti.Geolocation.AUTHORIZATION_AUTHORIZED
How to test this...
Use the below app.js file.
var win = Titanium.UI.createWindow({ backgroundColor:'#fff',layout:'vertical' }); var btnAuthorization = Titanium.UI.createButton({ title:'Authorization Check', left:25,right:25, top:80 }); win.add(btnAuthorization); var btnGeoTest = Titanium.UI.createButton({ title:'Test Geo', left:25,right:25, top:45 }); win.add(btnGeoTest); Ti.Geolocation.addEventListener('authorization',function(e){ Ti.API.info('authorization event:' + JSON.stringify(e)); }); function printAuthorizedResults(authorization){ Ti.API.info('Authorization: '+authorization); if (authorization == Ti.Geolocation.AUTHORIZATION_UNKNOWN) { return "Authorization = Ti.Geolocation.AUTHORIZATION_UNKNOWN"; } if (authorization == Ti.Geolocation.AUTHORIZATION_DENIED) { return "Authorization = Ti.Geolocation.AUTHORIZATION_DENIED"; } if (authorization == Ti.Geolocation.AUTHORIZATION_RESTRICTED) { return "Authorization = Ti.Geolocation.AUTHORIZATION_DENIED"; } if (authorization == Ti.Geolocation.AUTHORIZATION_AUTHORIZED) { return "Authorization = Ti.Geolocation.AUTHORIZATION_AUTHORIZED"; } if (authorization == Ti.Geolocation.AUTHORIZATION_ALWAYS) { return "Authorization = Ti.Geolocation.AUTHORIZATION_ALWAYS"; } if (authorization == Ti.Geolocation.AUTHORIZATION_WHEN_IN_USE) { return "Authorization = Ti.Geolocation.AUTHORIZATION_WHEN_IN_USE"; } return "Error: No authorization value found"; } btnAuthorization.addEventListener('click',function(d){ alert(printAuthorizedResults(Ti.Geolocation.locationServicesAuthorization)); }); btnGeoTest.addEventListener('click',function(d){ Ti.Geolocation.getCurrentPosition(function(e) { if (!e.success || e.error){ Ti.API.info("Code translation: "+translateErrorCode(e.code)); alert('error ' + JSON.stringify(e.error)); return; } var longitude = e.coords.longitude; var latitude = e.coords.latitude; var altitude = e.coords.altitude; var heading = e.coords.heading; var accuracy = e.coords.accuracy; var speed = e.coords.speed; var timestamp = e.coords.timestamp; var altitudeAccuracy = e.coords.altitudeAccuracy; Ti.API.info('speed ' + speed); Titanium.API.info('geo - current location: ' + new Date(timestamp) + ' long ' + longitude + ' lat ' + latitude + ' accuracy ' + accuracy); }); }); win.open();
感谢原作者 :Ben
原文地址:https://gist.github.com/benbahrenburg/c4c992c8c61d197510ea#how-to-test-this