Skip to content

Commit ef04507

Browse files
committed
fix: #257
1 parent 6513b9d commit ef04507

File tree

2 files changed

+117
-104
lines changed

2 files changed

+117
-104
lines changed

src/ios/CDVLocation.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,5 +66,5 @@ typedef NSUInteger CDVLocationStatus;
6666
- (void)locationManager:(CLLocationManager*)manager
6767
didFailWithError:(NSError*)error;
6868

69-
- (BOOL)isLocationServicesEnabled;
69+
- (void)isLocationServicesEnabled:(void (^)(BOOL))comletionHandler;
7070
@end

src/ios/CDVLocation.m

Lines changed: 116 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ @implementation CDVLocation
5555

5656
- (void)pluginInitialize
5757
{
58+
// TODO: The CLLocationManager instance is only safe to use on the thread/dispatch queue it was created in.
59+
// https://github.com/apache/cordova-plugin-geolocation/issues/257#issuecomment-1883740721
5860
self.locationManager = [[CLLocationManager alloc] init];
5961
self.locationManager.delegate = self; // Tells the location manager to send updates to this object
6062
__locationStarted = NO;
@@ -80,86 +82,93 @@ - (BOOL)isAuthorized
8082
return YES;
8183
}
8284

83-
- (BOOL)isLocationServicesEnabled
85+
- (void)isLocationServicesEnabled:(void (^)(BOOL))comletionHandler
8486
{
85-
BOOL locationServicesEnabledClassPropertyAvailable = [CLLocationManager respondsToSelector:@selector(locationServicesEnabled)]; // iOS 4.x
86-
87-
if (locationServicesEnabledClassPropertyAvailable) { // iOS 4.x
88-
return [CLLocationManager locationServicesEnabled];
89-
} else {
90-
return NO;
91-
}
87+
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
88+
BOOL locationServicesEnabledClassPropertyAvailable = [CLLocationManager respondsToSelector:@selector(locationServicesEnabled)]; // iOS 4.x
89+
90+
if (locationServicesEnabledClassPropertyAvailable) { // iOS 4.x
91+
comletionHandler([CLLocationManager locationServicesEnabled]);
92+
} else {
93+
comletionHandler(NO);
94+
}
95+
});
9296
}
9397

