Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion Libraries/Geolocation/Geolocation.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ type GeoOptions = {
maximumAge: number,
enableHighAccuracy: bool,
distanceFilter: number,
locationAuthorizationIOS: string,
}

/**

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

null: Parsing error: Unexpected token, expected ;

188 | };
189 |

190 | Geolocation.IOS_AUTHORIZATIONS: Object = {};
| ^
191 | Geolocation.IOS_AUTHORIZATIONS.WHEN_IN_USE = 'locationAuthorizationWhenInUse';
192 | Geolocation.IOS_AUTHORIZATIONS.ALWAYS = 'locationAuthorizationAlways';
193 |

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unexpected token :

Expand Down Expand Up @@ -73,7 +74,10 @@ type GeoOptions = {
*
*/
var Geolocation = {

IOS_AUTHORIZATIONS: Object = {
WHEN_IN_USE: 'locationAuthorizationWhenInUse',
ALWAYS: 'locationAuthorizationAlways',
},
/*
* Request suitable Location permission based on the key configured on pList.
* If NSLocationAlwaysUsageDescription is set, it will request Always authorization,
Expand Down
125 changes: 93 additions & 32 deletions Libraries/Geolocation/RCTLocationObserver.m
Original file line number Diff line number Diff line change
Expand Up @@ -25,29 +25,58 @@ typedef NS_ENUM(NSInteger, RCTPositionErrorCode) {
RCTPositionErrorTimeout,
};

typedef NS_ENUM(NSInteger, RCTLocationAuthorizationCode) {
RCTLocationAuthorizationUnknown = 1,
RCTLocationAuthorizationWhenInUse,
RCTLocationAuthorizationAlways,
};

#define RCT_DEFAULT_LOCATION_ACCURACY kCLLocationAccuracyHundredMeters

typedef struct {
double timeout;
double maximumAge;
double accuracy;
double distanceFilter;
RCTLocationAuthorizationCode locationAuthorization;
} RCTLocationOptions;

@implementation RCTConvert (RCTLocationAuthorizationCode)

RCT_ENUM_CONVERTER(
RCTLocationAuthorizationCode,
(
@{
@"locationAuthorizationUnknown" : @(RCTLocationAuthorizationUnknown),
@"locationAuthorizationWhenInUse" : @(RCTLocationAuthorizationWhenInUse),
@"locationAuthorizationAlways" : @(RCTLocationAuthorizationAlways)
}
),
RCTLocationAuthorizationUnknown,
integerValue
)

@end


@implementation RCTConvert (RCTLocationOptions)

+ (RCTLocationOptions)RCTLocationOptions:(id)json
{
NSDictionary<NSString *, id> *options = [RCTConvert NSDictionary:json];

double distanceFilter = options[@"distanceFilter"] == NULL ? RCT_DEFAULT_LOCATION_ACCURACY
: [RCTConvert double:options[@"distanceFilter"]] ?: kCLDistanceFilterNone;


RCTLocationAuthorizationCode locationAuthorization = options[@"locationAuthorizationIOS"] == NULL ? RCTLocationAuthorizationUnknown
: [RCTConvert RCTLocationAuthorizationCode:options[@"locationAuthorizationIOS"]] ?: RCTLocationAuthorizationUnknown;

return (RCTLocationOptions){
.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,
.locationAuthorization = locationAuthorization
};
}

Expand Down Expand Up @@ -133,16 +162,64 @@ - (dispatch_queue_t)methodQueue

#pragma mark - Private API

- (void)beginLocationUpdatesWithDesiredAccuracy:(CLLocationAccuracy)desiredAccuracy distanceFilter:(CLLocationDistance)distanceFilter
- (void)beginLocationUpdatesWithDesiredAccuracy:(CLLocationAccuracy)desiredAccuracy
distanceFilter:(CLLocationDistance)distanceFilter
locationAuthorization:(RCTLocationAuthorizationCode)locationAuthorization
{
[self requestAuthorization];

[self requestSpecificAuthorization:locationAuthorization];
_locationManager.distanceFilter = distanceFilter;
_locationManager.desiredAccuracy = desiredAccuracy;
// Start observing location
[_locationManager startUpdatingLocation];
}

- (void) requestAlwaysAuthorizationHelper:(CLLocationManager*)locationManager
{
[locationManager requestAlwaysAuthorization];

// On iOS 9+ we also need to enable background updates
NSArray *backgroundModes = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIBackgroundModes"];
if(backgroundModes && [backgroundModes containsObject:@"location"]) {
if([locationManager respondsToSelector:@selector(setAllowsBackgroundLocationUpdates:)]) {
[locationManager setAllowsBackgroundLocationUpdates:YES];
}
}
}

- (void) requestSpecificAuthorization:(RCTLocationAuthorizationCode)locationAuthorization
{
if (!_locationManager) {
_locationManager = [CLLocationManager new];
_locationManager.delegate = self;
}

// Request location access permission
// If locationAuthorization option is provided, request that specific permission
// Otherwise, fall back to requesting based on the Info.plist
switch (locationAuthorization) {
case RCTLocationAuthorizationAlways:
if ([_locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) {
[self requestAlwaysAuthorizationHelper:_locationManager];
}
break;
case RCTLocationAuthorizationWhenInUse:
if ([_locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
[_locationManager requestWhenInUseAuthorization];
}
break;
case RCTLocationAuthorizationUnknown:
if ([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"] &&
[_locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) {
[self requestAlwaysAuthorizationHelper:_locationManager];
} else if ([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"] &&
[_locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
[_locationManager requestWhenInUseAuthorization];
}
break;
}
}

#pragma mark - Timeout handler

- (void)timeout:(NSTimer *)timer
Expand All @@ -162,40 +239,22 @@ - (void)timeout:(NSTimer *)timer

RCT_EXPORT_METHOD(requestAuthorization)
{
if (!_locationManager) {
_locationManager = [CLLocationManager new];
_locationManager.delegate = self;
}

// Request location access permission
if ([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"] &&
[_locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) {
[_locationManager requestAlwaysAuthorization];

// On iOS 9+ we also need to enable background updates
NSArray *backgroundModes = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIBackgroundModes"];
if (backgroundModes && [backgroundModes containsObject:@"location"]) {
if ([_locationManager respondsToSelector:@selector(setAllowsBackgroundLocationUpdates:)]) {
[_locationManager setAllowsBackgroundLocationUpdates:YES];
}
}
} else if ([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"] &&
[_locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
[_locationManager requestWhenInUseAuthorization];
}
[self requestSpecificAuthorization:RCTLocationAuthorizationUnknown];
}

RCT_EXPORT_METHOD(startObserving:(RCTLocationOptions)options)
{
checkLocationConfig();

// Select best options
_observerOptions = options;
for (RCTLocationRequest *request in _pendingRequests) {
_observerOptions.accuracy = MIN(_observerOptions.accuracy, request.options.accuracy);
}

[self beginLocationUpdatesWithDesiredAccuracy:_observerOptions.accuracy distanceFilter:_observerOptions.distanceFilter];

[self beginLocationUpdatesWithDesiredAccuracy:_observerOptions.accuracy
distanceFilter:_observerOptions.distanceFilter
locationAuthorization:_observerOptions.locationAuthorization];
_observingLocation = YES;
}

Expand Down Expand Up @@ -263,13 +322,15 @@ - (void)timeout:(NSTimer *)timer
_pendingRequests = [NSMutableArray new];
}
[_pendingRequests addObject:request];

// Configure location manager and begin updating location
CLLocationAccuracy accuracy = options.accuracy;
if (_locationManager) {
accuracy = MIN(_locationManager.desiredAccuracy, accuracy);
}
[self beginLocationUpdatesWithDesiredAccuracy:accuracy distanceFilter:options.distanceFilter];
[self beginLocationUpdatesWithDesiredAccuracy:accuracy
distanceFilter:options.distanceFilter
locationAuthorization:options.locationAuthorization];
}

#pragma mark - CLLocationManagerDelegate
Expand Down