[ios] Mapbox's Location Manager new API. (#12013)

* [ios] The new location manager API provides two new protocols MGLLocationManager and MGLLocationManagerDelegate to handle the location cycle and updates respectively. This enables developers to chose the appropriate location provider according to their needs, or transition between outdoors/indoors location updates.

It does provide a default implementation based on CLLocationManager.
This commit is contained in:
Fabian Guerra Soto
2018-07-20 14:14:43 -07:00
committed by GitHub
parent bbccce18c4
commit 681e0141de
14 changed files with 781 additions and 15 deletions

View File

@@ -0,0 +1,181 @@
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
NS_ASSUME_NONNULL_BEGIN
@protocol MGLLocationManagerDelegate;
/**
The `MGLLocationManager` protocol defines a set of methods that a class must
implement in order to serve as the location manager of an `MGLMapView`. A location
manager is responsible for notifying the map view about location-related events,
such as a change in the user’s location. This protocol is similar to the
Core Location framework’s `CLLocationManager` class, but your implementation
does not need to be based on `CLLocationManager`.
*/
@protocol MGLLocationManager <NSObject>
@optional
#pragma mark Configuring Location Update Precision
/**
Specifies the minimum distance (measured in meters) a device must move horizontally
before a location update is generated.
The default value of this property is `kCLDistanceFilterNone` when `MGLMapView` uses its
default location manager.
@see `CLLocationManager.distanceFilter`
*/
@property(nonatomic, assign) CLLocationDistance distanceFilter;
/**
Specifies the accuracy of the location data.
The default value is `kCLLocationAccuracyBest` when `MGLMapView` uses its
default location manager.
@note Determining a location with greater accuracy requires more time and more power.
@see `CLLocationManager.desiredAccuracy`
*/
@property (nonatomic, assign) CLLocationAccuracy desiredAccuracy;
/**
Specifies the type of user activity associated with the location updates.
The location manager uses this property as a cue to determine when location updates
may be automatically paused.
The default value is `CLActivityTypeOther` when `MGLMapView` uses its
default location manager.
@see `CLLocationManager.activityType`
*/
@property (nonatomic, assign) CLActivityType activityType;
@required
/**
The delegate to receive location updates.
Do not set the location manager’s delegate yourself. `MGLMapView` sets this property
after the location manager becomes `MGLMapView`’s location manager.
*/
@property (nonatomic, weak) id<MGLLocationManagerDelegate> delegate;
#pragma mark Requesting Authorization for Location Services
/**
Returns the current localization authorization status.
@see `+[CLLocationManger authorizationStatus]`
*/
@property (nonatomic, readonly) CLAuthorizationStatus authorizationStatus;
/**
Requests permission to use the location services whenever the app is running.
*/
- (void)requestAlwaysAuthorization;
/**
Requests permission to use the location services while the app is in
the foreground.
*/
- (void)requestWhenInUseAuthorization;
#pragma mark Initiating Location Updates
/**
Starts the generation of location updates that reports the user's current location.
*/
- (void)startUpdatingLocation;
/**
Stops the generation of location updates.
*/
- (void)stopUpdatingLocation;
#pragma mark Initiating Heading Updates
/**
Specifies a physical device orientation.
*/
@property (nonatomic) CLDeviceOrientation headingOrientation;
/**
Starts the generation of heading updates that reports the user's current hading.
*/
- (void)startUpdatingHeading;
/**
Stops the generation of heading updates.
*/
- (void)stopUpdatingHeading;
/**
Dissmisses immediately the heading calibration view from screen.
*/
- (void)dismissHeadingCalibrationDisplay;
@end
/**
The `MGLLocationManagerDelegate` protocol defines a set of methods that respond
to location updates from an `MGLLocationManager` object that is serving as the
location manager of an `MGLMapView`.
*/
@protocol MGLLocationManagerDelegate <NSObject>
#pragma mark Responding to Location Updates
/**
Notifies the delegate with the new location data.
@param manager The location manager reporting the update.
@param locations An array of `CLLocation` objects in chronological order,
with the last object representing the most recent location. This array
contains multiple `CLLocation` objects when `MGLMapView` uses its
default location manager.
*/
- (void)locationManager:(id<MGLLocationManager>)manager
didUpdateLocations:(NSArray<CLLocation *> *)locations;
#pragma mark Responding to Heading Updates
/**
Notifies the delegate with the new heading data.
@param manager The location manager reporting the update.
@param newHeading The new heading update.
*/
- (void)locationManager:(id<MGLLocationManager>)manager
didUpdateHeading:(CLHeading *)newHeading;
/**
Asks the delegate if the calibration alert should be displayed.
@param manager The location manager reporting the calibration.
*/
- (BOOL)locationManagerShouldDisplayHeadingCalibration:(id<MGLLocationManager>)manager;
#pragma mark Responding to Location Updates Errors
/**
Notifies the delegate that the location manager was unable to retrieve
location updates.
@param manager The location manager reporting the error.
@param error An error object containing the error code that indicates
why the location manager failed.
*/
- (void)locationManager:(id<MGLLocationManager>)manager
didFailWithError:(nonnull NSError *)error;
@optional
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,116 @@
#import "MGLLocationManager_Private.h"
@interface MGLCLLocationManager()<CLLocationManagerDelegate>
@property (nonatomic) CLLocationManager *locationManager;
@end
@implementation MGLCLLocationManager
- (instancetype)init
{
if (self = [super init]) {
_locationManager = [[CLLocationManager alloc] init];
_locationManager.delegate = self;
}
return self;
}
@synthesize delegate;
- (void)setHeadingOrientation:(CLDeviceOrientation)headingOrientation
{
self.locationManager.headingOrientation = headingOrientation;
}
- (CLDeviceOrientation)headingOrientation
{
return self.locationManager.headingOrientation;
}
- (void)setDesiredAccuracy:(CLLocationAccuracy)desiredAccuracy {
self.locationManager.desiredAccuracy = desiredAccuracy;
}
- (CLLocationAccuracy)desiredAccuracy {
return self.locationManager.desiredAccuracy;
}
- (CLAuthorizationStatus)authorizationStatus {
return [CLLocationManager authorizationStatus];
}
- (void)setActivityType:(CLActivityType)activityType {
self.locationManager.activityType = activityType;
}
- (CLActivityType)activityType {
return self.locationManager.activityType;
}
- (void)dismissHeadingCalibrationDisplay {
[self.locationManager dismissHeadingCalibrationDisplay];
}
- (void)requestAlwaysAuthorization {
[self.locationManager requestAlwaysAuthorization];
}
- (void)requestWhenInUseAuthorization {
[self.locationManager requestWhenInUseAuthorization];
}
- (void)startUpdatingHeading {
[self.locationManager startUpdatingHeading];
}
- (void)startUpdatingLocation {
[self.locationManager startUpdatingLocation];
}
- (void)stopUpdatingHeading {
[self.locationManager stopUpdatingHeading];
}
- (void)stopUpdatingLocation {
[self.locationManager stopUpdatingLocation];
}
- (void)dealloc
{
[self.locationManager stopUpdatingLocation];
[self.locationManager stopUpdatingHeading];
self.locationManager.delegate = nil;
self.delegate = nil;
}
#pragma mark - CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {
if ([self.delegate respondsToSelector:@selector(locationManager:didUpdateLocations:)]) {
[self.delegate locationManager:self didUpdateLocations:locations];
}
}
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading {
if ([self.delegate respondsToSelector:@selector(locationManager:didUpdateHeading:)]) {
[self.delegate locationManager:self didUpdateHeading:newHeading];
}
}
- (BOOL)locationManagerShouldDisplayHeadingCalibration:(CLLocationManager *)manager {
if ([self.delegate respondsToSelector:@selector(locationManagerShouldDisplayHeadingCalibration:)]) {
return [self.delegate locationManagerShouldDisplayHeadingCalibration:self];
}
return NO;
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
if ([self.delegate respondsToSelector:@selector(locationManager:didFailWithError:)]) {
[self.delegate locationManager:self didFailWithError:error];
}
}
@end

