Skip to content

Commit

Permalink
Merge pull request #237 from JGreenlee/comply-ios-permissions
Browse files Browse the repository at this point in the history
🍎 iOS Permissions Changes to Comply with iOS Guidelines
  • Loading branch information
shankari authored Oct 7, 2024
2 parents dcc4853 + 84f5003 commit 01f3982
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 35 deletions.
10 changes: 5 additions & 5 deletions plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -212,27 +212,27 @@
</config-file>

<config-file target="*-Info.plist" parent="NSLocationAlwaysAndWhenInUseUsageDescription">
<string>We use your data to create an automatic trip diary</string>
<string>To create an automatic trip diary, "Precise" location access must be "Always" allowed</string>
</config-file>

<config-file target="*-Info.plist" parent="NSLocationAlwaysUsageDescription">
<string>We use your data to create an automatic trip diary</string>
<string>To track your trips in the background, location access must be "Always" allowed</string>
</config-file>

<config-file target="*-Info.plist" parent="NSLocationWhenInUseUsageDescription">
<string>We use your data to create an automatic trip diary</string>
<string>To create an automatic trip diary, "Precise" location access must be allowed "While Using App"</string>
</config-file>

<config-file target="*-Info.plist" parent="NSMotionUsageDescription">
<string>Our app uses the motion sensors to determine the transportation mode for the sections of your trip</string>
<string>To determine the modes of transportation during your trips, the app must access your phone's motion sensors</string>
</config-file>

<config-file target="*-Info.plist" parent="ITSAppUsesNonExemptEncryption">
<false/>
</config-file>

<config-file target="*-Info.plist" parent="NSBluetoothAlwaysUsageDescription">
<string>We need Bluetooth access to interact with BLE beacons for the fleet version of the app.</string>
<string>To interact with BLE beacons for the fleet version of the app, Bluetooth access is required</string>
</config-file>

