From 2529baa62b509f2c763d5b3f9f5e1e388a45917f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Wed, 13 May 2015 15:33:28 -0700 Subject: [PATCH 1/8] Grab access token and other app-wide data from Info.plist MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit That way there’s no ambiguity about when you should call things like `+[MGLAccountManager setMapboxMetricsEnabledSettingShownInApp:]`. In fact, that method is now deprecated because it’s so easy to call in the wrong place. Fixes #1535. --- include/mbgl/ios/MGLAccountManager.h | 2 +- platform/ios/MGLAccountManager.m | 17 ++++++++++++++++- platform/ios/MGLMapboxEvents.m | 4 +++- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/include/mbgl/ios/MGLAccountManager.h b/include/mbgl/ios/MGLAccountManager.h index 7ec4135f1..5c1b2e357 100644 --- a/include/mbgl/ios/MGLAccountManager.h +++ b/include/mbgl/ios/MGLAccountManager.h @@ -21,7 +21,7 @@ /** Certain Mapbox plans require the collection of user metrics. If you aren't using a preference switch in an existing or new `Settings.bundle` in your application, set this value to `YES` to indicate that you are providing a metrics opt-out for users within your app's interface directly. * @param showsOptOut Whether your application's interface provides a user opt-out preference. The default value is `NO`, meaning a `Settings.bundle` is expected for providing a user opt-out preference. */ -+ (void)setMapboxMetricsEnabledSettingShownInApp:(BOOL)showsOptOut; ++ (void)setMapboxMetricsEnabledSettingShownInApp:(BOOL)showsOptOut DEPRECATED_MSG_ATTRIBUTE("Set MGLMapboxMetricsEnabledSettingShownInApp in Info.plist"); /** Whether in-app user metrics opt-out is configured. If set to the default value of `NO`, a user opt-out preference is expected in a `Settings.bundle` that shows in the application's section within the system Settings app. */ + (BOOL)mapboxMetricsEnabledSettingShownInApp; diff --git a/platform/ios/MGLAccountManager.m b/platform/ios/MGLAccountManager.m index 2e3c0a38e..819dd741d 100644 --- a/platform/ios/MGLAccountManager.m +++ b/platform/ios/MGLAccountManager.m @@ -9,11 +9,25 @@ @property (atomic) BOOL mapboxMetricsEnabledSettingShownInApp; @property (atomic) NSString *accessToken; ++ (void)setMapboxMetricsEnabledSettingShownInApp:(BOOL)showsOptOut; + @end @implementation MGLAccountManager ++ (void)initialize { + if (self == [MGLAccountManager class]) { + // Read initial configuration from Info.plist. + NSBundle *bundle = [NSBundle bundleForClass:self]; + self.accessToken = [bundle objectForInfoDictionaryKey:@"MGLMapboxAccessToken"]; + NSNumber *shownInAppNumber = [bundle objectForInfoDictionaryKey:@"MGLMapboxMetricsEnabledSettingShownInApp"]; + if (shownInAppNumber) { + [MGLAccountManager sharedManager].mapboxMetricsEnabledSettingShownInApp = [shownInAppNumber boolValue]; + } + } +} + // Can be called from any thread. // + (instancetype) sharedManager { @@ -25,7 +39,6 @@ void (^setupBlock)() = ^{ dispatch_once(&onceToken, ^{ _sharedManager = [[self alloc] init]; - _sharedManager.mapboxMetricsEnabledSettingShownInApp = NO; }); }; if ( ! [[NSThread currentThread] isMainThread]) { @@ -48,6 +61,8 @@ } + (void) setAccessToken:(NSString *) accessToken { + if ( ! [accessToken length]) return; + [[MGLAccountManager sharedManager] setAccessToken:accessToken]; // Update MGLMapboxEvents diff --git a/platform/ios/MGLMapboxEvents.m b/platform/ios/MGLMapboxEvents.m index 2b9d88777..017dceeb3 100644 --- a/platform/ios/MGLMapboxEvents.m +++ b/platform/ios/MGLMapboxEvents.m @@ -176,8 +176,10 @@ const NSTimeInterval MGLFlushInterval = 60; + (void)initialize { if (self == [MGLMapboxEvents class]) { + NSBundle *bundle = [NSBundle bundleForClass:self]; + NSNumber *accountTypeNumber = [bundle objectForInfoDictionaryKey:@"MGLMapboxAccountType"]; [[NSUserDefaults standardUserDefaults] registerDefaults:@{ - @"MGLMapboxAccountType": @0, + @"MGLMapboxAccountType": accountTypeNumber ? accountTypeNumber : @0, @"MGLMapboxMetricsEnabled": @YES, }]; } From cbb7112e8c2a79a4777a1e439029686dc3e3547e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Wed, 13 May 2015 16:08:40 -0700 Subject: [PATCH 2/8] Set up MGLAccountManager without any prodding `MGLAccountManager` is now guaranteed to initialize without the code ever making any mention of it. It also is guaranteed to be set up before `MGLMapboxMetrics` but will definitely cause `MGLMapboxMetrics` to be set up on the main thread if the access token is set in Info.plist. --- platform/ios/MGLAccountManager.m | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/platform/ios/MGLAccountManager.m b/platform/ios/MGLAccountManager.m index 819dd741d..d5b89e9f9 100644 --- a/platform/ios/MGLAccountManager.m +++ b/platform/ios/MGLAccountManager.m @@ -16,15 +16,13 @@ @implementation MGLAccountManager -+ (void)initialize { - if (self == [MGLAccountManager class]) { - // Read initial configuration from Info.plist. - NSBundle *bundle = [NSBundle bundleForClass:self]; - self.accessToken = [bundle objectForInfoDictionaryKey:@"MGLMapboxAccessToken"]; - NSNumber *shownInAppNumber = [bundle objectForInfoDictionaryKey:@"MGLMapboxMetricsEnabledSettingShownInApp"]; - if (shownInAppNumber) { - [MGLAccountManager sharedManager].mapboxMetricsEnabledSettingShownInApp = [shownInAppNumber boolValue]; - } ++ (void)load { + // Read initial configuration from Info.plist. + NSBundle *bundle = [NSBundle bundleForClass:self]; + self.accessToken = [bundle objectForInfoDictionaryKey:@"MGLMapboxAccessToken"]; + NSNumber *shownInAppNumber = [bundle objectForInfoDictionaryKey:@"MGLMapboxMetricsEnabledSettingShownInApp"]; + if (shownInAppNumber) { + [MGLAccountManager sharedManager].mapboxMetricsEnabledSettingShownInApp = [shownInAppNumber boolValue]; } } @@ -63,7 +61,7 @@ + (void) setAccessToken:(NSString *) accessToken { if ( ! [accessToken length]) return; - [[MGLAccountManager sharedManager] setAccessToken:accessToken]; + [MGLAccountManager sharedManager].accessToken = accessToken; // Update MGLMapboxEvents // NOTE: This is (likely) the initial setup of MGLMapboxEvents From 164ff72297a0b57c42cc5dc1299e6b7f1dd13db9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Wed, 13 May 2015 16:33:40 -0700 Subject: [PATCH 3/8] Fall back on MGLAccountManager access token Makes IB designables aware of access tokens set via Info.plist. --- platform/ios/MGLMapView.mm | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/platform/ios/MGLMapView.mm b/platform/ios/MGLMapView.mm index c928dd6ae..4be5d20d2 100644 --- a/platform/ios/MGLMapView.mm +++ b/platform/ios/MGLMapView.mm @@ -153,7 +153,8 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration) - (NSString *)accessToken { - return @(_mbglMap->getAccessToken().c_str()).mgl_stringOrNilIfEmpty; + NSString *accessToken = @(_mbglMap->getAccessToken().c_str()).mgl_stringOrNilIfEmpty; + return accessToken ? accessToken : [MGLAccountManager accessToken]; } - (void)setAccessToken:(NSString *)accessToken @@ -2559,7 +2560,7 @@ CLLocationCoordinate2D latLngToCoordinate(mbgl::LatLng latLng) // More explanation UILabel *explanationLabel2 = [[UILabel alloc] init]; - explanationLabel2.text = @"and enter it into the Access Token field in the Attributes inspector."; + explanationLabel2.text = @"and enter it into the Access Token field in the Attributes inspector or in an MGLMapboxAccessToken entry in the Info.plist file."; explanationLabel2.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody]; explanationLabel2.numberOfLines = 0; explanationLabel2.translatesAutoresizingMaskIntoConstraints = NO; From 0ad76c95d20f7ef7b7ef712d8edb8c54219880e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Wed, 13 May 2015 22:33:03 -0700 Subject: [PATCH 4/8] Obsoleted +setMapboxMetricsEnabledSettingShownInApp: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Made `+[MGLAccountManager setMapboxMetricsEnabledSettingShownInApp:]` unavailable, with a message explaining what to do instead. Removed a commented-out call to that method. Only the environment for an access token if one hasn’t already been set in Info.plist. --- include/mbgl/ios/MGLAccountManager.h | 2 +- ios/app/MBXAppDelegate.m | 32 +++++++++++++--------------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/include/mbgl/ios/MGLAccountManager.h b/include/mbgl/ios/MGLAccountManager.h index 5c1b2e357..6b127543e 100644 --- a/include/mbgl/ios/MGLAccountManager.h +++ b/include/mbgl/ios/MGLAccountManager.h @@ -21,7 +21,7 @@ /** Certain Mapbox plans require the collection of user metrics. If you aren't using a preference switch in an existing or new `Settings.bundle` in your application, set this value to `YES` to indicate that you are providing a metrics opt-out for users within your app's interface directly. * @param showsOptOut Whether your application's interface provides a user opt-out preference. The default value is `NO`, meaning a `Settings.bundle` is expected for providing a user opt-out preference. */ -+ (void)setMapboxMetricsEnabledSettingShownInApp:(BOOL)showsOptOut DEPRECATED_MSG_ATTRIBUTE("Set MGLMapboxMetricsEnabledSettingShownInApp in Info.plist"); ++ (void)setMapboxMetricsEnabledSettingShownInApp:(BOOL)showsOptOut __attribute__((unavailable("Set MGLMapboxMetricsEnabledSettingShownInApp in Info.plist."))); /** Whether in-app user metrics opt-out is configured. If set to the default value of `NO`, a user opt-out preference is expected in a `Settings.bundle` that shows in the application's section within the system Settings app. */ + (BOOL)mapboxMetricsEnabledSettingShownInApp; diff --git a/ios/app/MBXAppDelegate.m b/ios/app/MBXAppDelegate.m index ce699ce69..39868b174 100644 --- a/ios/app/MBXAppDelegate.m +++ b/ios/app/MBXAppDelegate.m @@ -8,24 +8,22 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - // Set Access Token - NSString *accessToken = [[NSProcessInfo processInfo] environment][@"MAPBOX_ACCESS_TOKEN"]; - if (accessToken) { - // Store to preferences so that we can launch the app later on without having to specify - // token. - [[NSUserDefaults standardUserDefaults] setObject:accessToken forKey:@"access_token"]; - } else { - // Try to retrieve from preferences, maybe we've stored them there previously and can reuse - // the token. - accessToken = [[NSUserDefaults standardUserDefaults] objectForKey:@"access_token"]; + // Set access token, unless MGLAccountManager already read it in from Info.plist. + if ( ! [MGLAccountManager accessToken]) { + NSString *accessToken = [[NSProcessInfo processInfo] environment][@"MAPBOX_ACCESS_TOKEN"]; + if (accessToken) { + // Store to preferences so that we can launch the app later on without having to specify + // token. + [[NSUserDefaults standardUserDefaults] setObject:accessToken forKey:@"access_token"]; + } else { + // Try to retrieve from preferences, maybe we've stored them there previously and can reuse + // the token. + accessToken = [[NSUserDefaults standardUserDefaults] objectForKey:@"access_token"]; + } + if ( ! accessToken) NSLog(@"No access token set. Mapbox vector tiles won't work."); + + [MGLAccountManager setAccessToken:accessToken]; } - if ( ! accessToken) NSLog(@"No access token set. Mapbox vector tiles won't work."); - - // Signal To SDK That Opt Out Is In App UI -// [MGLAccountManager setMapboxMetricsEnabledSettingShownInApp:YES]; - - // Start Mapbox GL SDK - [MGLAccountManager setAccessToken:accessToken]; self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; self.window.rootViewController = [[UINavigationController alloc] initWithRootViewController:[MBXViewController new]]; From a04703e2d59ccedf32ef9bbd22169640a5aeec50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Thu, 14 May 2015 00:38:52 -0700 Subject: [PATCH 5/8] Updated Metrics in-app opt-out assertion The message referred to `+[MGLAccountManager setMapboxMetricsEnabledSettingShownInApp:]`, which is no longer available. --- platform/ios/MGLMapboxEvents.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/ios/MGLMapboxEvents.m b/platform/ios/MGLMapboxEvents.m index 017dceeb3..44972395d 100644 --- a/platform/ios/MGLMapboxEvents.m +++ b/platform/ios/MGLMapboxEvents.m @@ -215,7 +215,7 @@ const NSTimeInterval MGLFlushInterval = 60; } } - NSAssert(defaultEnabledValue, @"End users must be able to opt out of Metrics in your app, either inside Settings (via Settings.bundle) or inside this app. If you implement the opt-out control inside this app, disable this assertion by setting [MGLAccountManager setMapboxMetricsEnabledSettingShownInApp:YES] before the app initializes any Mapbox GL classes."); + NSAssert(defaultEnabledValue, @"End users must be able to opt out of Metrics in your app, either inside Settings (via Settings.bundle) or inside this app. If you implement the opt-out control inside this app, disable this assertion by setting MGLMapboxMetricsEnabledSettingShownInApp to YES in Info.plist."); [[NSUserDefaults standardUserDefaults] registerDefaults:@{ @"MGLMapboxMetricsEnabled": defaultEnabledValue, }]; From 9a57464f823b36dc0c7b0db75f742a40513ffc87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Wed, 20 May 2015 10:45:26 -0700 Subject: [PATCH 6/8] Removed accessToken from MGLMapView public API With helpful instructions for migrating to Info.plist or the `MGLAccountManager` API. --- include/mbgl/ios/MGLMapView.h | 27 +++++++++++---------------- platform/ios/MGLMapView.mm | 28 ++++++++++++---------------- 2 files changed, 23 insertions(+), 32 deletions(-) diff --git a/include/mbgl/ios/MGLMapView.h b/include/mbgl/ios/MGLMapView.h index 9d7b5c901..2d6589bf0 100644 --- a/include/mbgl/ios/MGLMapView.h +++ b/include/mbgl/ios/MGLMapView.h @@ -20,30 +20,25 @@ IB_DESIGNABLE /** @name Initializing a Map View */ -/** Initialize a map view with the default style, given frame, and access token set in MapboxGL singleton. -* @param frame The frame with which to initialize the map view. -* @return An initialized map view, or `nil` if the map view was unable to be initialized. */ +/** Initializes and returns a newly allocated map view with the specified frame and the default style. +* @param frame The frame for the view, measured in points. +* @return An initialized map view or `nil` if the map view couldn’t be created. */ - (instancetype)initWithFrame:(CGRect)frame; +- (instancetype)initWithFrame:(CGRect)frame accessToken:(NSString *)accessToken __attribute__((unavailable("Use -initWithFrame:. Set MGLMapboxAccessToken in the Info.plist or call +[MGLAccountManager setAccessToken:]."))); -/** Initialize a map view with the default style and a given frame and access token. -* @param frame The frame with which to initialize the map view. -* @param accessToken A Mapbox API access token. -* @return An initialized map view, or `nil` if the map view was unable to be initialized. */ -- (instancetype)initWithFrame:(CGRect)frame accessToken:(NSString *)accessToken; - -/** Initialize a map view with a given frame, access token, and style URL. - * @param frame The frame with which to initialize the map view. - * @param accessToken A Mapbox API access token. - * @param styleURL The map style URL to use. Can be either an HTTP/HTTPS URL or a Mapbox map ID style URL (`mapbox://`). - * @return An initialized map view, or `nil` if the map view was unable to be initialized. */ -- (instancetype)initWithFrame:(CGRect)frame accessToken:(NSString *)accessToken styleURL:(NSURL *)styleURL; +/** Initializes and returns a newly allocated map view with the specified frame and style URL. +* @param frame The frame for the view, measured in points. +* @param styleURL The map style URL to use. Can be either an HTTP/HTTPS URL or a Mapbox map ID style URL (`mapbox://`). +* @return An initialized map view or `nil` if the map view couldn’t be created. */ +- (instancetype)initWithFrame:(CGRect)frame styleURL:(NSURL *)styleURL; +- (instancetype)initWithFrame:(CGRect)frame accessToken:(NSString *)accessToken styleURL:(NSURL *)styleURL __attribute__((unavailable("Use -initWithFrame:styleURL:. Set MGLMapboxAccessToken in the Info.plist or call +[MGLAccountManager setAccessToken:]."))); #pragma mark - Authorizing Access /** @name Authorizing Access */ /** Mapbox API access token for the map view. */ -@property (nonatomic) NSString *accessToken; +@property (nonatomic) NSString *accessToken __attribute__((unavailable("Use +[MGLAccountManager accessToken] and +[MGLAccountManager setAccessToken:]."))); #pragma mark - Managing Constraints diff --git a/platform/ios/MGLMapView.mm b/platform/ios/MGLMapView.mm index 4be5d20d2..cb89c58d4 100644 --- a/platform/ios/MGLMapView.mm +++ b/platform/ios/MGLMapView.mm @@ -113,25 +113,18 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration) if (self && [self commonInit]) { self.styleURL = nil; - self.accessToken = [MGLAccountManager accessToken]; return self; } return nil; } -- (instancetype)initWithFrame:(CGRect)frame accessToken:(NSString *)accessToken -{ - return [self initWithFrame:frame accessToken:accessToken styleURL:nil]; -} - -- (instancetype)initWithFrame:(CGRect)frame accessToken:(NSString *)accessToken styleURL:(NSURL *)styleURL +- (instancetype)initWithFrame:(CGRect)frame styleURL:(NSURL *)styleURL { self = [super initWithFrame:frame]; if (self && [self commonInit]) { - self.accessToken = accessToken; self.styleURL = styleURL; } @@ -153,19 +146,18 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration) - (NSString *)accessToken { - NSString *accessToken = @(_mbglMap->getAccessToken().c_str()).mgl_stringOrNilIfEmpty; - return accessToken ? accessToken : [MGLAccountManager accessToken]; + NSAssert(NO, @"-[MGLMapView accessToken] has been removed. Use +[MGLAccountManager accessToken] or get MGLMapboxAccessToken from the Info.plist."); + return nil; } - (void)setAccessToken:(NSString *)accessToken { - _mbglMap->setAccessToken(accessToken ? (std::string)[accessToken UTF8String] : ""); - [MGLAccountManager setAccessToken:accessToken.mgl_stringOrNilIfEmpty]; + NSAssert(NO, @"-[MGLMapView setAccessToken:] has been replaced by +[MGLAccountManager setAccessToken:].\n\nIf you previously set this access token in a storyboard inspectable, select the MGLMapView in Interface Builder and delete the “accessToken” entry from the User Defined Runtime Attributes section of the Identity inspector. Then go to the Info.plist file and set MGLMapboxAccessToken to “%@”.", accessToken); } + (NSSet *)keyPathsForValuesAffectingStyleURL { - return [NSSet setWithObjects:@"mapID", @"accessToken", nil]; + return [NSSet setWithObjects:@"mapID", nil]; } - (NSURL *)styleURL @@ -274,6 +266,10 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration) } _mbglMap->resize(self.bounds.size.width, self.bounds.size.height, _glView.contentScaleFactor); + // mbgl::Map keeps its own copy of the access token. + NSString *accessToken = [MGLAccountManager accessToken]; + _mbglMap->setAccessToken(accessToken ? (std::string)[accessToken UTF8String] : ""); + // Notify map object when network reachability status changes. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reachabilityChanged:) @@ -1557,7 +1553,7 @@ CLLocationCoordinate2D latLngToCoordinate(mbgl::LatLng latLng) + (NSSet *)keyPathsForValuesAffectingMapID { - return [NSSet setWithObjects:@"styleURL", @"accessToken", nil]; + return [NSSet setWithObjects:@"styleURL", nil]; } - (NSString *)mapID @@ -2495,7 +2491,7 @@ CLLocationCoordinate2D latLngToCoordinate(mbgl::LatLng latLng) self.layer.borderColor = [UIColor colorWithWhite:184/255. alpha:1].CGColor; self.layer.borderWidth = 1; - if (self.accessToken) + if ([MGLAccountManager accessToken]) { self.layer.backgroundColor = [UIColor colorWithRed:59/255. green:178/255. @@ -2560,7 +2556,7 @@ CLLocationCoordinate2D latLngToCoordinate(mbgl::LatLng latLng) // More explanation UILabel *explanationLabel2 = [[UILabel alloc] init]; - explanationLabel2.text = @"and enter it into the Access Token field in the Attributes inspector or in an MGLMapboxAccessToken entry in the Info.plist file."; + explanationLabel2.text = @"and set it as the value of MGLMapboxAccessToken in the Info.plist file."; explanationLabel2.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody]; explanationLabel2.numberOfLines = 0; explanationLabel2.translatesAutoresizingMaskIntoConstraints = NO; From a081f1af5b7c173da5f5c1beaec8c274aeb353de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Wed, 20 May 2015 10:47:42 -0700 Subject: [PATCH 7/8] Removed redundant declaration --- platform/ios/MGLAccountManager.m | 2 -- 1 file changed, 2 deletions(-) diff --git a/platform/ios/MGLAccountManager.m b/platform/ios/MGLAccountManager.m index d5b89e9f9..97d7e5e5e 100644 --- a/platform/ios/MGLAccountManager.m +++ b/platform/ios/MGLAccountManager.m @@ -9,8 +9,6 @@ @property (atomic) BOOL mapboxMetricsEnabledSettingShownInApp; @property (atomic) NSString *accessToken; -+ (void)setMapboxMetricsEnabledSettingShownInApp:(BOOL)showsOptOut; - @end From 90a50c0c4150080f725cc6b66909eef58a2a9b4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Wed, 20 May 2015 11:49:59 -0700 Subject: [PATCH 8/8] Observe access token changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The singleton `MGLAccountManager` wants to be the sole arbiter of the access token, but each instance of `mbgl::Map` (`mbgl::DefaultFileSource` in #1607) has its own copy of the access token. Now `MGLMapView` observes for changes to the `MGLAccountManager`’s access token and synchronizes `mbgl::Map` with it. --- gyp/platform-ios.gypi | 1 + platform/ios/MGLAccountManager.m | 2 +- platform/ios/MGLAccountManager_Private.h | 10 ++++++++++ platform/ios/MGLMapView.mm | 22 ++++++++++++++++++---- 4 files changed, 30 insertions(+), 5 deletions(-) create mode 100644 platform/ios/MGLAccountManager_Private.h diff --git a/gyp/platform-ios.gypi b/gyp/platform-ios.gypi index 7e91648c4..12cbd9592 100644 --- a/gyp/platform-ios.gypi +++ b/gyp/platform-ios.gypi @@ -27,6 +27,7 @@ '../platform/ios/MGLFileCache.h', '../platform/ios/MGLFileCache.mm', '../include/mbgl/ios/MGLAccountManager.h', + '../platform/ios/MGLAccountManager_Private.h', '../platform/ios/MGLAccountManager.m', '../include/mbgl/ios/MGLAnnotation.h', '../include/mbgl/ios/MGLUserLocation.h', diff --git a/platform/ios/MGLAccountManager.m b/platform/ios/MGLAccountManager.m index 97d7e5e5e..38ef1f4ca 100644 --- a/platform/ios/MGLAccountManager.m +++ b/platform/ios/MGLAccountManager.m @@ -1,6 +1,6 @@ #import -#import "MGLAccountManager.h" +#import "MGLAccountManager_Private.h" #import "MGLMapboxEvents_Private.h" #import "NSProcessInfo+MGLAdditions.h" diff --git a/platform/ios/MGLAccountManager_Private.h b/platform/ios/MGLAccountManager_Private.h new file mode 100644 index 000000000..3cc05b09f --- /dev/null +++ b/platform/ios/MGLAccountManager_Private.h @@ -0,0 +1,10 @@ +#import "MGLAccountManager.h" + +@interface MGLAccountManager (Private) + +/** Returns the shared instance of the `MGLAccountManager` class. */ ++ (instancetype)sharedManager; + +@property (atomic) NSString *accessToken; + +@end diff --git a/platform/ios/MGLMapView.mm b/platform/ios/MGLMapView.mm index cb89c58d4..997d5734a 100644 --- a/platform/ios/MGLMapView.mm +++ b/platform/ios/MGLMapView.mm @@ -20,7 +20,7 @@ #import "NSString+MGLAdditions.h" #import "NSProcessInfo+MGLAdditions.h" #import "NSException+MGLAdditions.h" -#import "MGLAccountManager.h" +#import "MGLAccountManager_Private.h" #import "MGLAnnotation.h" #import "MGLUserLocationAnnotationView.h" #import "MGLUserLocation_Private.h" @@ -266,9 +266,12 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration) } _mbglMap->resize(self.bounds.size.width, self.bounds.size.height, _glView.contentScaleFactor); - // mbgl::Map keeps its own copy of the access token. - NSString *accessToken = [MGLAccountManager accessToken]; - _mbglMap->setAccessToken(accessToken ? (std::string)[accessToken UTF8String] : ""); + // Observe for changes to the global access token (and find out the current one). + [[MGLAccountManager sharedManager] addObserver:self + forKeyPath:@"accessToken" + options:(NSKeyValueObservingOptionInitial | + NSKeyValueObservingOptionNew) + context:NULL]; // Notify map object when network reachability status changes. [[NSNotificationCenter defaultCenter] addObserver:self @@ -410,6 +413,7 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration) [_regionChangeDelegateQueue cancelAllOperations]; [[NSNotificationCenter defaultCenter] removeObserver:self]; + [[MGLAccountManager sharedManager] removeObserver:self forKeyPath:@"accessToken"]; if (_mbglMap) { @@ -1292,6 +1296,16 @@ std::chrono::steady_clock::duration secondsAsDuration(float duration) #pragma mark - Properties - +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(__unused void *)context +{ + // Synchronize mbgl::Map’s access token with the global one in MGLAccountManager. + if ([keyPath isEqualToString:@"accessToken"] && object == [MGLAccountManager sharedManager]) + { + NSString *accessToken = change[NSKeyValueChangeNewKey]; + _mbglMap->setAccessToken(accessToken ? (std::string)[accessToken UTF8String] : ""); + } +} + + (NSSet *)keyPathsForValuesAffectingZoomEnabled { return [NSSet setWithObject:@"allowsZooming"];