View File

@@ -0,0 +1,5 @@
#import "MGLLocationManager.h"
@interface MGLCLLocationManager : NSObject<MGLLocationManager>
@end

View File

@@ -4,8 +4,12 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT
## master
### Other changes
* Fixed a crash that occurred when the user started a gesture before the drift animation for a previous gesture was complete. ([#12148](https://github.com/mapbox/mapbox-gl-native/pull/12148))
* Token string syntax (`"{token}"`) in `MGLSymbolStyleLayer` `text` and `iconImageName` properties is now correctly converted to the appropriate `NSExpression` equivalent. ([#11659](https://github.com/mapbox/mapbox-gl-native/issues/11659))
* Added an `MGLMapView.locationManager` property and `MGLLocationManager` protocol for tracking user location using a custom alternative to `CLLocationManager`. ([#12013](https://github.com/mapbox/mapbox-gl-native/pull/12013))
## 4.2.0 - July 18, 2018

View File

@@ -0,0 +1,5 @@
#import <UIKit/UIKit.h>
@interface MBXCustomLocationViewController : UIViewController
@end

View File

@@ -0,0 +1,174 @@
#import "MBXCustomLocationViewController.h"
#import <Mapbox/Mapbox.h>
@interface MBXCustomLocationManager : NSObject<MGLLocationManager>
@end
@interface MBXCustomLocationManager()
@property (nonatomic) CLLocationManager *locationManager;
@property (nonatomic, strong) NSTimer *locationUpdateTimer;
@property (nonatomic) NSUInteger index;
@property (strong, nonatomic) NSDictionary *routeCoordinates;
@property (strong, nonatomic) NSArray *coordinates;
@end
@implementation MBXCustomLocationManager
@synthesize delegate;
- (instancetype)init
{
if (self = [super init]) {
_locationManager = [[CLLocationManager alloc] init];
_index = 0;
}
return self;
}
- (CLAuthorizationStatus)authorizationStatus
{
return [CLLocationManager authorizationStatus];
}
- (void)setHeadingOrientation:(CLDeviceOrientation)headingOrientation
{
_locationManager.headingOrientation = headingOrientation;
}
- (CLDeviceOrientation)headingOrientation
{
return _locationManager.headingOrientation;
}
- (void)requestAlwaysAuthorization
{
[self.locationManager requestAlwaysAuthorization];
}
- (void)requestWhenInUseAuthorization
{
[self.locationManager requestWhenInUseAuthorization];
}
- (void)startUpdatingHeading
{
[self.locationManager startUpdatingHeading];
}
- (void)startUpdatingLocation
{
[self loadRouteCoordinates];
self.locationUpdateTimer = [NSTimer scheduledTimerWithTimeInterval:0.8
target:self
selector:@selector(updateLocation)
userInfo:nil
repeats:YES];
}
- (void)stopUpdatingHeading
{
[self.locationManager stopUpdatingHeading];
}
- (void)stopUpdatingLocation
{
[self.locationUpdateTimer invalidate];
self.locationUpdateTimer = nil;
}
- (void)dismissHeadingCalibrationDisplay
{
[self.locationManager dismissHeadingCalibrationDisplay];
}
- (void)dealloc
{
[self.locationManager stopUpdatingLocation];
[self.locationManager stopUpdatingHeading];
self.delegate = nil;
}
#pragma mark - Location Updates
- (void)loadRouteCoordinates
{
NSString *filePath = [[NSBundle bundleForClass:self.class] pathForResource:@"simple_route" ofType:@"json"];
NSData *data = [NSData dataWithContentsOfFile:filePath];
_routeCoordinates = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
_coordinates = [self.routeCoordinates objectForKey:@"coordinates"];
}
- (void)updateLocation
{
if ([self.delegate respondsToSelector:@selector(locationManager:didUpdateLocations:)]) {
if (self.index >= [self.coordinates count] ) {
self.index = 0;
self.coordinates = [[self.coordinates reverseObjectEnumerator] allObjects];
}
NSArray *loc = self.coordinates[self.index];
CLLocationDegrees latitude = [[loc objectAtIndex:1] doubleValue];
CLLocationDegrees longitude = [[loc objectAtIndex:0] doubleValue];
CLLocation *location = [[CLLocation alloc] initWithLatitude:latitude longitude:longitude];
self.index++;
[self.delegate locationManager:self didUpdateLocations:@[location]];
}
}
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading
{
if ([self.delegate respondsToSelector:@selector(locationManager:didUpdateHeading:)]) {
[self.delegate locationManager:self didUpdateHeading:newHeading];
}
}
- (BOOL)locationManagerShouldDisplayHeadingCalibration:(CLLocationManager *)manager
{
if ([self.delegate respondsToSelector:@selector(locationManagerShouldDisplayHeadingCalibration:)]) {
return [self.delegate locationManagerShouldDisplayHeadingCalibration:self];
}
return NO;
}
- (void)locationManager:(CLLocationManager *)locationManager didFailWithError:(nonnull NSError *)error {
if ([self.delegate respondsToSelector:@selector(locationManager:didFailWithError:)]) {
[self.delegate locationManager:self didFailWithError:error];
}
}
@end
@interface MBXCustomLocationViewController ()
@property (strong, nonatomic) MGLMapView *mapView;
@end
@implementation MBXCustomLocationViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.mapView = [[MGLMapView alloc] initWithFrame:self.view.bounds];
self.mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
MBXCustomLocationManager *mbxLocationManager = [[MBXCustomLocationManager alloc] init];
self.mapView.locationManager = mbxLocationManager;
// Set the map’s center coordinate and zoom level.
[self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(37.788380, -122.400121)
zoomLevel:13
animated:NO];
[self.view addSubview:self.mapView];
self.mapView.showsUserLocation = YES;
}
- (void)viewWillDisappear:(BOOL)animated {
self.mapView.showsUserLocation = NO;
}
@end

View File

@@ -98,6 +98,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
MBXSettingsMiscellaneousLocalizeLabels,
MBXSettingsMiscellaneousShowSnapshots,
MBXSettingsMiscellaneousShouldLimitCameraChanges,
MBXSettingsMiscellaneousShowCustomLocationManager,
MBXSettingsMiscellaneousPrintLogFile,
MBXSettingsMiscellaneousDeleteLogFile,
};
@@ -444,6 +445,7 @@ CLLocationCoordinate2D randomWorldCoordinate() {
[NSString stringWithFormat:@"Show Labels in %@", (_localizingLabels ? @"Default Language" : [[NSLocale currentLocale] displayNameForKey:NSLocaleIdentifier value:[self bestLanguageForUser]])],
@"Show Snapshots",
[NSString stringWithFormat:@"%@ Camera Changes", (_shouldLimitCameraChanges ? @"Unlimit" : @"Limit")],
@"View Route Simulation",
]];
if (self.debugLoggingEnabled)
@@ -682,6 +684,11 @@ CLLocationCoordinate2D randomWorldCoordinate() {
[self performSegueWithIdentifier:@"ShowSnapshots" sender:nil];
break;
}
case MBXSettingsMiscellaneousShowCustomLocationManager:
{
[self performSegueWithIdentifier:@"ShowCustomLocationManger" sender:nil];
break;
}
case MBXSettingsMiscellaneousShouldLimitCameraChanges:
{
self.shouldLimitCameraChanges = !self.shouldLimitCameraChanges;

View File

@@ -107,6 +107,7 @@
<outlet property="hudLabel" destination="58y-pX-YyB" id="aGG-7a-bZR"/>
<outlet property="mapView" destination="kNe-zV-9ha" id="VNR-WO-1q4"/>
<segue destination="zvf-Qd-4Ru" kind="show" identifier="ShowSnapshots" id="hzX-Jp-UJq"/>
<segue destination="dgL-Bu-te0" kind="show" identifier="ShowCustomLocationManger" id="kDM-0K-hSf"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="AAd-8J-9UU" userLabel="First Responder" sceneMemberID="firstResponder"/>
@@ -432,6 +433,21 @@
</objects>
<point key="canvasLocation" x="1365.5999999999999" y="1083.5082458770617"/>
</scene>
<!--Custom Location View Controller-->
<scene sceneID="TUi-Dc-6uA">
<objects>
<viewController id="dgL-Bu-te0" customClass="MBXCustomLocationViewController" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="ero-1d-Jm5">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<viewLayoutGuide key="safeArea" id="t2S-ES-YuE"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="RtO-ic-8Nc" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="2073" y="1082"/>
</scene>
</scenes>
<resources>
<image name="TrackingLocationOffMask.png" width="23" height="23"/>

View File

@@ -0,0 +1,184 @@
{
"coordinates":[
[
-122.39899,
37.787357
],
[
-122.398818,
37.78722
],
[
-122.398794,
37.7872
],
[
-122.398259,
37.786773
],
[
-122.398984,
37.786206
],
[
-122.399053,
37.786151
],
[
-122.399379,
37.785888
],
[
-122.399614,
37.785697
],
[
-122.399884,
37.785478
],
[
-122.400382,
37.78509
],
[
-122.400478,
37.785015
],
[
-122.400599,
37.785111
],
[
-122.4012,
37.785587
],
[
-122.401495,
37.785825
],
[
-122.401705,
37.785993
],
[
-122.402041,
37.786261
],
[
-122.402476,
37.786603
],
[
-122.402573,
37.78668
],
[
-122.403019,
37.787031
],
[
-122.403315,
37.78728
],
[
-122.403358,
37.787324
],
[
-122.403382,
37.787356
],
[
-122.403398,
37.787392
],
[
-122.403405,
37.787425
],
[
-122.403415,
37.787486
],
[
-122.403434,
37.787654
],
[
-122.403436,
37.787676
],
[
-122.40344,
37.787698
],
[
-122.403444,
37.787729
],
[
-122.403464,
37.787825
],
[
-122.403476,
37.787877
],
[
-122.403497,
37.787965
],
[
-122.403591,
37.788436
],
[
-122.403684,
37.788901
],
[
-122.403774,
37.789349
],
[
-122.403798,
37.789469
],
[
-122.403872,
37.789833
],
[
-122.404232,
37.789788
],
[
-122.405435,
37.789635
],
[
-122.406,
37.789562
],
[
-122.406982,
37.789436
],
[
-122.407475,
37.789373
],
[
-122.408599,
37.789231
],
[
-122.408616,
37.789229
],
[
-122.408451,
37.788454
]
]
}

View File

@@ -30,6 +30,8 @@
1753ED431E53CE6F00A9FD90 /* MGLConversion.h in Headers */ = {isa = PBXBuildFile; fileRef = 1753ED411E53CE6F00A9FD90 /* MGLConversion.h */; };
1F06668A1EC64F8E001C16D7 /* MGLLight.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F0666881EC64F8E001C16D7 /* MGLLight.h */; settings = {ATTRIBUTES = (Public, ); }; };
1F06668D1EC64F8E001C16D7 /* MGLLight.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1F0666891EC64F8E001C16D7 /* MGLLight.mm */; };
1F26B6C120E189C9007BCC21 /* MBXCustomLocationViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F26B6C020E189C9007BCC21 /* MBXCustomLocationViewController.m */; };
1F26B6C320E1A351007BCC21 /* simple_route.json in Resources */ = {isa = PBXBuildFile; fileRef = 1F26B6C220E1A351007BCC21 /* simple_route.json */; };
1F7454921ECBB42C00021D39 /* MGLLight.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1F0666891EC64F8E001C16D7 /* MGLLight.mm */; };
1F7454931ECBB43F00021D39 /* MGLLight.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F0666881EC64F8E001C16D7 /* MGLLight.h */; settings = {ATTRIBUTES = (Public, ); }; };
1F7454961ECD450D00021D39 /* MGLLight_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F7454941ECD450D00021D39 /* MGLLight_Private.h */; };
@@ -38,6 +40,12 @@
1F95931D1E6DE2E900D5B294 /* MGLNSDateAdditionsTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1F95931C1E6DE2E900D5B294 /* MGLNSDateAdditionsTests.mm */; };
1FC4817D2098CBC0000D09B4 /* NSPredicate+MGLPrivateAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 1FC4817B2098CBC0000D09B4 /* NSPredicate+MGLPrivateAdditions.h */; };
1FC4817F2098CD80000D09B4 /* NSPredicate+MGLPrivateAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 1FC4817B2098CBC0000D09B4 /* NSPredicate+MGLPrivateAdditions.h */; };
1FCAE2A220B872A400C577DD /* MGLLocationManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1FCAE2A020B872A400C577DD /* MGLLocationManager.h */; settings = {ATTRIBUTES = (Public, ); }; };
1FCAE2A320B872A400C577DD /* MGLLocationManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1FCAE2A020B872A400C577DD /* MGLLocationManager.h */; settings = {ATTRIBUTES = (Public, ); }; };
1FCAE2A420B872A400C577DD /* MGLLocationManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1FCAE2A120B872A400C577DD /* MGLLocationManager.m */; };
1FCAE2A520B872A400C577DD /* MGLLocationManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1FCAE2A120B872A400C577DD /* MGLLocationManager.m */; };
1FCAE2A820B88B3800C577DD /* MGLLocationManager_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 1FCAE2A620B88B3800C577DD /* MGLLocationManager_Private.h */; };
1FCAE2A920B88B3800C577DD /* MGLLocationManager_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 1FCAE2A620B88B3800C577DD /* MGLLocationManager_Private.h */; };
30E578171DAA85520050F07E /* UIImage+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 30E578111DAA7D690050F07E /* UIImage+MGLAdditions.h */; };
30E578181DAA85520050F07E /* UIImage+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 30E578111DAA7D690050F07E /* UIImage+MGLAdditions.h */; };
30E578191DAA855E0050F07E /* UIImage+MGLAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 30E578121DAA7D690050F07E /* UIImage+MGLAdditions.mm */; };
@@ -752,10 +760,16 @@
1753ED411E53CE6F00A9FD90 /* MGLConversion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLConversion.h; sourceTree = "<group>"; };
1F0666881EC64F8E001C16D7 /* MGLLight.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLLight.h; sourceTree = "<group>"; };
1F0666891EC64F8E001C16D7 /* MGLLight.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLLight.mm; sourceTree = "<group>"; };
1F26B6BF20E189C9007BCC21 /* MBXCustomLocationViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBXCustomLocationViewController.h; sourceTree = "<group>"; };
1F26B6C020E189C9007BCC21 /* MBXCustomLocationViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBXCustomLocationViewController.m; sourceTree = "<group>"; };
1F26B6C220E1A351007BCC21 /* simple_route.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = simple_route.json; sourceTree = "<group>"; };
1F7454941ECD450D00021D39 /* MGLLight_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLLight_Private.h; sourceTree = "<group>"; };
1F7454A61ED08AB400021D39 /* MGLLightTest.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLLightTest.mm; path = ../../darwin/test/MGLLightTest.mm; sourceTree = "<group>"; };
1F95931C1E6DE2E900D5B294 /* MGLNSDateAdditionsTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLNSDateAdditionsTests.mm; path = ../../darwin/test/MGLNSDateAdditionsTests.mm; sourceTree = "<group>"; };
1FC4817B2098CBC0000D09B4 /* NSPredicate+MGLPrivateAdditions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSPredicate+MGLPrivateAdditions.h"; sourceTree = "<group>"; };
1FCAE2A020B872A400C577DD /* MGLLocationManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLLocationManager.h; sourceTree = "<group>"; };
1FCAE2A120B872A400C577DD /* MGLLocationManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MGLLocationManager.m; sourceTree = "<group>"; };
1FCAE2A620B88B3800C577DD /* MGLLocationManager_Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLLocationManager_Private.h; sourceTree = "<group>"; };
20DABE861DF78148007AC5FF /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Foundation.strings"; sourceTree = "<group>"; };
20DABE881DF78148007AC5FF /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = "<group>"; };
20DABE8A1DF78149007AC5FF /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Root.strings"; sourceTree = "<group>"; };
@@ -1697,6 +1711,7 @@
353BAEF51D646370009A8DA9 /* amsterdam.geojson */,
DA1DC96C1CB6C6CE006E619F /* points.geojson */,
DA1DC96D1CB6C6CE006E619F /* polyline.geojson */,
1F26B6C220E1A351007BCC21 /* simple_route.json */,
DA1DC96F1CB6C6CE006E619F /* threestates.geojson */,
DD4823721D94AE6C00EB71B7 /* fill_filter_style.json */,
DD4823731D94AE6C00EB71B7 /* line_filter_style.json */,
@@ -1770,6 +1785,8 @@
DA1DC9691CB6C6B7006E619F /* MBXOfflinePacksTableViewController.m */,
927FBCFA1F4DAA8300F8BF1F /* MBXSnapshotsViewController.h */,
927FBCFB1F4DAA8300F8BF1F /* MBXSnapshotsViewController.m */,
1F26B6BF20E189C9007BCC21 /* MBXCustomLocationViewController.h */,
1F26B6C020E189C9007BCC21 /* MBXCustomLocationViewController.m */,
DA1DC9531CB6C1C2006E619F /* MBXViewController.h */,
DA1DC99A1CB6E064006E619F /* MBXViewController.m */,
632281DD1E6F855900D75A5D /* MBXEmbeddedMapViewController.h */,
@@ -1911,6 +1928,9 @@
DA8847EE1CBAFA5100AB86E3 /* MGLTypes.h */,
DA8848111CBAFA6200AB86E3 /* MGLTypes.m */,
35E1A4D71D74336F007AA97F /* MGLValueEvaluator.h */,
1FCAE2A020B872A400C577DD /* MGLLocationManager.h */,
1FCAE2A620B88B3800C577DD /* MGLLocationManager_Private.h */,
1FCAE2A120B872A400C577DD /* MGLLocationManager.m */,
);
name = Foundation;
path = ../darwin/src;
@@ -2227,6 +2247,7 @@
35E79F201D41266300957B9E /* MGLStyleLayer_Private.h in Headers */,
FA68F14A1E9D656600F9F6C2 /* MGLFillExtrusionStyleLayer.h in Headers */,
353933FB1D3FB7C0003F57D7 /* MGLRasterStyleLayer.h in Headers */,
1FCAE2A820B88B3800C577DD /* MGLLocationManager_Private.h in Headers */,
DA8847EF1CBAFA5100AB86E3 /* MGLAccountManager.h in Headers */,
DA35A2C91CCAAAD200E826B2 /* NSValue+MGLAdditions.h in Headers */,
3510FFEA1D6D9C7A00F413B2 /* NSComparisonPredicate+MGLAdditions.h in Headers */,
@@ -2237,6 +2258,7 @@
35D3A1E61E9BE7EB002B38EE /* MGLScaleBar.h in Headers */,
0778DD431F67556700A73B34 /* MGLComputedShapeSource.h in Headers */,
DA8848311CBAFA6200AB86E3 /* NSString+MGLAdditions.h in Headers */,
1FCAE2A220B872A400C577DD /* MGLLocationManager.h in Headers */,
DACA86262019218600E9693A /* MGLRasterDEMSource.h in Headers */,
353933F81D3FB79F003F57D7 /* MGLLineStyleLayer.h in Headers */,
92F2C3ED1F0E3C3A00268EC0 /* MGLRendererFrontend.h in Headers */,
@@ -2377,6 +2399,7 @@
DA72620C1DEEE3480043BB89 /* MGLOpenGLStyleLayer.h in Headers */,
35CE61831D4165D9004F2359 /* UIColor+MGLAdditions.h in Headers */,
96E516F32000597100A02306 /* NSDictionary+MGLAdditions.h in Headers */,
1FCAE2A920B88B3800C577DD /* MGLLocationManager_Private.h in Headers */,
96E516F02000595800A02306 /* NSBundle+MGLAdditions.h in Headers */,
96E516F920005A3500A02306 /* MGLFaux3DUserLocationAnnotationView.h in Headers */,
96E516F22000596D00A02306 /* NSException+MGLAdditions.h in Headers */,
@@ -2416,6 +2439,7 @@
968F36B51E4D128D003A5522 /* MGLDistanceFormatter.h in Headers */,
4018B1CB1CDC288E00F666AF /* MGLAnnotationView.h in Headers */,
DABFB85F1CBE99E500D62B32 /* MGLGeometry.h in Headers */,
1FCAE2A320B872A400C577DD /* MGLLocationManager.h in Headers */,
96E516E02000550C00A02306 /* MGLFeature_Private.h in Headers */,
353933F61D3FB785003F57D7 /* MGLBackgroundStyleLayer.h in Headers */,
DABFB85D1CBE99E500D62B32 /* MGLAccountManager.h in Headers */,
@@ -2736,6 +2760,7 @@
DA1DC9731CB6C6CE006E619F /* threestates.geojson in Resources */,
DA821D061CCC6D59007508D4 /* LaunchScreen.storyboard in Resources */,
96E027231E57C76E004B8E66 /* Localizable.strings in Resources */,
1F26B6C320E1A351007BCC21 /* simple_route.json in Resources */,
DD4823751D94AE6C00EB71B7 /* fill_filter_style.json in Resources */,
DA1DC99F1CB6E088006E619F /* Assets.xcassets in Resources */,
);
@@ -2836,6 +2861,7 @@
927FBCFC1F4DAA8300F8BF1F /* MBXSnapshotsViewController.m in Sources */,
DA1DC99B1CB6E064006E619F /* MBXViewController.m in Sources */,
40FDA76B1CCAAA6800442548 /* MBXAnnotationView.m in Sources */,
1F26B6C120E189C9007BCC21 /* MBXCustomLocationViewController.m in Sources */,
3E6465D62065767A00685536 /* LimeGreenStyleLayer.m in Sources */,
632281DF1E6F855900D75A5D /* MBXEmbeddedMapViewController.m in Sources */,
);
@@ -3000,6 +3026,7 @@
40834BED1FE05E1800C1BD0D /* MMEEventLogger.m in Sources */,
353AFA161D65AB17005A69F4 /* NSDate+MGLAdditions.mm in Sources */,
40834BF41FE05E1800C1BD0D /* MMETrustKitWrapper.m in Sources */,
1FCAE2A420B872A400C577DD /* MGLLocationManager.m in Sources */,
40834BEF1FE05E1800C1BD0D /* MMEEventsManager.m in Sources */,
35D13AC51D3D19DD00AFB4E0 /* MGLFillStyleLayer.mm in Sources */,
DA8848241CBAFA6200AB86E3 /* MGLOfflineStorage.mm in Sources */,
@@ -3126,6 +3153,7 @@
40834C011FE05E1800C1BD0D /* MMEEventLogger.m in Sources */,
35D13AC61D3D19DD00AFB4E0 /* MGLFillStyleLayer.mm in Sources */,
40834C081FE05E1800C1BD0D /* MMETrustKitWrapper.m in Sources */,
1FCAE2A520B872A400C577DD /* MGLLocationManager.m in Sources */,
40834C031FE05E1800C1BD0D /* MMEEventsManager.m in Sources */,
DAA4E42A1CBB730400178DFB /* NSProcessInfo+MGLAdditions.m in Sources */,
DAA4E4211CBB730400178DFB /* MGLOfflineStorage.mm in Sources */,

