[ios] Add telemetry setting directly to attribution button action sheet
- Deprecate and no-op `+[MGLAccountManager mapboxMetricsEnabledSettingShownInApp]` - Check for attribution button hiding and make sure ToS are understood
This commit is contained in:
@@ -50,6 +50,7 @@ Known issues:
|
||||
- The map view’s background can now be transparent or translucent, as long as the style’s background layer is transparent or translucent and `MGLMapView.opaque` is set to `NO`. ([#3096](https://github.com/mapbox/mapbox-gl-native/pull/3096))
|
||||
- Documentation is now generated by [jazzy](https://github.com/realm/jazzy) instead of appledoc. ♪♫ ([#3203](https://github.com/mapbox/mapbox-gl-native/pull/3203))
|
||||
- New API to provide a custom callout view to the map for annotations. ([#3456](https://github.com/mapbox/mapbox-gl-native/pull/3456))
|
||||
- Make telemetry on/off setting available in-app. ([#3445](https://github.com/mapbox/mapbox-gl-native/pull/3445))
|
||||
|
||||
## iOS 3.0.1
|
||||
|
||||
|
||||
@@ -26,12 +26,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
*/
|
||||
+ (nullable NSString *)accessToken;
|
||||
|
||||
#pragma mark Providing User Metrics Opt-Out
|
||||
|
||||
/**
|
||||
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 __attribute__((deprecated("Telemetry settings are now always shown in the ℹ️ menu.")));
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -129,8 +129,8 @@ IB_DESIGNABLE
|
||||
@property (nonatomic, readonly) UIImageView *logoView;
|
||||
|
||||
/**
|
||||
A view showing legally required copyright notices, positioned at the
|
||||
bottom-right of the map view.
|
||||
A view showing legally required copyright notices and telemetry settings,
|
||||
positioned at the bottom-right of the map view.
|
||||
|
||||
@note The Mapbox terms of service, which governs the use of Mapbox-hosted
|
||||
vector tiles and styles,
|
||||
@@ -139,6 +139,14 @@ IB_DESIGNABLE
|
||||
OpenStreetMap data, or other Mapbox data such as satellite or terrain
|
||||
data. If that applies to this map view, do not hide this view or remove
|
||||
any notices from it.
|
||||
|
||||
@note You are additionally
|
||||
[required](https://www.mapbox.com/help/metrics-opt-out-for-users/) to
|
||||
provide users with the option to disable anonymous usage and location
|
||||
sharing (telemetry). If this view is hidden, you must implement this
|
||||
setting elsewhere in your app or via `Settings.bundle`. See our
|
||||
[website](https://www.mapbox.com/ios-sdk/#telemetry_opt_out) for
|
||||
implementation help.
|
||||
*/
|
||||
@property (nonatomic, readonly) UIButton *attributionButton;
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<key>Key</key>
|
||||
<string>MGLMapboxMetricsEnabled</string>
|
||||
<key>Title</key>
|
||||
<string>Mapbox Metrics</string>
|
||||
<string>Mapbox Telemetry</string>
|
||||
<key>Type</key>
|
||||
<string>PSToggleSwitchSpecifier</string>
|
||||
<key>TrueValue</key>
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
"Privacy Settings" = "Privacy Settings";
|
||||
"Mapbox Metrics" = "Mapbox Metrics";
|
||||
"Mapbox Telemetry" = "Mapbox Telemetry";
|
||||
"This setting allows the application to share anonymized location and usage data with Mapbox." = "This setting allows the application to share anonymized location and usage data with Mapbox.";
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<key>Key</key>
|
||||
<string>MGLMapboxMetricsEnabled</string>
|
||||
<key>Title</key>
|
||||
<string>Mapbox Metrics</string>
|
||||
<string>Mapbox Telemetry</string>
|
||||
<key>Type</key>
|
||||
<string>PSToggleSwitchSpecifier</string>
|
||||
<key>TrueValue</key>
|
||||
|
||||
Binary file not shown.
@@ -8,7 +8,6 @@
|
||||
|
||||
@interface MGLAccountManager() <FABKit>
|
||||
|
||||
@property (atomic) BOOL mapboxMetricsEnabledSettingShownInApp;
|
||||
@property (atomic) NSString *accessToken;
|
||||
|
||||
@end
|
||||
@@ -21,15 +20,8 @@
|
||||
// Load all referenced categories due to absence of -ObjC linker flag
|
||||
[MGLCategoryLoader loadCategories];
|
||||
|
||||
// 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"];
|
||||
// Read the initial configuration from Info.plist.
|
||||
NSString *accessToken = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"MGLMapboxAccessToken"];
|
||||
if (accessToken.length) {
|
||||
self.accessToken = accessToken;
|
||||
}
|
||||
@@ -60,7 +52,7 @@
|
||||
}
|
||||
|
||||
+ (BOOL) mapboxMetricsEnabledSettingShownInApp {
|
||||
return [MGLAccountManager sharedManager].mapboxMetricsEnabledSettingShownInApp;
|
||||
NSLog(@"mapboxMetricsEnabledSettingShownInApp is no longer necessary; the Mapbox iOS SDK has changed to always provide a telemetry setting in-app.");
|
||||
}
|
||||
|
||||
+ (void) setAccessToken:(NSString *) accessToken {
|
||||
|
||||
@@ -117,6 +117,7 @@ public:
|
||||
CLLocationManagerDelegate,
|
||||
UIActionSheetDelegate,
|
||||
MGLCalloutViewDelegate,
|
||||
UIAlertViewDelegate,
|
||||
MGLMultiPointDelegate,
|
||||
MGLAnnotationImageDelegate>
|
||||
|
||||
@@ -333,6 +334,7 @@ std::chrono::steady_clock::duration MGLDurationInSeconds(float duration)
|
||||
_attributionButton.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
[self addSubview:_attributionButton];
|
||||
_attributionButtonConstraints = [NSMutableArray array];
|
||||
[_attributionButton addObserver:self forKeyPath:@"hidden" options:NSKeyValueObservingOptionNew context:NULL];
|
||||
|
||||
// setup compass
|
||||
//
|
||||
@@ -480,6 +482,7 @@ std::chrono::steady_clock::duration MGLDurationInSeconds(float duration)
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
[[MGLAccountManager sharedManager] removeObserver:self forKeyPath:@"accessToken"];
|
||||
[_attributionButton removeObserver:self forKeyPath:@"hidden"];
|
||||
|
||||
[self validateDisplayLink];
|
||||
|
||||
@@ -1422,13 +1425,9 @@ std::chrono::steady_clock::duration MGLDurationInSeconds(float duration)
|
||||
@"© Mapbox",
|
||||
@"© OpenStreetMap",
|
||||
@"Improve This Map",
|
||||
@"Mapbox Telemetry",
|
||||
nil];
|
||||
|
||||
// iOS 8+: add action that opens app's Settings.app panel, if applicable
|
||||
if (&UIApplicationOpenSettingsURLString != NULL && ! [MGLAccountManager mapboxMetricsEnabledSettingShownInApp])
|
||||
{
|
||||
[self.attributionSheet addButtonWithTitle:@"Adjust Privacy Settings"];
|
||||
}
|
||||
}
|
||||
|
||||
[self.attributionSheet showFromRect:self.attributionButton.frame inView:self animated:YES];
|
||||
@@ -1453,10 +1452,48 @@ std::chrono::steady_clock::duration MGLDurationInSeconds(float duration)
|
||||
[[UIApplication sharedApplication] openURL:
|
||||
[NSURL URLWithString:feedbackURL]];
|
||||
}
|
||||
// skips to 4 because button is conditionally added after cancel (index 3)
|
||||
else if (buttonIndex == actionSheet.firstOtherButtonIndex + 4)
|
||||
else if (buttonIndex == actionSheet.firstOtherButtonIndex + 3)
|
||||
{
|
||||
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
|
||||
NSString *message;
|
||||
NSString *participate;
|
||||
NSString *optOut;
|
||||
|
||||
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"MGLMapboxMetricsEnabled"])
|
||||
{
|
||||
message = @"You are helping to make OpenStreetMap and Mapbox maps better by contributing anonymous usage data.";
|
||||
participate = @"Keep Participating";
|
||||
optOut = @"Stop Participating";
|
||||
}
|
||||
else
|
||||
{
|
||||
message = @"You can help make OpenStreetMap and Mapbox maps better by contributing anonymous usage data.";
|
||||
participate = @"Participate";
|
||||
optOut = @"Don’t Participate";
|
||||
}
|
||||
|
||||
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Make Mapbox Maps Better"
|
||||
message:message
|
||||
delegate:self
|
||||
cancelButtonTitle:participate
|
||||
otherButtonTitles:@"Tell Me More", optOut, nil];
|
||||
[alert show];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
|
||||
{
|
||||
if (buttonIndex == alertView.cancelButtonIndex)
|
||||
{
|
||||
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"MGLMapboxMetricsEnabled"];
|
||||
}
|
||||
else if (buttonIndex == alertView.firstOtherButtonIndex)
|
||||
{
|
||||
[[UIApplication sharedApplication] openURL:
|
||||
[NSURL URLWithString:@"https://mapbox.com/telemetry/"]];
|
||||
}
|
||||
else if (buttonIndex == alertView.firstOtherButtonIndex + 1)
|
||||
{
|
||||
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"MGLMapboxMetricsEnabled"];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1472,6 +1509,15 @@ std::chrono::steady_clock::duration MGLDurationInSeconds(float duration)
|
||||
_mbglFileSource->setAccessToken((std::string)[accessToken UTF8String]);
|
||||
}
|
||||
}
|
||||
else if ([keyPath isEqualToString:@"hidden"] && object == _attributionButton)
|
||||
{
|
||||
NSNumber *hiddenNumber = change[NSKeyValueChangeNewKey];
|
||||
BOOL attributionButtonWasHidden = [hiddenNumber boolValue];
|
||||
if (attributionButtonWasHidden)
|
||||
{
|
||||
[MGLMapboxEvents ensureMetricsOptoutExists];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingZoomEnabled
|
||||
|
||||
@@ -66,7 +66,10 @@ typedef NS_MUTABLE_DICTIONARY_OF(NSString *, id) MGLMutableMapboxEventAttributes
|
||||
+ (void) flush;
|
||||
|
||||
// Main thread only
|
||||
+ (void)validate;
|
||||
+ (void) validate;
|
||||
|
||||
// Main thread only
|
||||
+ (void) ensureMetricsOptoutExists;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -180,36 +180,6 @@ const NSTimeInterval MGLFlushInterval = 60;
|
||||
|
||||
self = [super init];
|
||||
if (self) {
|
||||
if (! [MGLAccountManager mapboxMetricsEnabledSettingShownInApp] &&
|
||||
[[NSUserDefaults standardUserDefaults] integerForKey:@"MGLMapboxAccountType"] == 0) {
|
||||
// Opt Out is not configured in UI, so check for Settings.bundle
|
||||
// Put Settings bundle into memory
|
||||
id defaultEnabledValue;
|
||||
NSString *appSettingsBundle = [[NSBundle mainBundle] pathForResource:@"Settings" ofType:@"bundle"];
|
||||
|
||||
if (appSettingsBundle) {
|
||||
// Dynamic Settings.bundle loading based on:
|
||||
// http://stackoverflow.com/questions/510216/can-you-make-the-settings-in-settings-bundle-default-even-if-you-dont-open-the
|
||||
NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[appSettingsBundle stringByAppendingPathComponent:@"Root.plist"]];
|
||||
NSArray *preferences = settings[@"PreferenceSpecifiers"];
|
||||
for (NSDictionary *prefSpecification in preferences) {
|
||||
if ([prefSpecification[@"Key"] isEqualToString:@"MGLMapboxMetricsEnabled"]) {
|
||||
defaultEnabledValue = prefSpecification[@"DefaultValue"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!defaultEnabledValue)
|
||||
{
|
||||
[NSException raise:@"MGLMapboxMetricsEnabled setting missing" format:
|
||||
@"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,
|
||||
}];
|
||||
}
|
||||
|
||||
_appBundleId = [[NSBundle mainBundle] bundleIdentifier];
|
||||
_appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"];
|
||||
_appVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
|
||||
@@ -770,6 +740,42 @@ const NSTimeInterval MGLFlushInterval = 60;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Main thread only
|
||||
//
|
||||
+ (void) ensureMetricsOptoutExists {
|
||||
MGLAssertIsMainThread();
|
||||
|
||||
NSNumber *shownInAppNumber = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"MGLMapboxMetricsEnabledSettingShownInApp"];
|
||||
BOOL metricsEnabledSettingShownInAppFlag = [shownInAppNumber boolValue];
|
||||
|
||||
if ( ! metricsEnabledSettingShownInAppFlag &&
|
||||
[[NSUserDefaults standardUserDefaults] integerForKey:@"MGLMapboxAccountType"] == 0) {
|
||||
// Opt-out is not configured in UI, so check for Settings.bundle
|
||||
id defaultEnabledValue;
|
||||
NSString *appSettingsBundle = [[NSBundle mainBundle] pathForResource:@"Settings" ofType:@"bundle"];
|
||||
|
||||
if (appSettingsBundle) {
|
||||
// Dynamic Settings.bundle loading based on http://stackoverflow.com/a/510329/2094275
|
||||
NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[appSettingsBundle stringByAppendingPathComponent:@"Root.plist"]];
|
||||
NSArray *preferences = settings[@"PreferenceSpecifiers"];
|
||||
for (NSDictionary *prefSpecification in preferences) {
|
||||
if ([prefSpecification[@"Key"] isEqualToString:@"MGLMapboxMetricsEnabled"]) {
|
||||
defaultEnabledValue = prefSpecification[@"DefaultValue"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! defaultEnabledValue) {
|
||||
[NSException raise:@"Telemetry opt-out missing" format:
|
||||
@"End users must be able to opt out of Mapbox Telemetry in your app, either inside Settings (via Settings.bundle) or inside this app. "
|
||||
@"By default, this opt-out control is included as a menu item in the attribution action sheet. "
|
||||
@"If you reimplement the opt-out control inside this app, disable this assertion by setting MGLMapboxMetricsEnabledSettingShownInApp to YES in Info.plist."
|
||||
@"\n\nSee https://www.mapbox.com/ios-sdk/#telemetry_opt_out for more information."
|
||||
@"\n\nAdditionally, by hiding this attribution control you agree to display the required attribution elsewhere in this app."];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark CLLocationManagerDelegate
|
||||
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
|
||||
// Iterate through locations to pass all data
|
||||
|
||||
Reference in New Issue
Block a user