diff --git a/gyp/platform-ios.gypi b/gyp/platform-ios.gypi index 0f709d69496..0bb9b5fe39e 100644 --- a/gyp/platform-ios.gypi +++ b/gyp/platform-ios.gypi @@ -25,9 +25,9 @@ '../platform/ios/MGLMapView.mm', '../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/MGLConfigurationManager.h', + '../platform/ios/MGLConfigurationManager_Private.h', + '../platform/ios/MGLConfigurationManager.m', '../include/mbgl/ios/MGLAnnotation.h', '../include/mbgl/ios/MGLUserLocation.h', '../platform/ios/MGLUserLocation_Private.h', diff --git a/include/mbgl/ios/MGLAccountManager.h b/include/mbgl/ios/MGLAccountManager.h index 9bfb3b497e6..7d31f922726 100644 --- a/include/mbgl/ios/MGLAccountManager.h +++ b/include/mbgl/ios/MGLAccountManager.h @@ -3,29 +3,29 @@ NS_ASSUME_NONNULL_BEGIN /** The MGLAccountManager object provides a global way to set a Mapbox API access token, as well as other settings used framework-wide. */ +__deprecated @interface MGLAccountManager : NSObject /** @name Authorizing Access */ /** Set the Mapbox API access token for the framework. * -* You can set an access token on MGLAccountManager or on an individual map view. The same token is used throughout the framework. +* You can set an access token on MGLConfigurationManager or on an individual map view. The same token is used throughout the framework. * @param accessToken The Mapbox API access token. */ -+ (void)setAccessToken:(nullable NSString *)accessToken; ++ (void)setAccessToken:(nullable NSString *)accessToken __deprecated_msg("Use + setAccessToken in MGLConfigurationManager"); /** Retreive the Mapbox API access token for the framework. * -* You can set an access token on MGLAccountManager or on an individual map view. The same token is used throughout the framework. +* You can set an access token on MGLConfigurationManager or on an individual map view. The same token is used throughout the framework. * @return accessToken The Mapbox API access token. */ -+ (nullable NSString *)accessToken; ++ (nullable NSString *)accessToken __deprecated_msg("Use + accessToken in MGLConfigurationManager"); /** @name Providing User Metrics Opt-Out */ - + (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; ++ (BOOL)mapboxMetricsEnabledSettingShownInApp __deprecated_msg("Use + mapboxMetricsEnabledSettingShownInApp in MGLConfigurationManager"); @end -NS_ASSUME_NONNULL_END +NS_ASSUME_NONNULL_END \ No newline at end of file diff --git a/include/mbgl/ios/MGLConfigurationManager.h b/include/mbgl/ios/MGLConfigurationManager.h new file mode 100644 index 00000000000..065900814ee --- /dev/null +++ b/include/mbgl/ios/MGLConfigurationManager.h @@ -0,0 +1,43 @@ +#import "MGLTypes.h" +#import + +NS_ASSUME_NONNULL_BEGIN + +/** The MGLConfigurationManager object provides a global way to set a Mapbox API access token, as well as other settings used framework-wide. */ +@interface MGLConfigurationManager : NSObject + +/** @name Authorizing Access */ + +/** Set the Mapbox API access token for the framework. +* +* You can set an access token on MGLConfigurationManager or on an individual map view. The same token is used throughout the framework. +* @param accessToken The Mapbox API access token. */ ++ (void)setAccessToken:(nullable NSString *)accessToken; + +/** Retreive the Mapbox API access token for the framework. +* +* You can set an access token on MGLConfigurationManager or on an individual map view. The same token is used throughout the framework. +* @return accessToken The Mapbox API access token. */ ++ (nullable NSString *)accessToken; + +/** @name Providing User Metrics Opt-Out */ ++ (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; + +/** Set the type of activity associated with location updates for the application. +* +* You can configure the activity type associated with location updates that make the most sense for youre application. +* @param activityType The desired CLActivityType */ ++ (void)setActivityType:(CLActivityType)activityType; + +/** Retreive the type of activity associated with location updates for the application. +* +* You can configure the activity type associated with location updates that make the most sense for your application. +* @return activityType The configured CLActivityType*/ ++ (CLActivityType)activityType; + +@end + +NS_ASSUME_NONNULL_END diff --git a/include/mbgl/ios/MGLMapView.h b/include/mbgl/ios/MGLMapView.h index 2b9a3d29138..cefff469c99 100644 --- a/include/mbgl/ios/MGLMapView.h +++ b/include/mbgl/ios/MGLMapView.h @@ -30,20 +30,20 @@ IB_DESIGNABLE * @param frame The frame for the view, measured in points. * @return An initialized map view. */ - (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:]."))); +- (instancetype)initWithFrame:(CGRect)frame accessToken:(NSString *)accessToken __attribute__((unavailable("Use -initWithFrame:. Set MGLMapboxAccessToken in the Info.plist or call +[MGLConfigurationManager setAccessToken:]."))); /** 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://`). Specify `nil` for the default style. * @return An initialized map view. */ - (instancetype)initWithFrame:(CGRect)frame styleURL:(nullable NSURL *)styleURL; -- (instancetype)initWithFrame:(CGRect)frame accessToken:(NSString *)accessToken styleURL:(nullable NSURL *)styleURL __attribute__((unavailable("Use -initWithFrame:styleURL:. Set MGLMapboxAccessToken in the Info.plist or call +[MGLAccountManager setAccessToken:]."))); +- (instancetype)initWithFrame:(CGRect)frame accessToken:(NSString *)accessToken styleURL:(nullable NSURL *)styleURL __attribute__((unavailable("Use -initWithFrame:styleURL:. Set MGLMapboxAccessToken in the Info.plist or call +[MGLConfigurationManager setAccessToken:]."))); #pragma mark - Authorizing Access /** @name Authorizing Access */ -@property (nonatomic, nullable) NSString *accessToken __attribute__((unavailable("Use +[MGLAccountManager accessToken] and +[MGLAccountManager setAccessToken:]."))); +@property (nonatomic, nullable) NSString *accessToken __attribute__((unavailable("Use +[MGLConfigurationManager accessToken] and +[MGLConfigurationManager setAccessToken:]."))); #pragma mark - Managing Constraints diff --git a/include/mbgl/ios/Mapbox.h b/include/mbgl/ios/Mapbox.h index 401a62e82e1..01f66ff3438 100644 --- a/include/mbgl/ios/Mapbox.h +++ b/include/mbgl/ios/Mapbox.h @@ -1,4 +1,4 @@ -#import "MGLAccountManager.h" +#import "MGLConfigurationManager.h" #import "MGLAnnotation.h" #import "MGLAnnotationImage.h" #import "MGLGeometry.h" diff --git a/ios/app/MBXAppDelegate.m b/ios/app/MBXAppDelegate.m index bca039739ad..fa28eb3000d 100644 --- a/ios/app/MBXAppDelegate.m +++ b/ios/app/MBXAppDelegate.m @@ -6,8 +6,8 @@ @implementation MBXAppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - // Set access token, unless MGLAccountManager already read it in from Info.plist. - if ( ! [MGLAccountManager accessToken]) { + // Set access token, unless MGLConfigurationManager already read it in from Info.plist. + if ( ! [MGLConfigurationManager 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 @@ -20,7 +20,7 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( } if ( ! accessToken) NSLog(@"No access token set. Mapbox vector tiles won't work."); - [MGLAccountManager setAccessToken:accessToken]; + [MGLConfigurationManager setAccessToken:accessToken]; } self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; diff --git a/platform/ios/MGLAccountManager.m b/platform/ios/MGLAccountManager.m index 710ddd3e38a..b7420c9ca4b 100644 --- a/platform/ios/MGLAccountManager.m +++ b/platform/ios/MGLAccountManager.m @@ -1,73 +1,18 @@ -#import "MGLAccountManager_Private.h" -#import "MGLMapboxEvents.h" -#import "NSProcessInfo+MGLAdditions.h" - -@interface MGLAccountManager() - -@property (atomic) BOOL mapboxMetricsEnabledSettingShownInApp; -@property (atomic) NSString *accessToken; - -@end - +#import "MGLAccountManager.h" +#import "MGLConfigurationManager.h" @implementation MGLAccountManager -+ (void)load { - // Read the initial configuration from Info.plist. The shown-in-app setting - // preempts the Settings bundle check in -[MGLMapboxEvents init] triggered - // by setting the access token. - NSBundle *bundle = [NSBundle mainBundle]; - NSNumber *shownInAppNumber = [bundle objectForInfoDictionaryKey:@"MGLMapboxMetricsEnabledSettingShownInApp"]; - if (shownInAppNumber) { - [MGLAccountManager sharedManager].mapboxMetricsEnabledSettingShownInApp = [shownInAppNumber boolValue]; - } - NSString *accessToken = [bundle objectForInfoDictionaryKey:@"MGLMapboxAccessToken"]; - if (accessToken.length) { - self.accessToken = accessToken; - } -} - -// Can be called from any thread. -// -+ (instancetype) sharedManager { - if (NSProcessInfo.processInfo.mgl_isInterfaceBuilderDesignablesAgent) { - return nil; - } - static dispatch_once_t onceToken; - static MGLAccountManager *_sharedManager; - void (^setupBlock)() = ^{ - dispatch_once(&onceToken, ^{ - _sharedManager = [[self alloc] init]; - }); - }; - if ( ! [[NSThread currentThread] isMainThread]) { - dispatch_sync(dispatch_get_main_queue(), ^{ - setupBlock(); - }); - } - else { - setupBlock(); - } - return _sharedManager; ++ (void)setAccessToken:(nullable NSString *)accessToken { + [MGLConfigurationManager setAccessToken:accessToken]; } -+ (BOOL) mapboxMetricsEnabledSettingShownInApp { - return [MGLAccountManager sharedManager].mapboxMetricsEnabledSettingShownInApp; ++ (nullable NSString *)accessToken { + return [MGLConfigurationManager accessToken]; } -+ (void) setAccessToken:(NSString *) accessToken { - if ( ! [accessToken length]) return; - - [MGLAccountManager sharedManager].accessToken = accessToken; - - // Update MGLMapboxEvents - // NOTE: This is (likely) the initial setup of MGLMapboxEvents - [MGLMapboxEvents sharedManager]; ++ (BOOL)mapboxMetricsEnabledSettingShownInApp { + return [MGLConfigurationManager mapboxMetricsEnabledSettingShownInApp]; } -+ (NSString *) accessToken { - return [MGLAccountManager sharedManager].accessToken; -} - - @end \ No newline at end of file diff --git a/platform/ios/MGLAccountManager_Private.h b/platform/ios/MGLAccountManager_Private.h deleted file mode 100644 index 3cc05b09f0f..00000000000 --- a/platform/ios/MGLAccountManager_Private.h +++ /dev/null @@ -1,10 +0,0 @@ -#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/MGLConfigurationManager.m b/platform/ios/MGLConfigurationManager.m new file mode 100644 index 00000000000..a7f4452e0bc --- /dev/null +++ b/platform/ios/MGLConfigurationManager.m @@ -0,0 +1,117 @@ +#import "MGLConfigurationManager_Private.h" +#import "MGLMapboxEvents.h" +#import "NSProcessInfo+MGLAdditions.h" + +static NSString * const kMGLMapboxMetricsEnabledSettingShownInApp = @"MGLMapboxMetricsEnabledSettingShownInApp"; +static NSString * const kMGLMapboxAccessToken = @"MGLMapboxAccessToken"; +static NSString * const kMGLMapboxActivityType = @"MGLMapboxActivityType"; + +// Used for parsing options specified in info.plist +static NSString * const kMGLMapboxActivityTypeOther = @"Other"; +static NSString * const kMGLMapboxActivityTypeAutomotiveNavigation = @"AutomotiveNavigation"; +static NSString * const kMGLMapboxActivityTypeFitness = @"Fitness"; +static NSString * const kMGLMapboxActivityTypeOtherNavigation = @"OtherNavigation"; + +@interface MGLConfigurationManager () + +@property (atomic) BOOL mapboxMetricsEnabledSettingShownInApp; +@property (atomic) NSString *accessToken; +@property (atomic) CLActivityType activityType; + +@end + + +@implementation MGLConfigurationManager + ++ (void)load { + // Read the initial configuration from Info.plist. The shown-in-app setting + // preempts the Settings bundle check in -[MGLMapboxEvents init] triggered + // by setting the access token. + NSBundle *bundle = [NSBundle mainBundle]; + + NSNumber *shownInAppNumber = [bundle objectForInfoDictionaryKey:kMGLMapboxMetricsEnabledSettingShownInApp]; + if (shownInAppNumber) { + [MGLConfigurationManager sharedManager].mapboxMetricsEnabledSettingShownInApp = [shownInAppNumber boolValue]; + } + + NSString *accessToken = [bundle objectForInfoDictionaryKey:kMGLMapboxAccessToken]; + if (accessToken.length) { + self.accessToken = accessToken; + } + + NSString *activityType = [bundle objectForInfoDictionaryKey:kMGLMapboxActivityType]; + if (activityType.length) { + self.activityType = [self activityTypeForBundleStringValue:activityType]; + } +} + +// Can be called from any thread. +// ++ (instancetype) sharedManager { + if (NSProcessInfo.processInfo.mgl_isInterfaceBuilderDesignablesAgent) { + return nil; + } + static dispatch_once_t onceToken; + static MGLConfigurationManager *_sharedManager; + void (^setupBlock)() = ^{ + dispatch_once(&onceToken, ^{ + _sharedManager = [[self alloc] init]; + }); + }; + if ( ! [[NSThread currentThread] isMainThread]) { + dispatch_sync(dispatch_get_main_queue(), ^{ + setupBlock(); + }); + } + else { + setupBlock(); + } + return _sharedManager; +} + ++ (BOOL) mapboxMetricsEnabledSettingShownInApp { + return [MGLConfigurationManager sharedManager].mapboxMetricsEnabledSettingShownInApp; +} + ++ (void) setAccessToken:(NSString *) accessToken { + if ( ! [accessToken length]) return; + + [MGLConfigurationManager sharedManager].accessToken = accessToken; + + // Update MGLMapboxEvents + // NOTE: This is (likely) the initial setup of MGLMapboxEvents + [MGLMapboxEvents sharedManager]; +} + ++ (NSString *) accessToken { + return [MGLConfigurationManager sharedManager].accessToken; +} + ++ (void) setActivityType:(CLActivityType)activityType { + [MGLConfigurationManager sharedManager].activityType = activityType; + + // Ensure MGLMapboxEvents configures location manager with new activity type + [MGLMapboxEvents validate]; +} + ++ (CLActivityType) activityType { + return [MGLConfigurationManager sharedManager].activityType; +} + +#pragma mark - Utility + ++ (CLActivityType)activityTypeForBundleStringValue:(NSString *)stringValue { + if ([stringValue isEqualToString:kMGLMapboxActivityTypeAutomotiveNavigation]) { + return CLActivityTypeAutomotiveNavigation; + } + if ([stringValue isEqual:kMGLMapboxActivityTypeFitness]) { + return CLActivityTypeFitness; + } + if ([stringValue isEqual:kMGLMapboxActivityTypeOtherNavigation]) { + return CLActivityTypeOtherNavigation; + } + return CLActivityTypeOther; +} + + +@end \ No newline at end of file diff --git a/platform/ios/MGLConfigurationManager_Private.h b/platform/ios/MGLConfigurationManager_Private.h new file mode 100644 index 00000000000..1fbc38fc935 --- /dev/null +++ b/platform/ios/MGLConfigurationManager_Private.h @@ -0,0 +1,8 @@ +#import "MGLConfigurationManager.h" + +@interface MGLConfigurationManager (Private) + +/** Returns the shared instance of the `MGLConfigurationManager` class. */ ++ (instancetype)sharedManager; + +@end diff --git a/platform/ios/MGLMapView.mm b/platform/ios/MGLMapView.mm index 391763b9459..12a0fb09332 100644 --- a/platform/ios/MGLMapView.mm +++ b/platform/ios/MGLMapView.mm @@ -29,7 +29,7 @@ #import "MGLUserLocationAnnotationView.h" #import "MGLUserLocation_Private.h" #import "MGLFileCache.h" -#import "MGLAccountManager_Private.h" +#import "MGLConfigurationManager_Private.h" #import "MGLMapboxEvents.h" #import "SMCalloutView.h" @@ -158,7 +158,7 @@ - (nullable NSString *)accessToken { [NSException raise:@"Method unavailable" format: @"%s has been removed. " - @"Use +[MGLAccountManager accessToken] or get MGLMapboxAccessToken from the Info.plist.", + @"Use +[MGLConfigurationManager accessToken] or get MGLMapboxAccessToken from the Info.plist.", __PRETTY_FUNCTION__]; return nil; } @@ -166,7 +166,7 @@ - (nullable NSString *)accessToken - (void)setAccessToken:(nullable NSString *)accessToken { [NSException raise:@"Method unavailable" format: - @"%s has been replaced by +[MGLAccountManager setAccessToken:].\n\n" + @"%s has been replaced by +[MGLConfigurationManager setAccessToken:].\n\n" @"If 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 “%@”.", __PRETTY_FUNCTION__, accessToken]; @@ -232,7 +232,7 @@ - (void)commonInit } // Observe for changes to the global access token (and find out the current one). - [[MGLAccountManager sharedManager] addObserver:self + [[MGLConfigurationManager sharedManager] addObserver:self forKeyPath:@"accessToken" options:(NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew) @@ -289,7 +289,7 @@ - (void)commonInit nil]; // iOS 8+: add action that opens app's Settings.app panel, if applicable - if (&UIApplicationOpenSettingsURLString != NULL && ! [MGLAccountManager mapboxMetricsEnabledSettingShownInApp]) + if (&UIApplicationOpenSettingsURLString != NULL && ! [MGLConfigurationManager mapboxMetricsEnabledSettingShownInApp]) { [_attributionSheet addButtonWithTitle:@"Adjust Privacy Settings"]; } @@ -432,7 +432,7 @@ - (void)dealloc [_regionChangeDelegateQueue cancelAllOperations]; [[NSNotificationCenter defaultCenter] removeObserver:self]; - [[MGLAccountManager sharedManager] removeObserver:self forKeyPath:@"accessToken"]; + [[MGLConfigurationManager sharedManager] removeObserver:self forKeyPath:@"accessToken"]; if (_mbglMap) { @@ -1393,8 +1393,8 @@ - (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSIn - (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]) + // Synchronize mbgl::Map’s access token with the global one in MGLConfigurationManager. + if ([keyPath isEqualToString:@"accessToken"] && object == [MGLConfigurationManager sharedManager]) { NSString *accessToken = change[NSKeyValueChangeNewKey]; if (![accessToken isKindOfClass:[NSNull class]]) { diff --git a/platform/ios/MGLMapboxEvents.m b/platform/ios/MGLMapboxEvents.m index 314d50dd01f..124e83ed8f4 100644 --- a/platform/ios/MGLMapboxEvents.m +++ b/platform/ios/MGLMapboxEvents.m @@ -2,11 +2,11 @@ #import #import +#import #import #import -#import -#import "MGLAccountManager.h" +#import "MGLConfigurationManager.h" #import "NSProcessInfo+MGLAdditions.h" #import "NSBundle+MGLAdditions.h" #import "NSException+MGLAdditions.h" @@ -65,6 +65,7 @@ @interface MGLMapboxEventsData : NSObject @implementation MGLMapboxEventsData + - (instancetype)init { if (self = [super init]) { @@ -200,7 +201,7 @@ - (instancetype) init { self = [super init]; if (self) { - if (! [MGLAccountManager mapboxMetricsEnabledSettingShownInApp] && + if (! [MGLConfigurationManager mapboxMetricsEnabledSettingShownInApp] && [[NSUserDefaults standardUserDefaults] integerForKey:@"MGLMapboxAccountType"] == 0) { // Opt Out is not configured in UI, so check for Settings.bundle // Put Settings bundle into memory @@ -427,10 +428,12 @@ - (void)startUpdatingLocation { @"MGLMapboxEvents should not have a CLLocationManager while paused."); return; } + _locationManager = [[CLLocationManager alloc] init]; _locationManager.desiredAccuracy = kCLLocationAccuracyKilometer; _locationManager.distanceFilter = 10; _locationManager.delegate = self; + _locationManager.activityType = [MGLConfigurationManager accessToken]; [_locationManager startUpdatingLocation]; @@ -556,7 +559,7 @@ + (void) flush { // Can be called from any thread. // - (void) flush { - if ([MGLAccountManager accessToken] == nil) return; + if ([MGLConfigurationManager accessToken] == nil) return; __weak MGLMapboxEvents *weakSelf = self; @@ -592,7 +595,7 @@ - (void) postEvents:(NS_ARRAY_OF(MGLMapboxEventAttributes *) *)events { if (!strongSelf) return; // Setup URL Request - NSString *url = [NSString stringWithFormat:@"%@/events/v1?access_token=%@", MGLMapboxEventsAPIBase, [MGLAccountManager accessToken]]; + NSString *url = [NSString stringWithFormat:@"%@/events/v1?access_token=%@", MGLMapboxEventsAPIBase, [MGLConfigurationManager accessToken]]; NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:url]]; [request setValue:strongSelf.userAgent forHTTPHeaderField:@"User-Agent"]; [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];