View File

@@ -60,6 +60,10 @@ custom_categories:
children:
- MGLCalloutView
- MGLCalloutViewDelegate
- name: Location Updates
children:
- MGLLocationManager
- MGLLocationManagerDelegate
- name: Styling the Map
children:
- MGLStyle

View File

@@ -2,7 +2,6 @@
#import "MGLMapCamera.h"
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#import "MGLFoundation.h"
#import "MGLTypes.h"
@@ -22,6 +21,7 @@ NS_ASSUME_NONNULL_BEGIN
@protocol MGLOverlay;
@protocol MGLCalloutView;
@protocol MGLFeature;
@protocol MGLLocationManager;
/** The default deceleration rate for a map view. */
extern MGL_EXPORT const CGFloat MGLMapViewDecelerationRateNormal;
@@ -296,6 +296,24 @@ MGL_EXPORT IB_DESIGNABLE
#pragma mark Displaying the User’s Location
/**
The object that this map view uses to start and stop the delivery of location-related
updates.
To receive the current user location, implement the `-[MGLMapViewDelegate mapView:didUpdateUserLocation:]`
and `-[MGLMapViewDelegate mapView:didFailToLocateUserWithError:]` methods.
If setting this property to `nil` and setting `showsUserLocation` to `YES`, or
if no custom manager is provided this property is set to the default
location manager.
`MGLMapView` uses a default location manager. If you want to substitute your own
location manager, you should do so by setting this property before setting
`showsUserLocation` to `YES`. To restore the default location manager,
set this property to `nil`.
*/
@property (nonatomic, null_resettable) id<MGLLocationManager> locationManager;
/**
A Boolean value indicating whether the map may display the user location.
@@ -312,6 +330,9 @@ MGL_EXPORT IB_DESIGNABLE
`NSLocationAlwaysUsageDescription` in its `Info.plist` to satisfy the
requirements of the underlying Core Location framework when enabling this
property.
If you implement a custom location manager, set the `locationManager` before
calling `showsUserLocation`.
*/
@property (nonatomic, assign) BOOL showsUserLocation;