<podspec>
Expand Down
7 changes: 3 additions & 4 deletions res/android/values/dc_strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,8 @@
<!-- TripDiaryStateMachineService and Ongoing-->
<string name="success_moving_new_state">Success moving to %1$s</string>
<string name="failed_moving_new_state">Failed moving to %1$s</string>
<string name="location_permission_off">Insufficient location permissions, please fix</string>
<string name="location_permission_off_app_open">Insufficient location permissions, please fix in app settings</string>
<string name="location_permission_off_enable">Location permission off, click to enable</string>
<string name="location_permission_off">Insufficient permissions, please allow 'Always' and 'Precise' location access</string>
<string name="location_permission_off_app_open">Insufficient permissions, please select 'Always' and 'Precise' location access in app settings</string>
<string name="location_permission_intermediary_title">Permissions Needed!</string>
<string name="location_permission_intermediary_message">Further location permission needed. In order to use this app you need to click \"Allow all the time\" on the next page.</string>
<string name="location_feedback_both_off">Please make sure \"Allow all the time\" and \"Precise Location\" are turned on in the settings.</string>
Expand All @@ -32,7 +31,7 @@
<string name="activity_permission_off">Activity permission off, please fix</string>
<string name="activity_permission_off_app_open">Activity permission off, please fix in app settings</string>
<string name="activity_permission_off_enable">Activity permission off, click to enable</string>
<string name="notifications_blocked">Notifications blocked, please enable</string>
<string name="notifications_blocked">Notifications blocked, you will not be able to receive reminders or alerts</string>
<string name="notifications_paused">Notifications paused. This can only be fixed by the app developer. Please report to your admin.</string>
<string name="unused_apps_restricted">Please allow this app to read sensor data even if you launch it infrequently.</string>
<string name="fix_app_status_title">Please update permissions</string>
Expand Down
8 changes: 3 additions & 5 deletions res/ios/en.lproj/DCLocalizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,10 @@
"location-permission-problem" = "The app does not have the 'always' permission - background trip tracking will not work.";
"fix-permission-action-button" = "Fix permission";
"precise-location-problem" = "The app does not have permission to read 'precise' location - background trip tracking will not work.";
"notifications_blocked" = "Notifications blocked, please enable";
"notifications_blocked_app_open" = "Notifications blocked, please fix in app settings and then refresh";
"notifications_blocked" = "Notifications blocked, you will not be able to receive reminders or alerts";
"location_not_enabled" = "Location turned off, please turn on";
"location_permission_off" = "Insufficient location permissions, please fix";
"location_permission_off_app_open" = "Insufficient location permissions, please fix in app settings";
"location_permission_off_enable" = "Insufficient location permissions, please enable";
"location_permission_off" = "Insufficient permissions, please allow 'Always' and 'Precise' location access";
"location_permission_off_app_open" = "Insufficient permissions, please select 'Always' and 'Precise' location access in app settings";
"activity_permission_off" = "Motion and Fitness permission off, please enable";
"activity_permission_off_app_open" = "Motion and Fitness permission off, please fix in app settings";
"fix_app_status_title" = "Please update permissions";
Expand Down
74 changes: 53 additions & 21 deletions src/ios/Verification/SensorControlForegroundDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,16 @@ - (void) didChangeAuthorizationStatus:(CLAuthorizationStatus)status
CDVPluginResult* result = [CDVPluginResult
resultWithStatus:CDVCommandStatus_OK];
[commandDelegate sendPluginResult:result callbackId:callbackId];
} else if (status == kCLAuthorizationStatusAuthorizedWhenInUse) {
if (IsAtLeastiOSVersion(@"13.4")) {
NSLog(@"iOS >=13.4 detected and 'whenInUse' authorized, need second step to request 'always'");
[[TripDiaryStateMachine delegate] registerForegroundDelegate:self];
[[TripDiaryStateMachine instance].locMgr requestAlwaysAuthorization];
if ([[UIApplication sharedApplication] applicationState] != UIApplicationStateInactive) {
NSLog(@"App is active, i.e. request did not launch (happens if the user chose 'Allow Once' in step 1). Launching app settings to manually enable 'Always'");
[self openAppSettings];
}
}
} else {
[LocalNotificationManager addNotification:[NSString stringWithFormat:@"status %d != always %d, returning error", status, kCLAuthorizationStatusAuthorizedAlways]];
NSString* msg = NSLocalizedStringFromTable(@"location_permission_off_app_open", @"DCLocalizable", nil);
Expand Down Expand Up @@ -249,10 +259,17 @@ -(void) didRecieveFitnessPermission:(BOOL)isPermitted
- (void)checkAndPromptNotificationPermission {
NSString* callbackId = [command callbackId];
@try {
if ([UIApplication instancesRespondToSelector:@selector(registerUserNotificationSettings:)]) {
UIUserNotificationSettings* requestedSettings = [TripDiarySensorControlChecks REQUESTED_NOTIFICATION_TYPES];
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"HasPromptedForUserNotification"]) {
NSLog(@"Already prompted request for user notification. Launching app settings.");
[AppDelegate registerForegroundDelegate:self];
[[UIApplication sharedApplication] registerUserNotificationSettings:requestedSettings];
[self openAppSettings];
} else {
if ([UIApplication instancesRespondToSelector:@selector(registerUserNotificationSettings:)]) {
NSLog(@"Requesting user notification settings");
UIUserNotificationSettings* requestedSettings = [TripDiarySensorControlChecks REQUESTED_NOTIFICATION_TYPES];
[AppDelegate registerForegroundDelegate:self];
[[UIApplication sharedApplication] registerUserNotificationSettings:requestedSettings];
}
}
}
@catch (NSException *exception) {
Expand All @@ -265,15 +282,15 @@ - (void)checkAndPromptNotificationPermission {
}

- (void) didRegisterUserNotificationSettings:(UIUserNotificationSettings*)newSettings {
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"HasPromptedForUserNotification"];
NSString* callbackId = [command callbackId];
UIUserNotificationSettings* requestedSettings = [TripDiarySensorControlChecks REQUESTED_NOTIFICATION_TYPES];
if (requestedSettings.types == newSettings.types) {
CDVPluginResult* result = [CDVPluginResult
resultWithStatus:CDVCommandStatus_OK];
[commandDelegate sendPluginResult:result callbackId:callbackId];
} else {
NSString* msg = NSLocalizedStringFromTable(@"notifications_blocked_app_open", @"DCLocalizable", nil);
[self openAppSettings];
NSString* msg = NSLocalizedStringFromTable(@"notifications_blocked", @"DCLocalizable", nil);
CDVPluginResult* result = [CDVPluginResult
resultWithStatus:CDVCommandStatus_ERROR
messageAsString:msg];
Expand All @@ -282,25 +299,39 @@ - (void) didRegisterUserNotificationSettings:(UIUserNotificationSettings*)newSet
}

-(void)promptForPermission:(CLLocationManager*)locMgr {
if (IsAtLeastiOSVersion(@"13.0")) {
NSLog(@"iOS 13+ detected, launching UI settings to easily enable always");
if (IsAtLeastiOSVersion(@"13.4")) {
NSLog(@"iOS >=13.4 detected, using two-step approach of 'when in use' first and then 'always'");
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined) {
NSLog(@"Current location authorization = %d, when in use = %d, requesting when in use",
[CLLocationManager authorizationStatus], kCLAuthorizationStatusAuthorizedWhenInUse);
[[TripDiaryStateMachine delegate] registerForegroundDelegate:self];
[locMgr requestWhenInUseAuthorization];
} else if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedWhenInUse) {
NSLog(@"Current location authorization = %d, always = %d, requesting always",
[CLLocationManager authorizationStatus], kCLAuthorizationStatusAuthorizedAlways);
[[TripDiaryStateMachine delegate] registerForegroundDelegate:self];
[locMgr requestAlwaysAuthorization];
if ([[UIApplication sharedApplication] applicationState] != UIApplicationStateInactive) {
NSLog(@"App is active, i.e. request did not launch (happens if the user chose 'Allow Once' in step 1). Launching app settings to manually enable 'Always'");
[self openAppSettings];
}
} else {
[[TripDiaryStateMachine delegate] registerForegroundDelegate:self];
[self openAppSettings];
}
} else if (IsAtLeastiOSVersion(@"13.0")) {
NSLog(@"iOS >=13,<13.4 detected, launching UI settings to manually enable 'always'");
// we want to leave the registration in the prompt for permission, since we don't want to register callbacks when we open the app settings for other reasons
[[TripDiaryStateMachine delegate] registerForegroundDelegate:self];
[[TripDiaryStateMachine instance].locMgr startUpdatingLocation];
[self openAppSettings];
}
else {
} else {
NSLog(@"iOS <13 detected, simply requesting 'always'");
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined) {
if ([CLLocationManager instancesRespondToSelector:@selector(requestAlwaysAuthorization)]) {
NSLog(@"Current location authorization = %d, always = %d, requesting always",
[CLLocationManager authorizationStatus], kCLAuthorizationStatusAuthorizedAlways);
[[TripDiaryStateMachine delegate] registerForegroundDelegate:self];
[locMgr requestAlwaysAuthorization];
} else {
// TODO: should we remove this? Not sure when it will ever be called, given that
// requestAlwaysAuthorization is available in iOS8+
[LocalNotificationManager addNotification:@"Don't need to request authorization, system will automatically prompt for it"];
}
NSLog(@"Current location authorization = %d, always = %d, requesting always",
[CLLocationManager authorizationStatus], kCLAuthorizationStatusAuthorizedAlways);
[[TripDiaryStateMachine delegate] registerForegroundDelegate:self];
[locMgr requestAlwaysAuthorization];
} else {
// we want to leave the registration in the prompt for permission, since we don't want to register callbacks when we open the app settings for other reasons
[[TripDiaryStateMachine delegate] registerForegroundDelegate:self];
Expand Down Expand Up @@ -347,11 +378,12 @@ - (void)locationManager:(CLLocationManager *)manager
if (foregroundDelegateList.count > 0) {
[LocalNotificationManager addNotification:[NSString stringWithFormat:@"%lu foreground delegates found, calling didChangeAuthorizationStatus to return the new value %d", (unsigned long)foregroundDelegateList.count, status]];

int originalDelegateCount = (int)foregroundDelegateList.count;
for (id currDelegate in foregroundDelegateList) {
[currDelegate didChangeAuthorizationStatus:(CLAuthorizationStatus)status];
}
[LocalNotificationManager addNotification:[NSString stringWithFormat:@"Notified all foreground delegates, removing all of them"]];
[foregroundDelegateList removeAllObjects];
[LocalNotificationManager addNotification:[NSString stringWithFormat:@"Notified all foreground delegates, removing %d delegates", originalDelegateCount]];
[foregroundDelegateList removeObjectsInRange:NSMakeRange(0, originalDelegateCount)];
} else {
[LocalNotificationManager addNotification:[NSString stringWithFormat:@"No foreground delegate found, calling SensorControlBackgroundChecker from didChangeAuthorizationStatus to verify location service status and permission"]];
[SensorControlBackgroundChecker checkAppState];
Expand Down

0 comments on commit 01f3982

Please sign in to comment.