yeet
This commit is contained in:
14
node_modules/expo-location/ios/EXLocation/TaskConsumers/EXGeofencingTaskConsumer.h
generated
vendored
Normal file
14
node_modules/expo-location/ios/EXLocation/TaskConsumers/EXGeofencingTaskConsumer.h
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
// Copyright 2018-present 650 Industries. All rights reserved.
|
||||
|
||||
#import <CoreLocation/CLLocationManagerDelegate.h>
|
||||
#import <UMTaskManagerInterface/UMTaskConsumerInterface.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface EXGeofencingTaskConsumer : NSObject <UMTaskConsumerInterface, CLLocationManagerDelegate>
|
||||
|
||||
@property (nonatomic, strong) id<UMTaskInterface> task;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
215
node_modules/expo-location/ios/EXLocation/TaskConsumers/EXGeofencingTaskConsumer.m
generated
vendored
Normal file
215
node_modules/expo-location/ios/EXLocation/TaskConsumers/EXGeofencingTaskConsumer.m
generated
vendored
Normal file
@ -0,0 +1,215 @@
|
||||
// Copyright 2018-present 650 Industries. All rights reserved.
|
||||
|
||||
#import <CoreLocation/CLCircularRegion.h>
|
||||
#import <CoreLocation/CLLocationManager.h>
|
||||
#import <CoreLocation/CLErrorDomain.h>
|
||||
|
||||
#import <UMCore/UMUtilities.h>
|
||||
#import <EXLocation/EXLocation.h>
|
||||
#import <EXLocation/EXGeofencingTaskConsumer.h>
|
||||
#import <UMTaskManagerInterface/UMTaskInterface.h>
|
||||
|
||||
@interface EXGeofencingTaskConsumer ()
|
||||
|
||||
@property (nonatomic, strong) CLLocationManager *locationManager;
|
||||
@property (nonatomic, strong) NSMutableDictionary<NSString *, NSNumber *> *regionStates;
|
||||
@property (nonatomic, assign) BOOL backgroundOnly;
|
||||
|
||||
@end
|
||||
|
||||
@implementation EXGeofencingTaskConsumer
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[self reset];
|
||||
}
|
||||
|
||||
# pragma mark - UMTaskConsumerInterface
|
||||
|
||||
- (NSString *)taskType
|
||||
{
|
||||
return @"geofencing";
|
||||
}
|
||||
|
||||
- (void)setOptions:(nonnull NSDictionary *)options
|
||||
{
|
||||
[self stopMonitoringAllRegions];
|
||||
[self startMonitoringRegionsForTask:self->_task];
|
||||
}
|
||||
|
||||
- (void)didRegisterTask:(id<UMTaskInterface>)task
|
||||
{
|
||||
[self startMonitoringRegionsForTask:task];
|
||||
}
|
||||
|
||||
- (void)didUnregister
|
||||
{
|
||||
[self reset];
|
||||
}
|
||||
|
||||
# pragma mark - helpers
|
||||
|
||||
- (void)reset
|
||||
{
|
||||
[self stopMonitoringAllRegions];
|
||||
[UMUtilities performSynchronouslyOnMainThread:^{
|
||||
self->_locationManager = nil;
|
||||
self->_task = nil;
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)startMonitoringRegionsForTask:(id<UMTaskInterface>)task
|
||||
{
|
||||
[UMUtilities performSynchronouslyOnMainThread:^{
|
||||
CLLocationManager *locationManager = [CLLocationManager new];
|
||||
NSMutableDictionary *regionStates = [NSMutableDictionary new];
|
||||
NSDictionary *options = [task options];
|
||||
NSArray *regions = options[@"regions"];
|
||||
|
||||
self->_task = task;
|
||||
self->_locationManager = locationManager;
|
||||
self->_regionStates = regionStates;
|
||||
|
||||
locationManager.delegate = self;
|
||||
locationManager.allowsBackgroundLocationUpdates = YES;
|
||||
locationManager.pausesLocationUpdatesAutomatically = NO;
|
||||
|
||||
for (NSDictionary *regionDict in regions) {
|
||||
NSString *identifier = regionDict[@"identifier"] ?: [[NSUUID UUID] UUIDString];
|
||||
CLLocationDistance radius = [regionDict[@"radius"] doubleValue];
|
||||
CLLocationCoordinate2D center = [self.class coordinateFromDictionary:regionDict];
|
||||
BOOL notifyOnEntry = [self.class boolValueFrom:regionDict[@"notifyOnEntry"] defaultValue:YES];
|
||||
BOOL notifyOnExit = [self.class boolValueFrom:regionDict[@"notifyOnExit"] defaultValue:YES];
|
||||
|
||||
CLCircularRegion *region = [[CLCircularRegion alloc] initWithCenter:center radius:radius identifier:identifier];
|
||||
|
||||
region.notifyOnEntry = notifyOnEntry;
|
||||
region.notifyOnExit = notifyOnExit;
|
||||
|
||||
[regionStates setObject:@(CLRegionStateUnknown) forKey:identifier];
|
||||
[locationManager startMonitoringForRegion:region];
|
||||
[locationManager requestStateForRegion:region];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)stopMonitoringAllRegions
|
||||
{
|
||||
[UMUtilities performSynchronouslyOnMainThread:^{
|
||||
for (CLRegion *region in self->_locationManager.monitoredRegions) {
|
||||
[self->_locationManager stopMonitoringForRegion:region];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)executeTaskWithRegion:(nonnull CLRegion *)region eventType:(EXGeofencingEventType)eventType
|
||||
{
|
||||
if ([region isKindOfClass:[CLCircularRegion class]]) {
|
||||
CLCircularRegion *circularRegion = (CLCircularRegion *)region;
|
||||
CLRegionState regionState = [self regionStateForIdentifier:circularRegion.identifier];
|
||||
NSDictionary *data = @{
|
||||
@"eventType": @(eventType),
|
||||
@"region": [[self class] exportRegion:circularRegion withState:regionState],
|
||||
};
|
||||
|
||||
[_task executeWithData:data withError:nil];
|
||||
}
|
||||
}
|
||||
|
||||
# pragma mark - CLLocationManagerDelegate
|
||||
|
||||
// There is a bug in iOS that causes didEnterRegion and didExitRegion to be called multiple times.
|
||||
// https://stackoverflow.com/questions/36807060/region-monitoring-method-getting-called-multiple-times-in-geo-fencing
|
||||
// To prevent this behavior, we execute tasks only when the state has changed.
|
||||
|
||||
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
|
||||
{
|
||||
if ([self regionStateForIdentifier:region.identifier] != CLRegionStateInside) {
|
||||
[self setRegionState:CLRegionStateInside forIdentifier:region.identifier];
|
||||
[self executeTaskWithRegion:region eventType:EXGeofencingEventTypeEnter];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
|
||||
{
|
||||
if ([self regionStateForIdentifier:region.identifier] != CLRegionStateOutside) {
|
||||
[self setRegionState:CLRegionStateOutside forIdentifier:region.identifier];
|
||||
[self executeTaskWithRegion:region eventType:EXGeofencingEventTypeExit];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
|
||||
{
|
||||
[_task executeWithData:nil withError:error];
|
||||
}
|
||||
|
||||
- (void)locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(CLRegion *)region withError:(NSError *)error
|
||||
{
|
||||
if (error && error.domain == kCLErrorDomain) {
|
||||
// This error might happen when the device is not able to find out the location. Try to restart monitoring this region.
|
||||
[_locationManager stopMonitoringForRegion:region];
|
||||
[_locationManager startMonitoringForRegion:region];
|
||||
[_locationManager requestStateForRegion:region];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region
|
||||
{
|
||||
if ([self regionStateForIdentifier:region.identifier] != state) {
|
||||
EXGeofencingEventType eventType = state == CLRegionStateInside ? EXGeofencingEventTypeEnter : EXGeofencingEventTypeExit;
|
||||
|
||||
[self setRegionState:state forIdentifier:region.identifier];
|
||||
[self executeTaskWithRegion:region eventType:eventType];
|
||||
}
|
||||
}
|
||||
|
||||
# pragma mark - helpers
|
||||
|
||||
- (CLRegionState)regionStateForIdentifier:(NSString *)identifier
|
||||
{
|
||||
return [_regionStates[identifier] integerValue];
|
||||
}
|
||||
|
||||
- (void)setRegionState:(CLRegionState)regionState forIdentifier:(NSString *)identifier
|
||||
{
|
||||
[_regionStates setObject:@(regionState) forKey:identifier];
|
||||
}
|
||||
|
||||
# pragma mark - static helpers
|
||||
|
||||
+ (nonnull NSDictionary *)exportRegion:(nonnull CLCircularRegion *)region withState:(CLRegionState)regionState
|
||||
{
|
||||
return @{
|
||||
@"identifier": region.identifier,
|
||||
@"state": @([self exportRegionState:regionState]),
|
||||
@"radius": @(region.radius),
|
||||
@"latitude": @(region.center.latitude),
|
||||
@"longitude": @(region.center.longitude),
|
||||
};
|
||||
}
|
||||
|
||||
+ (EXGeofencingRegionState)exportRegionState:(CLRegionState)regionState
|
||||
{
|
||||
switch (regionState) {
|
||||
case CLRegionStateUnknown:
|
||||
return EXGeofencingRegionStateUnknown;
|
||||
case CLRegionStateInside:
|
||||
return EXGeofencingRegionStateInside;
|
||||
case CLRegionStateOutside:
|
||||
return EXGeofencingRegionStateOutside;
|
||||
}
|
||||
}
|
||||
|
||||
+ (CLLocationCoordinate2D)coordinateFromDictionary:(nonnull NSDictionary *)dict
|
||||
{
|
||||
CLLocationDegrees latitude = [dict[@"latitude"] doubleValue];
|
||||
CLLocationDegrees longitude = [dict[@"longitude"] doubleValue];
|
||||
return CLLocationCoordinate2DMake(latitude, longitude);
|
||||
}
|
||||
|
||||
+ (BOOL)boolValueFrom:(id)pointer defaultValue:(BOOL)defaultValue
|
||||
{
|
||||
return pointer == nil ? defaultValue : [pointer boolValue];
|
||||
}
|
||||
|
||||
@end
|
14
node_modules/expo-location/ios/EXLocation/TaskConsumers/EXLocationTaskConsumer.h
generated
vendored
Normal file
14
node_modules/expo-location/ios/EXLocation/TaskConsumers/EXLocationTaskConsumer.h
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
// Copyright 2018-present 650 Industries. All rights reserved.
|
||||
|
||||
#import <CoreLocation/CLLocationManagerDelegate.h>
|
||||
#import <UMTaskManagerInterface/UMTaskConsumerInterface.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface EXLocationTaskConsumer : NSObject <UMTaskConsumerInterface, CLLocationManagerDelegate>
|
||||
|
||||
@property (nonatomic, strong) id<UMTaskInterface> task;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
190
node_modules/expo-location/ios/EXLocation/TaskConsumers/EXLocationTaskConsumer.m
generated
vendored
Normal file
190
node_modules/expo-location/ios/EXLocation/TaskConsumers/EXLocationTaskConsumer.m
generated
vendored
Normal file
@ -0,0 +1,190 @@
|
||||
// Copyright 2018-present 650 Industries. All rights reserved.
|
||||
|
||||
#import <CoreLocation/CLLocationManager.h>
|
||||
#import <CoreLocation/CLErrorDomain.h>
|
||||
|
||||
#import <UMCore/UMUtilities.h>
|
||||
#import <EXLocation/EXLocation.h>
|
||||
#import <EXLocation/EXLocationTaskConsumer.h>
|
||||
#import <UMTaskManagerInterface/UMTaskInterface.h>
|
||||
|
||||
@interface EXLocationTaskConsumer ()
|
||||
|
||||
@property (nonatomic, strong) CLLocationManager *locationManager;
|
||||
@property (nonatomic, strong) NSMutableArray<CLLocation *> *deferredLocations;
|
||||
@property (nonatomic, strong) CLLocation *lastReportedLocation;
|
||||
@property (nonatomic, assign) CLLocationDistance deferredDistance;
|
||||
|
||||
@end
|
||||
|
||||
@implementation EXLocationTaskConsumer
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if (self = [super init]) {
|
||||
_deferredLocations = [NSMutableArray new];
|
||||
_deferredDistance = 0.0;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[self reset];
|
||||
}
|
||||
|
||||
# pragma mark - UMTaskConsumerInterface
|
||||
|
||||
- (NSString *)taskType
|
||||
{
|
||||
return @"location";
|
||||
}
|
||||
|
||||
- (void)didRegisterTask:(id<UMTaskInterface>)task
|
||||
{
|
||||
[UMUtilities performSynchronouslyOnMainThread:^{
|
||||
CLLocationManager *locationManager = [CLLocationManager new];
|
||||
|
||||
self->_task = task;
|
||||
self->_locationManager = locationManager;
|
||||
|
||||
locationManager.delegate = self;
|
||||
locationManager.allowsBackgroundLocationUpdates = YES;
|
||||
|
||||
// Set options-specific things in location manager.
|
||||
[self setOptions:task.options];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)didUnregister
|
||||
{
|
||||
[self reset];
|
||||
}
|
||||
|
||||
- (void)setOptions:(NSDictionary *)options
|
||||
{
|
||||
[UMUtilities performSynchronouslyOnMainThread:^{
|
||||
CLLocationManager *locationManager = self->_locationManager;
|
||||
EXLocationAccuracy accuracy = [options[@"accuracy"] unsignedIntegerValue] ?: EXLocationAccuracyBalanced;
|
||||
|
||||
locationManager.desiredAccuracy = [EXLocation CLLocationAccuracyFromOption:accuracy];
|
||||
locationManager.distanceFilter = [options[@"distanceInterval"] doubleValue] ?: kCLDistanceFilterNone;
|
||||
locationManager.activityType = [EXLocation CLActivityTypeFromOption:[options[@"activityType"] integerValue]];
|
||||
locationManager.pausesLocationUpdatesAutomatically = [options[@"pausesUpdatesAutomatically"] boolValue];
|
||||
|
||||
if (@available(iOS 11.0, *)) {
|
||||
locationManager.showsBackgroundLocationIndicator = [options[@"showsBackgroundLocationIndicator"] boolValue];
|
||||
}
|
||||
|
||||
[locationManager startUpdatingLocation];
|
||||
[locationManager startMonitoringSignificantLocationChanges];
|
||||
}];
|
||||
}
|
||||
|
||||
# pragma mark - CLLocationManagerDelegate
|
||||
|
||||
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
|
||||
{
|
||||
if (_task != nil && locations.count > 0) {
|
||||
[self deferLocations:locations];
|
||||
[self maybeReportDeferredLocations];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
|
||||
{
|
||||
if (error.domain == kCLErrorDomain) {
|
||||
// This error might happen when the device is not able to find out the location. Try to restart monitoring location.
|
||||
[manager stopUpdatingLocation];
|
||||
[manager stopMonitoringSignificantLocationChanges];
|
||||
[manager startUpdatingLocation];
|
||||
[manager startMonitoringSignificantLocationChanges];
|
||||
} else {
|
||||
[_task executeWithData:nil withError:error];
|
||||
}
|
||||
}
|
||||
|
||||
# pragma mark - internal
|
||||
|
||||
- (void)reset
|
||||
{
|
||||
[UMUtilities performSynchronouslyOnMainThread:^{
|
||||
[self->_locationManager stopUpdatingLocation];
|
||||
[self->_locationManager stopMonitoringSignificantLocationChanges];
|
||||
[self->_deferredLocations removeAllObjects];
|
||||
self->_lastReportedLocation = nil;
|
||||
self->_deferredDistance = 0.0;
|
||||
self->_locationManager = nil;
|
||||
self->_task = nil;
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)executeTaskWithDeferredLocations
|
||||
{
|
||||
// Execute task with deferred locations.
|
||||
NSDictionary *data = @{ @"locations": [EXLocationTaskConsumer _exportLocations:_deferredLocations] };
|
||||
[_task executeWithData:data withError:nil];
|
||||
|
||||
// Reset deferring state.
|
||||
_lastReportedLocation = _deferredLocations.lastObject;
|
||||
_deferredDistance = 0.0;
|
||||
[_deferredLocations removeAllObjects];
|
||||
}
|
||||
|
||||
- (void)maybeReportDeferredLocations
|
||||
{
|
||||
if ([self shouldReportDeferredLocations]) {
|
||||
[self executeTaskWithDeferredLocations];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)deferLocations:(NSArray<CLLocation *> *)locations
|
||||
{
|
||||
CLLocation *lastLocation = _deferredLocations.lastObject ?: _lastReportedLocation;
|
||||
|
||||
for (CLLocation *location in locations) {
|
||||
if (lastLocation) {
|
||||
_deferredDistance += [location distanceFromLocation:lastLocation];
|
||||
}
|
||||
lastLocation = location;
|
||||
}
|
||||
[_deferredLocations addObjectsFromArray:locations];
|
||||
}
|
||||
|
||||
- (BOOL)shouldReportDeferredLocations
|
||||
{
|
||||
if (_deferredLocations.count <= 0) {
|
||||
return NO;
|
||||
}
|
||||
UIApplicationState appState = [[UIApplication sharedApplication] applicationState];
|
||||
|
||||
if (appState == UIApplicationStateActive) {
|
||||
// Don't defer location updates when app is in foreground state.
|
||||
return YES;
|
||||
}
|
||||
|
||||
CLLocation *oldestLocation = _lastReportedLocation ?: _deferredLocations.firstObject;
|
||||
CLLocation *newestLocation = _deferredLocations.lastObject;
|
||||
NSDictionary *options = _task.options;
|
||||
CLLocationDistance distance = [self numberToDouble:options[@"deferredUpdatesDistance"] defaultValue:0];
|
||||
NSTimeInterval interval = [self numberToDouble:options[@"deferredUpdatesInterval"] defaultValue:0];
|
||||
|
||||
return [newestLocation.timestamp timeIntervalSinceDate:oldestLocation.timestamp] >= interval / 1000.0 && _deferredDistance >= distance;
|
||||
}
|
||||
|
||||
- (double)numberToDouble:(NSNumber *)number defaultValue:(double)defaultValue
|
||||
{
|
||||
return number == nil ? defaultValue : [number doubleValue];
|
||||
}
|
||||
|
||||
+ (NSArray<NSDictionary *> *)_exportLocations:(NSArray<CLLocation *> *)locations
|
||||
{
|
||||
NSMutableArray<NSDictionary *> *result = [NSMutableArray new];
|
||||
|
||||
for (CLLocation *location in locations) {
|
||||
[result addObject:[EXLocation exportLocation:location]];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@end
|
Reference in New Issue
Block a user