Skip to content

Commit 8029bd4

Browse files
committed
Add Settings option to denied location prompt
* Whenever the user clicks on never ask again option and denies the permission, we will show the reason why we need it and the option to open settings and change the location permission
1 parent ab0f423 commit 8029bd4

File tree

5 files changed

+56
-21
lines changed

5 files changed

+56
-21
lines changed

iOS_SDK/OneSignalSDK/Source/OSInAppMessageLocationPrompt.m

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030

3131
@interface OneSignal ()
3232

33-
+ (void)promptLocation:(void (^)(PromptActionResult result))completionHandler;
33+
+ (void)promptLocationFallbackToSettings:(BOOL)fallback completionHandler:(void (^)(PromptActionResult result))completionHandler;
3434

3535
@end
3636

@@ -46,7 +46,7 @@ - (instancetype)init
4646
}
4747

4848
- (void)handlePrompt:(void (^)(PromptActionResult result))completionHandler {
49-
[OneSignal promptLocation:completionHandler];
49+
[OneSignal promptLocationFallbackToSettings:true completionHandler:completionHandler];
5050
}
5151

5252
- (NSString *)description {

iOS_SDK/OneSignalSDK/Source/OneSignal.m

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -556,7 +556,7 @@ + (id)initWithLaunchOptions:(NSDictionary*)launchOptions
556556
_outcomeEventsController = [[OneSignalOutcomeEventsController alloc] init:self.sessionManager];
557557

558558
if (appId && mShareLocation)
559-
[OneSignalLocation getLocation:false withCompletionHandler:nil];
559+
[OneSignalLocation getLocation:false fallbackToSettings:false withCompletionHandler:nil];
560560

561561
/*
562562
* No need to call the handleNotificationOpened:userInfo as it will be called from one of the following selectors
@@ -1394,15 +1394,15 @@ + (void)setLocationShared:(BOOL)enable {
13941394
}
13951395

13961396
+ (void)promptLocation {
1397-
[self promptLocation:nil];
1397+
[self promptLocationFallbackToSettings:false completionHandler:nil];
13981398
}
13991399

1400-
+ (void)promptLocation:(void (^)(PromptActionResult result))completionHandler {
1400+
+ (void)promptLocationFallbackToSettings:(BOOL)fallback completionHandler:(void (^)(PromptActionResult result))completionHandler {
14011401
// return if the user has not granted privacy permissions
14021402
if ([self shouldLogMissingPrivacyConsentErrorWithMethodName:@"promptLocation"])
14031403
return;
14041404

1405-
[OneSignalLocation getLocation:true withCompletionHandler:completionHandler];
1405+
[OneSignalLocation getLocation:true fallbackToSettings:fallback withCompletionHandler:completionHandler];
14061406
}
14071407

14081408
+ (BOOL)isLocationShared {

iOS_SDK/OneSignalSDK/Source/OneSignalLocation.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,13 @@
2525
* THE SOFTWARE.
2626
*/
2727

28-
#ifndef OneSignalLocation_h
29-
#define OneSignalLocation_h
30-
3128
#import <Foundation/Foundation.h>
29+
#import <UIKit/UIKit.h>
3230
#import "OneSignalCommonDefines.h"
3331

32+
#ifndef OneSignalLocation_h
33+
#define OneSignalLocation_h
34+
3435
typedef struct os_location_coordinate {
3536
double latitude;
3637
double longitude;
@@ -42,13 +43,13 @@ typedef struct os_last_location {
4243
double horizontalAccuracy;
4344
} os_last_location;
4445

45-
@interface OneSignalLocation : NSObject
46+
@interface OneSignalLocation : NSObject <UIAlertViewDelegate>
4647

4748
+ (OneSignalLocation*) sharedInstance;
4849
+ (bool)started;
49-
+ (void)internalGetLocation:(bool)prompt;
50+
+ (void)internalGetLocation:(bool)prompt fallbackToSettings:(BOOL)fallback;
5051
- (void)locationManager:(id)manager didUpdateLocations:(NSArray *)locations;
51-
+ (void)getLocation:(bool)prompt withCompletionHandler:(void (^)(PromptActionResult result))completionHandler;
52+
+ (void)getLocation:(bool)prompt fallbackToSettings:(BOOL)fallback withCompletionHandler:(void (^)(PromptActionResult result))completionHandler;
5253
+ (void)sendLocation;
5354
+ (os_last_location*)lastLocation;
5455
+ (void)clearLastLocation;

iOS_SDK/OneSignalSDK/Source/OneSignalLocation.m

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,12 @@ @implementation OneSignalLocation
5050
os_last_location *lastLocation;
5151
bool initialLocationSent = false;
5252
UIBackgroundTaskIdentifier fcTask;
53+
const int alertSettingsTag = 199;
5354

5455
static id locationManager = nil;
5556
static bool started = false;
5657
static bool hasDelayed = false;
58+
static bool fallbackToSettings = false;
5759

5860
// CoreLocation must be statically linked for geotagging to work on iOS 6 and possibly 7.
5961
// plist NSLocationUsageDescription (iOS 6 & 7) and NSLocationWhenInUseUsageDescription (iOS 8+) keys also required.
@@ -104,18 +106,18 @@ + (void)clearLastLocation {
104106
}
105107
}
106108

107-
+ (void)getLocation:(bool)prompt withCompletionHandler:(void (^)(PromptActionResult result))completionHandler {
109+
+ (void)getLocation:(bool)prompt fallbackToSettings:(BOOL)fallback withCompletionHandler:(void (^)(PromptActionResult result))completionHandler {
108110
if (completionHandler)
109111
[OneSignalLocation.locationListeners addObject:completionHandler];
110112

111113
if (hasDelayed)
112-
[OneSignalLocation internalGetLocation:prompt];
114+
[OneSignalLocation internalGetLocation:prompt fallbackToSettings:fallback];
113115
else {
114116
// Delay required for locationServicesEnabled and authorizationStatus return the correct values when CoreLocation is not statically linked.
115117
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 2.0 * NSEC_PER_SEC);
116118
dispatch_after(popTime, dispatch_get_main_queue(), ^(void) {
117119
hasDelayed = true;
118-
[OneSignalLocation internalGetLocation:prompt];
120+
[OneSignalLocation internalGetLocation:prompt fallbackToSettings:fallback];
119121
});
120122
}
121123
// Listen to app going to and from background
@@ -193,16 +195,29 @@ + (void)sendCurrentAuthStatusToListeners {
193195
[self sendAndClearLocationListener:denied ? PERMISSION_DENIED : PERMISSION_GRANTED];
194196
}
195197

196-
+ (void)internalGetLocation:(bool)prompt {
198+
+ (void)internalGetLocation:(bool)prompt fallbackToSettings:(BOOL)fallback {
199+
fallbackToSettings = fallback;
200+
id clLocationManagerClass = NSClassFromString(@"CLLocationManager");
201+
202+
// On the application init we are always calling this method
203+
// If location permissions was not asked "started" will never be true
197204
if ([self started]) {
198-
[self sendCurrentAuthStatusToListeners];
205+
// We evaluate the following cases after permissions were asked (denied or given)
206+
CLAuthorizationStatus permissionStatus = [clLocationManagerClass performSelector:@selector(authorizationStatus)];
207+
// Fallback to settings alert view when the following condition are true:
208+
// - On a prompt flow
209+
// - Fallback to settings is enabled
210+
// - Permission were denied
211+
if (prompt && fallback && permissionStatus == kCLAuthorizationStatusDenied)
212+
[self showLocationSettingsAlertView];
213+
else
214+
[self sendCurrentAuthStatusToListeners];
199215
return;
200216
}
201217

202-
id clLocationManagerClass = NSClassFromString(@"CLLocationManager");
203-
204218
// Check for location in plist
205219
if (![clLocationManagerClass performSelector:@selector(locationServicesEnabled)]) {
220+
onesignal_Log(ONE_S_LL_DEBUG, @"CLLocationManager locationServices Disabled.");
206221
[self sendAndClearLocationListener:ERROR];
207222
return;
208223
}
@@ -249,11 +264,30 @@ + (void)internalGetLocation:(bool)prompt {
249264
started = true;
250265
}
251266

267+
+ (void)showLocationSettingsAlertView {
268+
onesignal_Log(ONE_S_LL_DEBUG, @"CLLocationManager permissionStatus kCLAuthorizationStatusDenied fallaback to settings");
269+
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Location Not Available" message:@"You have previously denied sharing your device location. Please go to settings to enable." delegate:singleInstance cancelButtonTitle:@"Cancel" otherButtonTitles:@"Open Settings", nil];
270+
alertView.tag = alertSettingsTag;
271+
[alertView show];
272+
}
273+
274+
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
275+
if (alertView.tag == alertSettingsTag) {
276+
if (buttonIndex == 1) {
277+
onesignal_Log(ONE_S_LL_DEBUG, @"CLLocationManage open settings option click");
278+
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
279+
}
280+
[OneSignalLocation sendAndClearLocationListener:false];
281+
return;
282+
}
283+
}
284+
252285
#pragma mark CLLocationManagerDelegate
253286

254287
- (void)locationManager:(id)manager didUpdateLocations:(NSArray *)locations {
255288
// return if the user has not granted privacy permissions or location shared is false
256-
if ([OneSignal requiresUserPrivacyConsent] || ![OneSignal isLocationShared]) {
289+
if (([OneSignal requiresUserPrivacyConsent] || ![OneSignal isLocationShared]) && !fallbackToSettings) {
290+
onesignal_Log(ONE_S_LL_DEBUG, @"CLLocationManagerDelegate clear Location listener due to permissions denied or location shared not available");
257291
[OneSignalLocation sendAndClearLocationListener:PERMISSION_DENIED];
258292
return;
259293
}

iOS_SDK/OneSignalSDK/UnitTests/Shadows/OneSignalLocationOverrider.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ + (void)grantLocationServices {
9999
calledRequestAlwaysAuthorization = false;
100100
calledRequestWhenInUseAuthorization = false;
101101

102-
[OneSignalLocation internalGetLocation:true];
102+
[OneSignalLocation internalGetLocation:true fallbackToSettings:false];
103103
}
104104

105105
+ (int)overrideAuthorizationStatus {

0 commit comments

Comments
 (0)