View File

@@ -73,6 +73,7 @@
#import "MGLAnnotationContainerView_Private.h"
#import "MGLAttributionInfo_Private.h"
#import "MGLMapAccessibilityElement.h"
#import "MGLLocationManager_Private.h"
#include <algorithm>
#include <cstdlib>
@@ -184,7 +185,7 @@ public:
@interface MGLMapView () <UIGestureRecognizerDelegate,
GLKViewDelegate,
CLLocationManagerDelegate,
MGLLocationManagerDelegate,
MGLSMCalloutViewDelegate,
MGLCalloutViewDelegate,
MGLMultiPointDelegate,
@@ -225,7 +226,6 @@ public:
/// Indicates how thoroughly the map view is tracking the user location.
@property (nonatomic) MGLUserTrackingState userTrackingState;
@property (nonatomic) CLLocationManager *locationManager;
@property (nonatomic) CGFloat scale;
@property (nonatomic) CGFloat angle;
@property (nonatomic) CGFloat quickZoomStart;
@@ -694,6 +694,9 @@ public:
[self.attributionButtonConstraints removeAllObjects];
self.attributionButtonConstraints = nil;
self.locationManager.delegate = nil;
self.locationManager = nil;
}
- (void)setDelegate:(nullable id<MGLMapViewDelegate>)delegate
@@ -4687,15 +4690,29 @@ public:
#pragma mark - User Location -
- (void)setLocationManager:(id<MGLLocationManager>)locationManager
{
if (!locationManager) {
[self.locationManager stopUpdatingLocation];
[self.locationManager stopUpdatingHeading];
}
self.locationManager.delegate = nil;
_locationManager = locationManager;
_locationManager.delegate = self;
}
- (void)validateLocationServices
{
BOOL shouldEnableLocationServices = self.showsUserLocation && !self.dormant;
if (shouldEnableLocationServices && ! self.locationManager)
if (shouldEnableLocationServices)
{
self.locationManager = [[CLLocationManager alloc] init];
// If no custom location manager is provided will use the internal implementation.
if (!self.locationManager) {
self.locationManager = [[MGLCLLocationManager alloc] init];
}
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined)
if (self.locationManager.authorizationStatus == kCLAuthorizationStatusNotDetermined)
{
BOOL requiresWhenInUseUsageDescription = [NSProcessInfo.processInfo isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){11,0,0}];
BOOL hasWhenInUseUsageDescription = !![[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"];
@@ -4735,8 +4752,6 @@ public:
{
[self.locationManager stopUpdatingLocation];
[self.locationManager stopUpdatingHeading];
self.locationManager.delegate = nil;
self.locationManager = nil;
}
}
@@ -4966,12 +4981,12 @@ public:
}
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
- (void)locationManager:(id<MGLLocationManager>)manager didUpdateLocations:(NSArray *)locations
{
[self locationManager:manager didUpdateLocations:locations animated:YES];
}
- (void)locationManager:(__unused CLLocationManager *)manager didUpdateLocations:(NSArray *)locations animated:(BOOL)animated
- (void)locationManager:(__unused id<MGLLocationManager>)manager didUpdateLocations:(NSArray *)locations animated:(BOOL)animated
{
CLLocation *oldLocation = self.userLocation.location;
CLLocation *newLocation = locations.lastObject;
@@ -5198,16 +5213,21 @@ public:
return direction;
}
- (BOOL)locationManagerShouldDisplayHeadingCalibration:(CLLocationManager *)manager
- (BOOL)locationManagerShouldDisplayHeadingCalibration:(id<MGLLocationManager>)manager
{
if (self.displayHeadingCalibration) [manager performSelector:@selector(dismissHeadingCalibrationDisplay)
withObject:nil
if (self.displayHeadingCalibration) [self performSelector:@selector(dismissHeadingCalibrationDisplay:)
withObject:manager
afterDelay:10.0];
return self.displayHeadingCalibration;
}
- (void)locationManager:(__unused CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading
- (void)dismissHeadingCalibrationDisplay:(id<MGLLocationManager>)manager
{
[manager dismissHeadingCalibrationDisplay];
}
- (void)locationManager:(__unused id<MGLLocationManager>)manager didUpdateHeading:(CLHeading *)newHeading
{
if ( ! _showsUserLocation || self.pan.state == UIGestureRecognizerStateBegan || newHeading.headingAccuracy < 0) return;
@@ -5234,7 +5254,7 @@ public:
}
}
- (void)locationManager:(__unused CLLocationManager *)manager didFailWithError:(NSError *)error
- (void)locationManager:(__unused id<MGLLocationManager>)manager didFailWithError:(NSError *)error
{
if ([error code] == kCLErrorDenied)
{

View File

@@ -67,3 +67,4 @@ FOUNDATION_EXPORT MGL_EXPORT const unsigned char MapboxVersionString[];
#import "MGLMapSnapshotter.h"
#import "NSExpression+MGLAdditions.h"
#import "NSPredicate+MGLAdditions.h"
#import "MGLLocationManager.h"