[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:
Jason Wray
2016-01-06 02:28:34 -05:00
parent d7fdcc73bf
commit 45a0f48ea0
11 changed files with 112 additions and 61 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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>

View File

@@ -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.";

View File

@@ -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>

View File

@@ -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 {

View File

@@ -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

View File

@@ -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

View File

@@ -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