Skip to content

Commit

Permalink
Fixes a bug where iOS location settings, e.g. accuracy and `distanc…
Browse files Browse the repository at this point in the history
…eFilter` are overridden by different calls (#1600)

* Fixes a bug where iOS location settings, e.g. `accuracy` and `distanceFilter` are overridden by different calls

* Reverted changes to the geolocator package to create a separate PR for those.
Revert the changes for the requestLocation API. Now use separate oneTimeLocationManager with startUpdatingLocation logic.
Reverted and updated tests.

---------

Co-authored-by: Oksana Liahusha <[email protected]>
  • Loading branch information
ksenia-lyagusha and Oksana Liahusha authored Nov 14, 2024
1 parent b53e4a5 commit 6a226c8
Show file tree
Hide file tree
Showing 7 changed files with 176 additions and 128 deletions.
6 changes: 6 additions & 0 deletions geolocator_apple/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## 2.3.8

* Uses different `CLLocationManager` instances, for one time request location and persistent request location.
* Fixes a bug where iOS location settings, e.g. `accuracy` and `distanceFilter` are overridden by different calls.
* Updates minimum deployment target to `iOS 11` as lower is not supported anymore by Xcode.

## 2.3.7

* Adds privacy manifest.
Expand Down
157 changes: 93 additions & 64 deletions geolocator_apple/example/ios/RunnerTests/GeolocationHandlerTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,18 @@ @interface GeolocationHandlerTests : XCTestCase

@implementation GeolocationHandlerTests {
CLLocationManager *_mockLocationManager;
CLLocationManager *_mockOneTimeLocationManager;

GeolocationHandler *_geolocationHandler;
}

- (void)setUp {
_mockLocationManager = OCMClassMock(CLLocationManager.class);
_mockOneTimeLocationManager = OCMClassMock(CLLocationManager.class);

_geolocationHandler = [[GeolocationHandler alloc] init];
[_geolocationHandler setLocationManagerOverride:_mockLocationManager];
[_geolocationHandler setOneTimeLocationManagerOverride:_mockOneTimeLocationManager];
}

#pragma mark - Test requesting current location
Expand All @@ -36,25 +40,25 @@ - (void)testGetCurrentPositionShouldCallStartUpdatingLocation {
resultHandler:^(CLLocation * _Nullable location) {}
errorHandler:^(NSString * _Nonnull errorCode, NSString * _Nonnull errorDescription) {}];

OCMVerify(times(1), [self->_mockLocationManager setDesiredAccuracy:kCLLocationAccuracyBest]);
OCMVerify(times(1), [self->_mockLocationManager startUpdatingLocation]);
OCMVerify(times(1), [self->_mockOneTimeLocationManager setDesiredAccuracy:kCLLocationAccuracyBest]);
OCMVerify(times(1), [self->_mockOneTimeLocationManager startUpdatingLocation]);
}

- (void)testRequestPositionShouldReturnLocationWithinTimeConstraints {
NSDate *now = [NSDate date];
NSCalendar *calendar = [NSCalendar currentCalendar];

CLLocation *firstLocation = [[CLLocation alloc] initWithCoordinate:CLLocationCoordinate2DMake(54.0, 6.4)
altitude:0.0
horizontalAccuracy:0
verticalAccuracy:0
timestamp:[calendar dateByAddingUnit:NSCalendarUnitSecond value:-6 toDate:now options:0]];
CLLocation *secondLocation = [[CLLocation alloc] initWithCoordinate:CLLocationCoordinate2DMake(54.1, 6.4)
altitude:0.0
horizontalAccuracy:0
verticalAccuracy:0
timestamp:now];

altitude:0.0
horizontalAccuracy:0
verticalAccuracy:0
timestamp:now];

XCTestExpectation *expectation = [self expectationWithDescription:@"expect result return third location"];
[_geolocationHandler requestPositionWithDesiredAccuracy:kCLLocationAccuracyBest
Expand All @@ -64,20 +68,20 @@ - (void)testRequestPositionShouldReturnLocationWithinTimeConstraints {
}
errorHandler:^(NSString * _Nonnull errorCode, NSString * _Nonnull errorDescription) {}];

[_geolocationHandler locationManager:_mockLocationManager didUpdateLocations: @[firstLocation]];
[_geolocationHandler locationManager:_mockLocationManager didUpdateLocations: @[secondLocation]];
[_geolocationHandler locationManager:_mockOneTimeLocationManager didUpdateLocations: @[firstLocation]];
[_geolocationHandler locationManager:_mockOneTimeLocationManager didUpdateLocations: @[secondLocation]];

[self waitForExpectationsWithTimeout:5.0 handler:nil];

OCMVerify(times(1), [self->_mockLocationManager stopUpdatingLocation]);
OCMVerify(times(1), [self->_mockOneTimeLocationManager stopUpdatingLocation]);
}

- (void)testRequestPositionShouldStopListeningOnResult {
CLLocation *location = [[CLLocation alloc] initWithCoordinate:CLLocationCoordinate2DMake(54.1, 6.4)
altitude:0.0
horizontalAccuracy:0
verticalAccuracy:0
timestamp:[NSDate date]];
altitude:0.0
horizontalAccuracy:0
verticalAccuracy:0
timestamp:[NSDate date]];

XCTestExpectation *expectation = [self expectationWithDescription:@"expect first result return third location"];
[_geolocationHandler requestPositionWithDesiredAccuracy:kCLLocationAccuracyBest
Expand All @@ -88,11 +92,11 @@ - (void)testRequestPositionShouldStopListeningOnResult {

}];

[_geolocationHandler locationManager:_mockLocationManager didUpdateLocations: @[location]];
[_geolocationHandler locationManager:_mockOneTimeLocationManager didUpdateLocations: @[location]];

[self waitForExpectationsWithTimeout:5.0 handler:nil];

OCMVerify(times(1), [self->_mockLocationManager stopUpdatingLocation]);
OCMVerify(times(1), [self->_mockOneTimeLocationManager stopUpdatingLocation]);
}

- (void)testRequestPositionShouldStopListeningOnError {
Expand All @@ -107,11 +111,11 @@ - (void)testRequestPositionShouldStopListeningOnError {

}];

[_geolocationHandler locationManager:_mockLocationManager didFailWithError: error];
[_geolocationHandler locationManager:_mockOneTimeLocationManager didFailWithError: error];

[self waitForExpectationsWithTimeout:5.0 handler:nil];

OCMVerify(times(1), [self->_mockLocationManager stopUpdatingLocation]);
OCMVerify(times(1), [self->_mockOneTimeLocationManager stopUpdatingLocation]);
}

- (void)testRequestPositionShouldNotStopListeningOnErrorDomainAndErrorLocationUnknown {
Expand Down Expand Up @@ -158,7 +162,7 @@ - (void)testStartListeningShouldNotStopListeningWhenListeningToStream {
- (void)testRequestingPositionWhileListeningDoesntStopStream {
CLLocation *mockLocation = [[CLLocation alloc] initWithLatitude:54.0 longitude:6.4];
XCTestExpectation *expectationStream = [self expectationWithDescription:@"expect result return third location"];
XCTestExpectation *expectationForeground = [self expectationWithDescription:@"expect result return third location"];
XCTestExpectation *expectationForeground = [self expectationWithDescription:@"expect result return third location"];
[_geolocationHandler startListeningWithDesiredAccuracy: kCLLocationAccuracyBest
distanceFilter:0
pauseLocationUpdatesAutomatically:NO
Expand All @@ -172,14 +176,14 @@ - (void)testRequestingPositionWhileListeningDoesntStopStream {
errorHandler:^(NSString * _Nonnull errorCode, NSString * _Nonnull errorDescription) {

}];

[_geolocationHandler requestPositionWithDesiredAccuracy:kCLLocationAccuracyHundredMeters
resultHandler:^(CLLocation * _Nullable location) {
XCTAssertEqual(location, mockLocation);
[expectationForeground fulfill];
} errorHandler:^(NSString * _Nonnull errorCode, NSString * _Nonnull errorDescription) {
}];
XCTAssertEqual(location, mockLocation);
[expectationForeground fulfill];
} errorHandler:^(NSString * _Nonnull errorCode, NSString * _Nonnull errorDescription) {

}];
[_geolocationHandler locationManager:_mockLocationManager didUpdateLocations: @[mockLocation]];

[self waitForExpectationsWithTimeout:5.0 handler:nil];
Expand Down Expand Up @@ -236,39 +240,39 @@ - (void)testStartListeningShouldNotReportErrorOnErrorDomainAndErrorLocationUnkno
}

- (void)testListeningBackgroundGeolocationOnlyWhenAllowedAndEnabled {
id geolocationHandlerMock = OCMPartialMock(_geolocationHandler);
[geolocationHandlerMock setLocationManagerOverride:_mockLocationManager];
OCMStub(ClassMethod([geolocationHandlerMock shouldEnableBackgroundLocationUpdates]))._andReturn([NSNumber numberWithBool:YES]);
[geolocationHandlerMock startListeningWithDesiredAccuracy: kCLLocationAccuracyBest
distanceFilter:0
pauseLocationUpdatesAutomatically:NO
showBackgroundLocationIndicator:NO
activityType:CLActivityTypeOther
allowBackgroundLocationUpdates:YES
resultHandler:^(CLLocation * _Nullable location) {
}
errorHandler:^(NSString * _Nonnull errorCode, NSString * _Nonnull errorDescription) {
}];
OCMVerify([_mockLocationManager setAllowsBackgroundLocationUpdates:YES]);
id geolocationHandlerMock = OCMPartialMock(_geolocationHandler);
[geolocationHandlerMock setLocationManagerOverride:_mockLocationManager];
OCMStub(ClassMethod([geolocationHandlerMock shouldEnableBackgroundLocationUpdates]))._andReturn([NSNumber numberWithBool:YES]);
[geolocationHandlerMock startListeningWithDesiredAccuracy: kCLLocationAccuracyBest
distanceFilter:0
pauseLocationUpdatesAutomatically:NO
showBackgroundLocationIndicator:NO
activityType:CLActivityTypeOther
allowBackgroundLocationUpdates:YES
resultHandler:^(CLLocation * _Nullable location) {
}
errorHandler:^(NSString * _Nonnull errorCode, NSString * _Nonnull errorDescription) {

}];
OCMVerify([_mockLocationManager setAllowsBackgroundLocationUpdates:YES]);
}

- (void)testNotListeningBackgroundGeolocationWhenNotEnabled {
id geolocationHandlerMock = OCMPartialMock(_geolocationHandler);
[geolocationHandlerMock setLocationManagerOverride:_mockLocationManager];
OCMStub(ClassMethod([geolocationHandlerMock shouldEnableBackgroundLocationUpdates]))._andReturn([NSNumber numberWithBool:YES]);
[geolocationHandlerMock startListeningWithDesiredAccuracy: kCLLocationAccuracyBest
distanceFilter:0
pauseLocationUpdatesAutomatically:NO
showBackgroundLocationIndicator:NO
activityType:CLActivityTypeOther
allowBackgroundLocationUpdates:NO
resultHandler:^(CLLocation * _Nullable location) {
}
errorHandler:^(NSString * _Nonnull errorCode, NSString * _Nonnull errorDescription) {
}];
OCMVerify(never(), [_mockLocationManager setAllowsBackgroundLocationUpdates:YES]);
id geolocationHandlerMock = OCMPartialMock(_geolocationHandler);
[geolocationHandlerMock setLocationManagerOverride:_mockLocationManager];
OCMStub(ClassMethod([geolocationHandlerMock shouldEnableBackgroundLocationUpdates]))._andReturn([NSNumber numberWithBool:YES]);
[geolocationHandlerMock startListeningWithDesiredAccuracy: kCLLocationAccuracyBest
distanceFilter:0
pauseLocationUpdatesAutomatically:NO
showBackgroundLocationIndicator:NO
activityType:CLActivityTypeOther
allowBackgroundLocationUpdates:NO
resultHandler:^(CLLocation * _Nullable location) {
}
errorHandler:^(NSString * _Nonnull errorCode, NSString * _Nonnull errorDescription) {

}];
OCMVerify(never(), [_mockLocationManager setAllowsBackgroundLocationUpdates:YES]);
}

- (void)testKeepLocationManagerSettingsWhenRequestingCurrentPosition {
Expand All @@ -283,14 +287,14 @@ - (void)testKeepLocationManagerSettingsWhenRequestingCurrentPosition {
._andReturn([NSNumber numberWithBool:YES]);
}
[geolocationHandlerMock startListeningWithDesiredAccuracy: kCLLocationAccuracyBest
distanceFilter:0
pauseLocationUpdatesAutomatically:NO
showBackgroundLocationIndicator:YES
activityType:CLActivityTypeOther
allowBackgroundLocationUpdates:YES
resultHandler:^(CLLocation * _Nullable location) {
distanceFilter:0
pauseLocationUpdatesAutomatically:NO
showBackgroundLocationIndicator:YES
activityType:CLActivityTypeOther
allowBackgroundLocationUpdates:YES
resultHandler:^(CLLocation * _Nullable location) {
}
errorHandler:^(NSString * _Nonnull errorCode, NSString * _Nonnull errorDescription) {
errorHandler:^(NSString * _Nonnull errorCode, NSString * _Nonnull errorDescription) {

}];
OCMVerify([_mockLocationManager setAllowsBackgroundLocationUpdates:YES]);
Expand All @@ -306,4 +310,29 @@ - (void)testKeepLocationManagerSettingsWhenRequestingCurrentPosition {
}
}

- (void)testKeepLocationManagerSettingsWhenRequestingCurrentPosition1 {
[_geolocationHandler startListeningWithDesiredAccuracy:kCLLocationAccuracyThreeKilometers
distanceFilter:kCLLocationAccuracyThreeKilometers
pauseLocationUpdatesAutomatically:NO
showBackgroundLocationIndicator:YES
activityType:CLActivityTypeOther
allowBackgroundLocationUpdates:YES
resultHandler:^(CLLocation * _Nullable location) {
}
errorHandler:^(NSString * _Nonnull errorCode, NSString * _Nonnull errorDescription) {

}];
OCMVerify([_mockLocationManager setDesiredAccuracy:kCLLocationAccuracyThreeKilometers]);
OCMVerify([_mockLocationManager setDistanceFilter:kCLLocationAccuracyThreeKilometers]);

[_geolocationHandler requestPositionWithDesiredAccuracy:kCLLocationAccuracyBest
resultHandler:^(CLLocation * _Nullable location) {}
errorHandler:^(NSString * _Nonnull errorCode, NSString * _Nonnull errorDescription) {}];
OCMVerify([_mockOneTimeLocationManager setDesiredAccuracy:kCLLocationAccuracyBest]);
OCMVerify([_mockOneTimeLocationManager setDistanceFilter:kCLDistanceFilterNone]);

OCMVerify(never(), [_mockLocationManager setDesiredAccuracy:kCLLocationAccuracyBest]);
OCMVerify(never(), [_mockLocationManager setDistanceFilter:kCLDistanceFilterNone]);
}

@end
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ - (void)testOpenAppSettings {

if (@available(iOS 8, *)) {
id mockApplication = OCMClassMock([UIApplication class]);
OCMStub([mockApplication openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]]).andReturn(YES);
OCMStub([(UIApplication *)mockApplication openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]]).andReturn(YES);
OCMStub(ClassMethod([mockApplication sharedApplication])).andReturn(mockApplication);


Expand Down Expand Up @@ -394,7 +394,7 @@ - (void)testOpenLocationSettings {

if (@available(iOS 8, *)) {
id mockApplication = OCMClassMock([UIApplication class]);
OCMStub([mockApplication openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]]).andReturn(YES);
OCMStub([(UIApplication *)mockApplication openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]]).andReturn(YES);
OCMStub(ClassMethod([mockApplication sharedApplication])).andReturn(mockApplication);


Expand Down
Loading

0 comments on commit 6a226c8

Please sign in to comment.