Skip to content

Instantly share code, notes, and snippets.

@benbahrenburg
Created September 14, 2014 02:29
Embed
What would you like to do?
TC-4715

This gist outlines the approach for adding a method to Geolocation.m to allow developers to request permissions in iOS8.

Before you start there are a few things I need to mention.

  1. Once you ask for a permission, you cannot seem to change it at an app level
  2. The tiapp.xml must have either the NSLocationWhenInUseUsageDescription or NSLocationAlwaysUsageDescription keys when requesting the associated permission

Making the update. Add the below to your 3.4.X branch of the Ti SDK

In Geolocation.h add this under the tempManager line

CLLocationManager *locationPermissionManager; // used for just permissions requests

In Geolocation.m add this under the AUTHORIZATION_WHEN_IN_USE line

First we add the below so we can hook a CLLocationManager for this purpose

-(CLLocationManager*)locationPermissionManager
{
    if (locationPermissionManager!=nil)
    {
        // if we have an instance, just use it
        return locationPermissionManager;
    }

    if (locationPermissionManager == nil) {
        locationPermissionManager = [[CLLocationManager alloc] init];
        locationPermissionManager.delegate = self;
    }
    return locationPermissionManager;
}

Then we we add the method that could be called via the Ti SDK

-(void)requestAuthorization:(id)value
{
    ENSURE_SINGLE_ARG(value,NSNumber);

    if (![TiUtils isIOS8OrGreater]) {
        return;
    }

    int requested = [value integerValue];
    int currentPermissionLevel = [CLLocationManager authorizationStatus];

    if(requested == kCLAuthorizationStatusAuthorizedWhenInUse){
        if ([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"]){
            if((currentPermissionLevel ==kCLAuthorizationStatusAuthorizedAlways) ||
               (currentPermissionLevel ==kCLAuthorizationStatusAuthorized)){
                NSLog(@"[ERROR] cannot change already granted permission from AUTHORIZATION_ALWAYS to AUTHORIZATION_WHEN_IN_USE");
            }else{
                [[self locationPermissionManager] requestWhenInUseAuthorization];
            }
        }else{
            NSLog(@"[ERROR] the NSLocationWhenInUseUsageDescription key must be defined in your tiapp.xml in order to request this permission");
        }
    }
    if((requested == kCLAuthorizationStatusAuthorizedAlways) ||
       (requested == kCLAuthorizationStatusAuthorized)){
        if ([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"]){
            if(currentPermissionLevel == kCLAuthorizationStatusAuthorizedWhenInUse){
                NSLog(@"[ERROR] cannot change already granted permission from AUTHORIZATION_WHEN_IN_USE to AUTHORIZATION_ALWAYS");
            }else{
                [[self locationPermissionManager] requestAlwaysAuthorization];
            }
        }else{
            NSLog(@"[ERROR] the NSLocationAlwaysUsageDescription key must be defined in your tiapp.xml in order to request this permission");
        }
    }
}

You will notice a fare amount of error handling is added. This is due to how Apple handles things.

//This is the app.js you can use for testing
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 btnRequestAlways = Titanium.UI.createButton({
title:'Request Always Run', left:25,right:25, top:45
});
win.add(btnRequestAlways);
var btnRequestInUse = Titanium.UI.createButton({
title:'Request In Use Run', left:25,right:25, top:45
});
win.add(btnRequestInUse);
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));
});
btnRequestAlways.addEventListener('click',function(d){
Ti.API.info('Ti.Geolocation.AUTHORIZATION_ALWAYS =' + Ti.Geolocation.AUTHORIZATION_ALWAYS);
Ti.Geolocation.requestAuthorization(Ti.Geolocation.AUTHORIZATION_ALWAYS);
});
btnRequestInUse.addEventListener('click',function(d){
Ti.API.info('Ti.Geolocation.AUTHORIZATION_WHEN_IN_USE=' + Ti.Geolocation.AUTHORIZATION_WHEN_IN_USE);
Ti.Geolocation.requestAuthorization(Ti.Geolocation.AUTHORIZATION_WHEN_IN_USE);
});
win.open();

Testing for iOS7

  1. Using the app.js from this gist set your device or simulator to iOS7
  2. Press any of the request for authorization buttons
  3. Nothing should happen

Testing for iOS8 - Ti.Geolocation.AUTHORIZATION_WHEN_IN_USE

  1. Reset your device or simulator permissions
  2. Add the below keys to your tiapp.xml ios/plist/dict section
<key>NSLocationWhenInUseUsageDescription</key>
<string>Test NSLocationWhenInUseUsageDescription</string>
  1. Using the app.js from this gist set your device or simulator to iOS8
  2. Press the btnAuthorization button, you should see a status of unknown
  3. Press the btnRequestInUse button, you should now see a prompt with the text from your NSLocationWhenInUseUsageDescription key. Press allow.
  4. Press the btnAuthorization button, you should see Ti.Geolocation.AUTHORIZATION_WHEN_IN_USE

Testing for Ti.Geolocation.AUTHORIZATION_ALWAYS

  1. Reset your device or simulator permissions
  2. Add the below keys to your tiapp.xml ios/plist/dict section
<key>NSLocationAlwaysUsageDescription</key>
<string>Test NSLocationAlwaysUsageDescription</string>
  1. Using the app.js from this gist set your device or simulator to iOS8
  2. Press the btnAuthorization button, you should see a status of unknown
  3. Press the btnRequestAlways button, you should now see a prompt with the text from your NSLocationAlwaysUsageDescription key. Press allow.
  4. Press the btnAuthorization button, you should see Ti.Geolocation.AUTHORIZATION_ALWAYS or Ti.Geolocation.AUTHORIZATION_AUTHORIZED"

Testing changing permission types

  1. After running your last test try pressing btnRequestInUse
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment