Use Apple's significant-change API (for iOS 11 UX)
Summary: In the yet-to-be-released iOS 11, Apple has changed the way they notify the user of location services. (You can watch their session from WWDC about all the changes [here](https://developer.apple.com/videos/play/wwdc2017/713/).) The current implementation of `RCTLocationObserver` uses the standard location services from Apple. When the user has granted `Always` location permission and the application uses the background location service, the user is presented with the *_Blue Bar of Shame_* (for more information check out [this blog post](https://blog.set.gl/ios-11-location-permissions-and-avoiding-the-blue-bar-of-shame-1cee6cd93bbe)): ![image](https://user-images.githubusercontent.com/15896334/28285133-281e425c-6af9-11e7-9177-61b879ab593c.png) * Added `useSignificantChanges` boolean to the options passed. * Added `_usingSignificantChanges` boolean based on user options. If `true`, then the CLLocationManager will use functions `startMonitoringSignificantLocationChanges`/ `stopMonitoringSignificantLocationChanges` rather than the standard location services. * Changed method signature of `beginLocationUpdatesWithDesiredAccuracy` to include `useSignificantChanges` flag * Added check for new `NSLocationAlwaysAndWhenInUseUsageDescription` All unit tests passed. Tested in simulator and on device, toggling `useSignificantChanges` option when calling `watchPosition`. Results were as expected. **When `TRUE`, the _Blue Bar of Shame_ was not present.** Changes do not affect Android and location services still work as expected on Android. * Change is for iOS only * Using a different API will have different accuracy results. Adding `useSignificantChanges` as an option was by design so apps that want to have most accurate and most frequent update can still use standard location services. Closes https://github.com/facebook/react-native/pull/15062 Differential Revision: D5443331 Pulled By: javache fbshipit-source-id: 0cf5b6cd831c5a7c8c25a5ddc2e410a9aa989bf4
This commit is contained in:
parent
64899c08f3
commit
f7043699b0
|
@ -27,10 +27,11 @@ var subscriptions = [];
|
|||
var updatesEnabled = false;
|
||||
|
||||
type GeoOptions = {
|
||||
timeout: number,
|
||||
maximumAge: number,
|
||||
enableHighAccuracy: bool,
|
||||
timeout?: number,
|
||||
maximumAge?: number,
|
||||
enableHighAccuracy?: bool,
|
||||
distanceFilter: number,
|
||||
useSignificantChanges?: bool,
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -124,7 +125,7 @@ var Geolocation = {
|
|||
|
||||
/*
|
||||
* Invokes the success callback whenever the location changes. Supported
|
||||
* options: timeout (ms), maximumAge (ms), enableHighAccuracy (bool), distanceFilter(m)
|
||||
* options: timeout (ms), maximumAge (ms), enableHighAccuracy (bool), distanceFilter(m), useSignificantChanges (bool)
|
||||
*/
|
||||
watchPosition: function(success: Function, error?: Function, options?: GeoOptions): number {
|
||||
if (!updatesEnabled) {
|
||||
|
|
|
@ -32,6 +32,7 @@ typedef struct {
|
|||
double maximumAge;
|
||||
double accuracy;
|
||||
double distanceFilter;
|
||||
BOOL useSignificantChanges;
|
||||
} RCTLocationOptions;
|
||||
|
||||
@implementation RCTConvert (RCTLocationOptions)
|
||||
|
@ -47,7 +48,8 @@ typedef struct {
|
|||
.timeout = [RCTConvert NSTimeInterval:options[@"timeout"]] ?: INFINITY,
|
||||
.maximumAge = [RCTConvert NSTimeInterval:options[@"maximumAge"]] ?: INFINITY,
|
||||
.accuracy = [RCTConvert BOOL:options[@"enableHighAccuracy"]] ? kCLLocationAccuracyBest : RCT_DEFAULT_LOCATION_ACCURACY,
|
||||
.distanceFilter = distanceFilter
|
||||
.distanceFilter = distanceFilter,
|
||||
.useSignificantChanges = [RCTConvert BOOL:options[@"useSignificantChanges"]] ?: NO,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -108,6 +110,7 @@ static NSDictionary<NSString *, id> *RCTPositionError(RCTPositionErrorCode code,
|
|||
NSDictionary<NSString *, id> *_lastLocationEvent;
|
||||
NSMutableArray<RCTLocationRequest *> *_pendingRequests;
|
||||
BOOL _observingLocation;
|
||||
BOOL _usingSignificantChanges;
|
||||
RCTLocationOptions _observerOptions;
|
||||
}
|
||||
|
||||
|
@ -117,7 +120,10 @@ RCT_EXPORT_MODULE()
|
|||
|
||||
- (void)dealloc
|
||||
{
|
||||
[_locationManager stopUpdatingLocation];
|
||||
_usingSignificantChanges ?
|
||||
[_locationManager stopMonitoringSignificantLocationChanges] :
|
||||
[_locationManager stopUpdatingLocation];
|
||||
|
||||
_locationManager.delegate = nil;
|
||||
}
|
||||
|
||||
|
@ -133,14 +139,18 @@ RCT_EXPORT_MODULE()
|
|||
|
||||
#pragma mark - Private API
|
||||
|
||||
- (void)beginLocationUpdatesWithDesiredAccuracy:(CLLocationAccuracy)desiredAccuracy distanceFilter:(CLLocationDistance)distanceFilter
|
||||
- (void)beginLocationUpdatesWithDesiredAccuracy:(CLLocationAccuracy)desiredAccuracy distanceFilter:(CLLocationDistance)distanceFilter useSignificantChanges:(BOOL)useSignificantChanges
|
||||
{
|
||||
[self requestAuthorization];
|
||||
|
||||
_locationManager.distanceFilter = distanceFilter;
|
||||
_locationManager.desiredAccuracy = desiredAccuracy;
|
||||
_usingSignificantChanges = useSignificantChanges;
|
||||
|
||||
// Start observing location
|
||||
[_locationManager startUpdatingLocation];
|
||||
_usingSignificantChanges ?
|
||||
[_locationManager startMonitoringSignificantLocationChanges] :
|
||||
[_locationManager startUpdatingLocation];
|
||||
}
|
||||
|
||||
#pragma mark - Timeout handler
|
||||
|
@ -154,7 +164,9 @@ RCT_EXPORT_MODULE()
|
|||
|
||||
// Stop updating if no pending requests
|
||||
if (_pendingRequests.count == 0 && !_observingLocation) {
|
||||
[_locationManager stopUpdatingLocation];
|
||||
_usingSignificantChanges ?
|
||||
[_locationManager stopMonitoringSignificantLocationChanges] :
|
||||
[_locationManager stopUpdatingLocation];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -195,7 +207,9 @@ RCT_EXPORT_METHOD(startObserving:(RCTLocationOptions)options)
|
|||
_observerOptions.accuracy = MIN(_observerOptions.accuracy, request.options.accuracy);
|
||||
}
|
||||
|
||||
[self beginLocationUpdatesWithDesiredAccuracy:_observerOptions.accuracy distanceFilter:_observerOptions.distanceFilter];
|
||||
[self beginLocationUpdatesWithDesiredAccuracy:_observerOptions.accuracy
|
||||
distanceFilter:_observerOptions.distanceFilter
|
||||
useSignificantChanges:_observerOptions.useSignificantChanges];
|
||||
_observingLocation = YES;
|
||||
}
|
||||
|
||||
|
@ -206,7 +220,9 @@ RCT_EXPORT_METHOD(stopObserving)
|
|||
|
||||
// Stop updating if no pending requests
|
||||
if (_pendingRequests.count == 0) {
|
||||
[_locationManager stopUpdatingLocation];
|
||||
_usingSignificantChanges ?
|
||||
[_locationManager stopMonitoringSignificantLocationChanges] :
|
||||
[_locationManager stopUpdatingLocation];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -269,7 +285,9 @@ RCT_EXPORT_METHOD(getCurrentPosition:(RCTLocationOptions)options
|
|||
if (_locationManager) {
|
||||
accuracy = MIN(_locationManager.desiredAccuracy, accuracy);
|
||||
}
|
||||
[self beginLocationUpdatesWithDesiredAccuracy:accuracy distanceFilter:options.distanceFilter];
|
||||
[self beginLocationUpdatesWithDesiredAccuracy:accuracy
|
||||
distanceFilter:options.distanceFilter
|
||||
useSignificantChanges:options.useSignificantChanges];
|
||||
}
|
||||
|
||||
#pragma mark - CLLocationManagerDelegate
|
||||
|
@ -306,7 +324,9 @@ RCT_EXPORT_METHOD(getCurrentPosition:(RCTLocationOptions)options
|
|||
|
||||
// Stop updating if not observing
|
||||
if (!_observingLocation) {
|
||||
[_locationManager stopUpdatingLocation];
|
||||
_usingSignificantChanges ?
|
||||
[_locationManager stopMonitoringSignificantLocationChanges] :
|
||||
[_locationManager stopUpdatingLocation];
|
||||
}
|
||||
|
||||
// Reset location accuracy if desiredAccuracy is changed.
|
||||
|
@ -356,8 +376,9 @@ static void checkLocationConfig()
|
|||
{
|
||||
#if RCT_DEV
|
||||
if (!([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"] ||
|
||||
[[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"])) {
|
||||
RCTLogError(@"Either NSLocationWhenInUseUsageDescription or NSLocationAlwaysUsageDescription key must be present in Info.plist to use geolocation.");
|
||||
[[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"] ||
|
||||
[[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysAndWhenInUseUsageDescription"])) {
|
||||
RCTLogError(@"Either NSLocationWhenInUseUsageDescription or NSLocationAlwaysUsageDescription or NSLocationAlwaysAndWhenInUseUsageDescription key must be present in Info.plist to use geolocation.");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue