Files
MapLibreParticleLab/platform/ios/src/MGLLocationManager.m
Minh Nguyễn b8c39667ff [ios] Moved SDK from gyp into Xcode project
Added a new Cocoa Touch dynamic framework target and Cocoa Touch static library target to the main iOS Xcode project. The targets are based on the templates provided by Xcode. They contain headers and source files in the darwin/ and ios/ subdirectories. Headers are explicitly marked public or project-internal instead of implicitly by subdirectory.

The SDK targets have a few dependencies that are managed by mason. Transform the config.gypi generated by configure into an .xcconfig file that Xcode uses to fill in compiler and linker flags.

Removed the iossdk target from platform.gypi and pared down the platform-lib target. make iproj opens the overall Xcode workspace instead of just the core project.

Resolved some warnings that are only now appearing because we’re using the standard warning and error flags instead of the pedantic and somewhat inappropriate flags that were forced by the gyp configuration files. Removed a console message informing developers of a long-ago deleted delegate method; the message was triggering a “selector not found” warning. Conditionalized some deprecated symbol usage that’s still needed for the static framework but not the dynamic framework, due to differing minimum deployment targets.

Added a build phase to the static library target that copies headers for use with the static library itself. This would allow us to potentially include a header in the dynamic framework but not the static library and vice-versa.

Updated the changelog to note that unused SVG files have been removed from the distribution.
2016-04-16 22:45:59 -07:00

169 lines
7.1 KiB
Objective-C

#import "MGLLocationManager.h"
#import <UIKit/UIKit.h>
static const NSTimeInterval MGLLocationManagerHibernationTimeout = 300.0;
static const NSTimeInterval MGLLocationManagerHibernationPollInterval = 5.0;
static const CLLocationDistance MGLLocationManagerHibernationRadius = 300.0;
static const CLLocationDistance MGLLocationManagerDistanceFilter = 5.0;
static NSString * const MGLLocationManagerRegionIdentifier = @"MGLLocationManagerRegionIdentifier.fence.center";
@interface MGLLocationManager ()
@property (nonatomic) CLLocationManager *standardLocationManager;
@property (nonatomic) BOOL hostAppHasBackgroundCapability;
@property (nonatomic, getter=isUpdatingLocation) BOOL updatingLocation;
@property (nonatomic) NSDate *backgroundLocationServiceTimeoutAllowedDate;
@property (nonatomic) NSTimer *backgroundLocationServiceTimeoutTimer;
@end
@implementation MGLLocationManager
- (instancetype)init {
self = [super init];
if (self) {
NSArray *backgroundModes = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIBackgroundModes"];
_hostAppHasBackgroundCapability = [backgroundModes containsObject:@"location"];
}
return self;
}
- (void)startUpdatingLocation {
if ([self isUpdatingLocation]) {
return;
}
[self configurePassiveStandardLocationManager];
[self startLocationServices];
}
- (void)stopUpdatingLocation {
if ([self isUpdatingLocation]) {
[self.standardLocationManager stopUpdatingLocation];
[self.standardLocationManager stopMonitoringSignificantLocationChanges];
self.updatingLocation = NO;
if ([self.delegate respondsToSelector:@selector(locationManagerDidStopLocationUpdates:)]) {
[self.delegate locationManagerDidStopLocationUpdates:self];
}
}
}
#pragma mark - Utilities
- (void)configurePassiveStandardLocationManager {
if (!self.standardLocationManager) {
CLLocationManager *standardLocationManager = [[CLLocationManager alloc] init];
standardLocationManager.delegate = self;
standardLocationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers;
standardLocationManager.distanceFilter = MGLLocationManagerDistanceFilter;
self.standardLocationManager = standardLocationManager;
}
}
- (void)startLocationServices {
CLAuthorizationStatus authorizationStatus = [CLLocationManager authorizationStatus];
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 80000
BOOL authorizedAlways = authorizationStatus == kCLAuthorizationStatusAuthorizedAlways;
#else
BOOL authorizedAlways = authorizationStatus == kCLAuthorizationStatusAuthorized;
#endif
if (authorizedAlways || authorizationStatus == kCLAuthorizationStatusAuthorizedWhenInUse) {
// If the host app can run in the background with `always` location permissions then allow background
// updates and start the significant location change service and background timeout timer
if (self.hostAppHasBackgroundCapability && authorizedAlways) {
[self.standardLocationManager startMonitoringSignificantLocationChanges];
[self startBackgroundTimeoutTimer];
// On iOS 9 and above also allow background location updates
if ([self.standardLocationManager respondsToSelector:@selector(allowsBackgroundLocationUpdates)]) {
self.standardLocationManager.allowsBackgroundLocationUpdates = YES;
}
}
[self.standardLocationManager startUpdatingLocation];
self.updatingLocation = YES;
if ([self.delegate respondsToSelector:@selector(locationManagerDidStartLocationUpdates:)]) {
[self.delegate locationManagerDidStartLocationUpdates:self];
}
}
}
- (void)timeoutAllowedCheck {
if (self.backgroundLocationServiceTimeoutAllowedDate == nil) {
return;
}
if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive ||
[UIApplication sharedApplication].applicationState == UIApplicationStateInactive ) {
[self startBackgroundTimeoutTimer];
return;
}
NSTimeInterval timeIntervalSinceTimeoutAllowed = [[NSDate date] timeIntervalSinceDate:self.backgroundLocationServiceTimeoutAllowedDate];
if (timeIntervalSinceTimeoutAllowed > 0) {
[self.standardLocationManager stopUpdatingLocation];
self.backgroundLocationServiceTimeoutAllowedDate = nil;
if ([self.delegate respondsToSelector:@selector(locationManagerBackgroundLocationUpdatesDidTimeout:)]) {
[self.delegate locationManagerBackgroundLocationUpdatesDidTimeout:self];
}
}
}
- (void)startBackgroundTimeoutTimer {
[self.backgroundLocationServiceTimeoutTimer invalidate];
self.backgroundLocationServiceTimeoutAllowedDate = [[NSDate date] dateByAddingTimeInterval:MGLLocationManagerHibernationTimeout];
self.backgroundLocationServiceTimeoutTimer = [NSTimer scheduledTimerWithTimeInterval:MGLLocationManagerHibernationPollInterval target:self selector:@selector(timeoutAllowedCheck) userInfo:nil repeats:YES];
}
- (void)establishRegionMonitoringForLocation:(CLLocation *)location {
CLCircularRegion *region = [[CLCircularRegion alloc] initWithCenter:location.coordinate radius:MGLLocationManagerHibernationRadius identifier:MGLLocationManagerRegionIdentifier];
region.notifyOnEntry = NO;
region.notifyOnExit = YES;
[self.standardLocationManager startMonitoringForRegion:region];
}
#pragma mark - CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
switch (status) {
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 80000
case kCLAuthorizationStatusAuthorizedAlways:
#else
case kCLAuthorizationStatusAuthorized:
#endif
case kCLAuthorizationStatusAuthorizedWhenInUse:
[self startUpdatingLocation];
break;
default:
[self stopUpdatingLocation];
break;
}
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {
CLLocation *location = locations.lastObject;
if (location.speed > 0.0) {
[self startBackgroundTimeoutTimer];
}
if (self.standardLocationManager.monitoredRegions.count == 0 || location.horizontalAccuracy < MGLLocationManagerHibernationRadius) {
[self establishRegionMonitoringForLocation:location];
}
if ([self.delegate respondsToSelector:@selector(locationManager:didUpdateLocations:)]) {
[self.delegate locationManager:self didUpdateLocations:locations];
}
}
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {
[self startBackgroundTimeoutTimer];
[self.standardLocationManager startUpdatingLocation];
}
- (void)locationManagerDidPauseLocationUpdates:(CLLocationManager *)manager {
if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) {
if ([self.delegate respondsToSelector:@selector(locationManagerBackgroundLocationUpdatesDidAutomaticallyPause:)]) {
[self.delegate locationManagerBackgroundLocationUpdatesDidAutomaticallyPause:self];
}
}
}
@end