9498
- (void)startLocation:(BOOL)enableHighAccuracy
9599
{
96-
if (![self isLocationServicesEnabled]) {
97-
[self returnLocationError:PERMISSIONDENIED withMessage:@"Location services are not enabled."];
98-
return;
99-
}
100-
if (![self isAuthorized]) {
101-
NSString* message = nil;
102-
BOOL authStatusAvailable = [CLLocationManager respondsToSelector:@selector(authorizationStatus)]; // iOS 4.2+
103-
if (authStatusAvailable) {
104-
NSUInteger code = [CLLocationManager authorizationStatus];
105-
if (code == kCLAuthorizationStatusNotDetermined) {
106-
// could return POSITION_UNAVAILABLE but need to coordinate with other platforms
107-
message = @"User undecided on application's use of location services.";
108-
} else if (code == kCLAuthorizationStatusRestricted) {
109-
message = @"Application's use of location services is restricted.";
100+
[self isLocationServicesEnabled:^(BOOL enabled) {
101+
if (!enabled) {
102+
[self returnLocationError:PERMISSIONDENIED withMessage:@"Location services are not enabled."];
103+
return;
104+
} else {
105+
if (![self isAuthorized]) {
106+
NSString* message = nil;
107+
BOOL authStatusAvailable = [CLLocationManager respondsToSelector:@selector(authorizationStatus)]; // iOS 4.2+
108+
if (authStatusAvailable) {
109+
NSUInteger code = [CLLocationManager authorizationStatus];
110+
if (code == kCLAuthorizationStatusNotDetermined) {
111+
// could return POSITION_UNAVAILABLE but need to coordinate with other platforms
112+
message = @"User undecided on application's use of location services.";
113+
} else if (code == kCLAuthorizationStatusRestricted) {
114+
message = @"Application's use of location services is restricted.";
115+
}
116+
}
117+
// PERMISSIONDENIED is only PositionError that makes sense when authorization denied
118+
[self returnLocationError:PERMISSIONDENIED withMessage:message];
119+
120+
return;
110121
}
111-
}
112-
// PERMISSIONDENIED is only PositionError that makes sense when authorization denied
113-
[self returnLocationError:PERMISSIONDENIED withMessage:message];
114-
115-
return;
116-
}
117-
122+
118123
#ifdef __IPHONE_8_0
119-
NSUInteger code = [CLLocationManager authorizationStatus];
120-
if (code == kCLAuthorizationStatusNotDetermined && ([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)] || [self.locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)])) { //iOS8+
121-
__highAccuracyEnabled = enableHighAccuracy;
122-
if([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"]){
123-
[self.locationManager requestWhenInUseAuthorization];
124-
} else if([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"]) {
125-
[self.locationManager requestAlwaysAuthorization];
126-
} else {
127-
NSLog(@"[Warning] No NSLocationAlwaysUsageDescription or NSLocationWhenInUseUsageDescription key is defined in the Info.plist file.");
128-
}
129-
return;
130-
}
124+
NSUInteger code = [CLLocationManager authorizationStatus];
125+
if (code == kCLAuthorizationStatusNotDetermined && ([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)] || [self.locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)])) { //iOS8+
126+
self->__highAccuracyEnabled = enableHighAccuracy;
127+
if([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"]){
128+
[self.locationManager requestWhenInUseAuthorization];
129+
} else if([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"]) {
130+
[self.locationManager requestAlwaysAuthorization];
131+
} else {
132+
NSLog(@"[Warning] No NSLocationAlwaysUsageDescription or NSLocationWhenInUseUsageDescription key is defined in the Info.plist file.");
133+
}
134+
return;
135+
}
131136
#endif
132-
133-
// Tell the location manager to start notifying us of location updates. We
134-
// first stop, and then start the updating to ensure we get at least one
135-
// update, even if our location did not change.
136-
[self.locationManager stopUpdatingLocation];
137-
[self.locationManager startUpdatingLocation];
138-
__locationStarted = YES;
139-
if (enableHighAccuracy) {
140-
__highAccuracyEnabled = YES;
141-
// Set distance filter to 5 for a high accuracy. Setting it to "kCLDistanceFilterNone" could provide a
142-
// higher accuracy, but it's also just spamming the callback with useless reports which drain the battery.
143-
self.locationManager.distanceFilter = 5;
144-
// Set desired accuracy to Best.
145-
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
146-
} else {
147-
__highAccuracyEnabled = NO;
148-
self.locationManager.distanceFilter = 10;
149-
self.locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers;
150-
}
137+
138+
// Tell the location manager to start notifying us of location updates. We
139+
// first stop, and then start the updating to ensure we get at least one
140+
// update, even if our location did not change.
141+
[self.locationManager stopUpdatingLocation];
142+
[self.locationManager startUpdatingLocation];
143+
self->__locationStarted = YES;
144+
if (enableHighAccuracy) {
145+
self->__highAccuracyEnabled = YES;
146+
// Set distance filter to 5 for a high accuracy. Setting it to "kCLDistanceFilterNone" could provide a
147+
// higher accuracy, but it's also just spamming the callback with useless reports which drain the battery.
148+
self.locationManager.distanceFilter = 5;
149+
// Set desired accuracy to Best.
150+
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
151+
} else {
152+
self->__highAccuracyEnabled = NO;
153+
self.locationManager.distanceFilter = 10;
154+
self.locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers;
155+
}
156+
}
157+
}];
151158
}
152159

153160
- (void)_stopLocation
154161
{
155162
if (__locationStarted) {
156-
if (![self isLocationServicesEnabled]) {
157-
return;
158-
}
159-
160-
[self.locationManager stopUpdatingLocation];
161-
__locationStarted = NO;
162-
__highAccuracyEnabled = NO;
163+
[self isLocationServicesEnabled:^(BOOL enabled) {
164+
if (!enabled) {
165+
return;
166+
}
167+
168+
[self.locationManager stopUpdatingLocation];
169+
self->__locationStarted = NO;
170+
self->__highAccuracyEnabled = NO;
171+
}];
163172
}
164173
}
165174

@@ -195,36 +204,38 @@ - (void)getLocation:(CDVInvokedUrlCommand*)command
195204
NSString* callbackId = command.callbackId;
196205
BOOL enableHighAccuracy = [[command argumentAtIndex:0] boolValue];
197206

198-
if ([self isLocationServicesEnabled] == NO) {
199-
NSMutableDictionary* posError = [NSMutableDictionary dictionaryWithCapacity:2];
200-
[posError setObject:[NSNumber numberWithInt:PERMISSIONDENIED] forKey:@"code"];
201-
[posError setObject:@"Location services are disabled." forKey:@"message"];
202-
CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:posError];
203-
[self.commandDelegate sendPluginResult:result callbackId:callbackId];
204-
} else {
205-
if (!self.locationData) {
206-
self.locationData = [[CDVLocationData alloc] init];
207-
}
208-
CDVLocationData* lData = self.locationData;
209-
@synchronized (self.locationData.locationCallbacks) {
210-
if (!lData.locationCallbacks) {
211-
lData.locationCallbacks = [NSMutableArray arrayWithCapacity:1];
207+
[self isLocationServicesEnabled:^(BOOL enabled) {
208+
if (!enabled) {
209+
NSMutableDictionary* posError = [NSMutableDictionary dictionaryWithCapacity:2];
210+
[posError setObject:[NSNumber numberWithInt:PERMISSIONDENIED] forKey:@"code"];
211+
[posError setObject:@"Location services are disabled." forKey:@"message"];
212+
CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:posError];
213+
[self.commandDelegate sendPluginResult:result callbackId:callbackId];
214+
} else {
215+
if (!self.locationData) {
216+
self.locationData = [[CDVLocationData alloc] init];
212217
}
213-
}
214-
215-
if (!self->__locationStarted || (self->__highAccuracyEnabled != enableHighAccuracy)) {
216-
// add the callbackId into the array so we can call back when get data
218+
CDVLocationData* lData = self.locationData;
217219
@synchronized (self.locationData.locationCallbacks) {
218-
if (callbackId != nil) {
219-
[lData.locationCallbacks addObject:callbackId];
220+
if (!lData.locationCallbacks) {
221+
lData.locationCallbacks = [NSMutableArray arrayWithCapacity:1];
220222
}
221223
}
222-
// Tell the location manager to start notifying us of heading updates
223-
[self startLocation:enableHighAccuracy];
224-
} else {
225-
[self returnLocationInfo:callbackId andKeepCallback:NO];
224+
225+
if (!self->__locationStarted || (self->__highAccuracyEnabled != enableHighAccuracy)) {
226+
// add the callbackId into the array so we can call back when get data
227+
@synchronized (self.locationData.locationCallbacks) {
228+
if (callbackId != nil) {
229+
[lData.locationCallbacks addObject:callbackId];
230+
}
231+
}
232+
// Tell the location manager to start notifying us of heading updates
233+
[self startLocation:enableHighAccuracy];
234+
} else {
235+
[self returnLocationInfo:callbackId andKeepCallback:NO];
236+
}
226237
}
227-
}
238+
}];
228239
}];
229240
}
230241

@@ -246,18 +257,20 @@ - (void)addWatch:(CDVInvokedUrlCommand*)command
246257
// add the callbackId into the dictionary so we can call back whenever get data
247258
[lData.watchCallbacks setObject:callbackId forKey:timerId];
248259

249-
if ([self isLocationServicesEnabled] == NO) {
250-
NSMutableDictionary* posError = [NSMutableDictionary dictionaryWithCapacity:2];
251-
[posError setObject:[NSNumber numberWithInt:PERMISSIONDENIED] forKey:@"code"];
252-
[posError setObject:@"Location services are disabled." forKey:@"message"];
253-
CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:posError];
254-
[self.commandDelegate sendPluginResult:result callbackId:callbackId];
255-
} else {
256-
if (!__locationStarted || (__highAccuracyEnabled != enableHighAccuracy)) {
257-
// Tell the location manager to start notifying us of location updates
258-
[self startLocation:enableHighAccuracy];
260+
[self isLocationServicesEnabled:^(BOOL enabled) {
261+
if (!enabled) {
262+
NSMutableDictionary* posError = [NSMutableDictionary dictionaryWithCapacity:2];
263+
[posError setObject:[NSNumber numberWithInt:PERMISSIONDENIED] forKey:@"code"];
264+
[posError setObject:@"Location services are disabled." forKey:@"message"];
265+
CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:posError];
266+
[self.commandDelegate sendPluginResult:result callbackId:callbackId];
267+
} else {
268+
if (!self->__locationStarted || (self->__highAccuracyEnabled != enableHighAccuracy)) {
269+
// Tell the location manager to start notifying us of location updates
270+
[self startLocation:enableHighAccuracy];
271+
}
259272
}
260-
}
273+
}];
261274
}
262275

263276
- (void)clearWatch:(CDVInvokedUrlCommand*)command

0 commit comments

Comments
 (0)