@@ -200,81 +200,92 @@ + (void)sendCurrentAuthStatusToListeners {
200200}
201201
202202+ (void )internalGetLocation : (bool )prompt fallbackToSettings : (BOOL )fallback {
203- fallbackToSettings = fallback;
204- id clLocationManagerClass = NSClassFromString (@" CLLocationManager" );
205-
206- // On the application init we are always calling this method
207- // If location permissions was not asked "started" will never be true
208- if ([self started ]) {
209- // We evaluate the following cases after permissions were asked (denied or given)
210- CLAuthorizationStatus permissionStatus = [clLocationManagerClass performSelector: @selector (authorizationStatus )];
211- BOOL showSettings = prompt && fallback && permissionStatus == kCLAuthorizationStatusDenied ;
212- [OneSignal onesignalLog: ONE_S_LL_DEBUG message: [NSString stringWithFormat: @" internalGetLocation called showSettings: %@ " , showSettings ? @" YES" : @" NO" ]];
213- // Fallback to settings alert view when the following condition are true:
214- // - On a prompt flow
215- // - Fallback to settings is enabled
216- // - Permission were denied
217- if (showSettings)
218- [self showLocationSettingsAlertController ];
219- else
220- [self sendCurrentAuthStatusToListeners ];
221- return ;
222- }
223-
224- // Check for location in plist
225- if (![clLocationManagerClass performSelector: @selector (locationServicesEnabled )]) {
226- [OneSignal onesignalLog: ONE_S_LL_DEBUG message: @" CLLocationManager locationServices Disabled." ];
227- [self sendAndClearLocationListener: ERROR];
228- return ;
229- }
230-
231- CLAuthorizationStatus permissionStatus = [clLocationManagerClass performSelector: @selector (authorizationStatus )];
232- // return if permission not determined and should not prompt
233- if (permissionStatus == kCLAuthorizationStatusNotDetermined && !prompt) {
234- [OneSignal onesignalLog: ONE_S_LL_DEBUG message: @" internalGetLocation kCLAuthorizationStatusNotDetermined." ];
235- return ;
236- }
237-
238- [self sendCurrentAuthStatusToListeners ];
239- locationManager = [[clLocationManagerClass alloc ] init ];
240- [locationManager setValue: [self sharedInstance ] forKey: @" delegate" ];
241-
203+ /*
204+ Do permission checking on a background thread to resolve locationServicesEnabled warning.
205+ */
206+ dispatch_async (dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0 ), ^{
207+ fallbackToSettings = fallback;
208+ id clLocationManagerClass = NSClassFromString (@" CLLocationManager" );
242209
243- // Check info plist for request descriptions
244- // LocationAlways > LocationWhenInUse > No entry (Log error)
245- // Location Always requires: Location Background Mode + NSLocationAlwaysUsageDescription
246- NSArray * backgroundModes = [[NSBundle mainBundle ] objectForInfoDictionaryKey: @" UIBackgroundModes" ];
247- NSString * alwaysDescription = [[NSBundle mainBundle ] objectForInfoDictionaryKey: @" NSLocationAlwaysUsageDescription" ] ?: [[NSBundle mainBundle ] objectForInfoDictionaryKey: @" NSLocationAlwaysAndWhenInUseUsageDescription" ];
248- // use background location updates if always permission granted or prompt allowed
249- BOOL backgroundLocationEnable = backgroundModes && [backgroundModes containsObject: @" location" ] && alwaysDescription;
250- BOOL permissionEnable = permissionStatus == kCLAuthorizationStatusAuthorizedAlways || prompt;
251-
252- [OneSignal onesignalLog: ONE_S_LL_DEBUG message: [NSString stringWithFormat: @" internalGetLocation called backgroundLocationEnable: %@ permissionEnable: %@ " , backgroundLocationEnable ? @" YES" : @" NO" , permissionEnable ? @" YES" : @" NO" ]];
253-
254- if (backgroundLocationEnable && permissionEnable) {
255- #pragma clang diagnostic push
256- #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
257- [locationManager performSelector: NSSelectorFromString (@" requestAlwaysAuthorization" )];
258- #pragma clang diagnostic pop
259- if ([OneSignalHelper isIOSVersionGreaterThanOrEqual: @" 9.0" ])
260- [locationManager setValue: @YES forKey: @" allowsBackgroundLocationUpdates" ];
261- }
262-
263- else if ([[NSBundle mainBundle ] objectForInfoDictionaryKey: @" NSLocationWhenInUseUsageDescription" ]) {
264- if (permissionStatus == kCLAuthorizationStatusNotDetermined )
265- [locationManager performSelector: @selector (requestWhenInUseAuthorization )];
266- }
267-
268- else {
269- [OneSignal onesignalLog: ONE_S_LL_ERROR message: @" Include a privacy NSLocationAlwaysUsageDescription or NSLocationWhenInUseUsageDescription in your info.plist to request location permissions." ];
270- [self sendAndClearLocationListener: LOCATION_PERMISSIONS_MISSING_INFO_PLIST];
271- }
210+ // On the application init we are always calling this method
211+ // If location permissions was not asked "started" will never be true
212+ if ([self started ]) {
213+ // We evaluate the following cases after permissions were asked (denied or given)
214+ CLAuthorizationStatus permissionStatus = [clLocationManagerClass performSelector: @selector (authorizationStatus )];
215+ BOOL showSettings = prompt && fallback && permissionStatus == kCLAuthorizationStatusDenied ;
216+ [OneSignal onesignalLog: ONE_S_LL_DEBUG message: [NSString stringWithFormat: @" internalGetLocation called showSettings: %@ " , showSettings ? @" YES" : @" NO" ]];
217+ // Fallback to settings alert view when the following condition are true:
218+ // - On a prompt flow
219+ // - Fallback to settings is enabled
220+ // - Permission were denied
221+ if (showSettings)
222+ [self showLocationSettingsAlertController ];
223+ else
224+ [self sendCurrentAuthStatusToListeners ];
225+ return ;
226+ }
272227
273- // This method is used for getting the location manager to obtain an initial location fix
274- // and will notify your delegate by calling its locationManager:didUpdateLocations: method
275- [locationManager performSelector: @selector (startUpdatingLocation )];
228+ // Check for location in plist
229+ if (![clLocationManagerClass performSelector: @selector (locationServicesEnabled )]) {
230+ [OneSignal onesignalLog: ONE_S_LL_DEBUG message: @" CLLocationManager locationServices Disabled." ];
231+ [self sendAndClearLocationListener: ERROR];
232+ return ;
233+ }
234+
235+ CLAuthorizationStatus permissionStatus = [clLocationManagerClass performSelector: @selector (authorizationStatus )];
236+ // return if permission not determined and should not prompt
237+ if (permissionStatus == kCLAuthorizationStatusNotDetermined && !prompt) {
238+ [OneSignal onesignalLog: ONE_S_LL_DEBUG message: @" internalGetLocation kCLAuthorizationStatusNotDetermined." ];
239+ return ;
240+ }
241+
242+ [self sendCurrentAuthStatusToListeners ];
243+ /*
244+ The location manager must be created on a thread with a run loop so we will go back to the main thread.
245+ */
246+ dispatch_async (dispatch_get_main_queue (), ^{
247+ locationManager = [[clLocationManagerClass alloc ] init ];
248+ [locationManager setValue: [self sharedInstance ] forKey: @" delegate" ];
249+
250+
251+ // Check info plist for request descriptions
252+ // LocationAlways > LocationWhenInUse > No entry (Log error)
253+ // Location Always requires: Location Background Mode + NSLocationAlwaysUsageDescription
254+ NSArray * backgroundModes = [[NSBundle mainBundle ] objectForInfoDictionaryKey: @" UIBackgroundModes" ];
255+ NSString * alwaysDescription = [[NSBundle mainBundle ] objectForInfoDictionaryKey: @" NSLocationAlwaysUsageDescription" ] ?: [[NSBundle mainBundle ] objectForInfoDictionaryKey: @" NSLocationAlwaysAndWhenInUseUsageDescription" ];
256+ // use background location updates if always permission granted or prompt allowed
257+ BOOL backgroundLocationEnable = backgroundModes && [backgroundModes containsObject: @" location" ] && alwaysDescription;
258+ BOOL permissionEnable = permissionStatus == kCLAuthorizationStatusAuthorizedAlways || prompt;
259+
260+ [OneSignal onesignalLog: ONE_S_LL_DEBUG message: [NSString stringWithFormat: @" internalGetLocation called backgroundLocationEnable: %@ permissionEnable: %@ " , backgroundLocationEnable ? @" YES" : @" NO" , permissionEnable ? @" YES" : @" NO" ]];
261+
262+ if (backgroundLocationEnable && permissionEnable) {
263+ #pragma clang diagnostic push
264+ #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
265+ [locationManager performSelector: NSSelectorFromString (@" requestAlwaysAuthorization" )];
266+ #pragma clang diagnostic pop
267+ if ([OneSignalHelper isIOSVersionGreaterThanOrEqual: @" 9.0" ])
268+ [locationManager setValue: @YES forKey: @" allowsBackgroundLocationUpdates" ];
269+ }
270+
271+ else if ([[NSBundle mainBundle ] objectForInfoDictionaryKey: @" NSLocationWhenInUseUsageDescription" ]) {
272+ if (permissionStatus == kCLAuthorizationStatusNotDetermined )
273+ [locationManager performSelector: @selector (requestWhenInUseAuthorization )];
274+ }
275+
276+ else {
277+ [OneSignal onesignalLog: ONE_S_LL_ERROR message: @" Include a privacy NSLocationAlwaysUsageDescription or NSLocationWhenInUseUsageDescription in your info.plist to request location permissions." ];
278+ [self sendAndClearLocationListener: LOCATION_PERMISSIONS_MISSING_INFO_PLIST];
279+ }
280+
281+ // This method is used for getting the location manager to obtain an initial location fix
282+ // and will notify your delegate by calling its locationManager:didUpdateLocations: method
283+
284+ [locationManager performSelector: @selector (startUpdatingLocation )];
285+ started = true ;
286+ });
287+ });
276288
277- started = true ;
278289}
279290
280291+ (void )showLocationSettingsAlertController {
0 commit comments