From d74a09cd42b05a77f2e390ec4317c91915866c36 Mon Sep 17 00:00:00 2001 From: Ben Baron Date: Tue, 30 Apr 2024 16:09:34 -0500 Subject: [PATCH] feat: Update to Braze 9.x.x SDK, improve privacy manifest support --- Package.swift | 10 +-- Sources/mParticle-Appboy/MPKitAppboy.m | 64 +++++++++++++++++-- .../PrivacyInfo.xcprivacy | 8 +-- .../mParticle-Appboy/include/MPKitAppboy.h | 10 ++- mParticle-Appboy.podspec | 16 +++-- mParticle-Appboy.xcodeproj/project.pbxproj | 4 +- 6 files changed, 85 insertions(+), 27 deletions(-) rename Sources/{ => mParticle-Appboy}/PrivacyInfo.xcprivacy (85%) diff --git a/Package.swift b/Package.swift index a99feac..9ab1475 100644 --- a/Package.swift +++ b/Package.swift @@ -18,10 +18,10 @@ let package = Package( dependencies: [ .package(name: "mParticle-Apple-SDK", url: "https://github.com/mParticle/mparticle-apple-sdk", - .upToNextMajor(from: "8.0.0")), + .upToNextMajor(from: "8.19.0")), .package(name: "braze-swift-sdk", url: "https://github.com/braze-inc/braze-swift-sdk", - .upToNextMajor(from: "8.0.0")), + .upToNextMajor(from: "9.0.0")), ], targets: [ .target( @@ -31,7 +31,8 @@ let package = Package( .product(name: "BrazeUI", package: "braze-swift-sdk", condition: .when(platforms: [.iOS])), .product(name: "BrazeKit", package: "braze-swift-sdk"), .product(name: "BrazeKitCompat", package: "braze-swift-sdk"), - ] + ], + resources: [.process("PrivacyInfo.xcprivacy")] ), .target( name: "mParticle-Appboy-NoLocation", @@ -41,7 +42,8 @@ let package = Package( .product(name: "BrazeKit", package: "braze-swift-sdk"), .product(name: "BrazeKitCompat", package: "braze-swift-sdk"), ], - path: "SPM/mParticle-Appboy-NoLocation" + path: "SPM/mParticle-Appboy-NoLocation", + resources: [.process("PrivacyInfo.xcprivacy")] ) ] ) diff --git a/Sources/mParticle-Appboy/MPKitAppboy.m b/Sources/mParticle-Appboy/MPKitAppboy.m index 36ca105..9deec34 100644 --- a/Sources/mParticle-Appboy/MPKitAppboy.m +++ b/Sources/mParticle-Appboy/MPKitAppboy.m @@ -53,6 +53,8 @@ #endif __weak static id urlDelegate = nil; static Braze *brazeInstance = nil; +static id brazeLocationProvider = nil; +static NSSet *brazeTrackingPropertyAllowList; @interface MPKitAppboy() { Braze *appboyInstance; @@ -114,6 +116,19 @@ + (Braze *)brazeInstance { return brazeInstance; } ++ (void)setBrazeLocationProvider:(nonnull id)instance { + brazeLocationProvider = instance; +} + ++ (void)setBrazeTrackingPropertyAllowList:(nonnull NSSet *)allowList { + for (id property in allowList) { + if (![property isKindOfClass:[BRZTrackingProperty class]]) { + return; + } + } + brazeTrackingPropertyAllowList = allowList; +} + #pragma mark Private methods - (NSString *)stringRepresentation:(id)value { NSString *stringRepresentation = nil; @@ -258,6 +273,25 @@ - (NSString *)advertisingIdentifierString { return _advertiserId; } +- (BOOL)isAppTrackingEnabled { + BOOL appTrackingEnabled = NO; + Class ATTrackingManager = NSClassFromString(@"ATTrackingManager"); + + if (ATTrackingManager) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wundeclared-selector" +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" + SEL selector = NSSelectorFromString(@"trackingAuthorizationStatus"); + NSUInteger trackingAuthorizationStatus = (NSUInteger)[ATTrackingManager performSelector:selector]; + appTrackingEnabled = (trackingAuthorizationStatus == 3); // ATTrackingManagerAuthorizationStatusAuthorized +#pragma clang diagnostic pop +#pragma clang diagnostic pop + } + + return appTrackingEnabled; +} + #pragma mark MPKitInstanceProtocol methods - (MPKitExecStatus *)didFinishLaunchingWithConfiguration:(NSDictionary *)configuration { @@ -291,8 +325,6 @@ - (MPKitExecStatus *)didFinishLaunchingWithConfiguration:(NSDictionary *)configu _started = NO; } - - execStatus = [[MPKitExecStatus alloc] initWithSDKCode:[[self class] kitCode] returnCode:MPKitReturnCodeSuccess]; return execStatus; } @@ -305,14 +337,24 @@ - (void)start { if (!self->appboyInstance) { NSDictionary *optionsDict = [self optionsDictionary]; BRZConfiguration *configuration = [[BRZConfiguration alloc] initWithApiKey:self.configuration[eabAPIKey] endpoint:optionsDict[ABKEndpointKey]]; + + [configuration.api addSDKMetadata:@[BRZSDKMetadata.mparticle]]; + configuration.api.sdkFlavor = ((NSNumber *)optionsDict[ABKSDKFlavorKey]).intValue; configuration.api.requestPolicy = ((NSNumber *)optionsDict[ABKRequestProcessingPolicyOptionKey]).intValue; - configuration.api.flushInterval = ((NSNumber *)optionsDict[ABKFlushIntervalOptionKey]).doubleValue; + NSNumber *flushIntervalOption = (NSNumber *)optionsDict[ABKFlushIntervalOptionKey] ?: @10; // If not set, use the default 10 seconds specified in Braze SDK header + configuration.api.flushInterval = flushIntervalOption.doubleValue < 1.0 ? 1.0 : flushIntervalOption.doubleValue; // Ensure value is above the minimum of 1.0 per run time warning from Braze SDK + configuration.api.trackingPropertyAllowList = brazeTrackingPropertyAllowList; + configuration.sessionTimeout = ((NSNumber *)optionsDict[ABKSessionTimeoutKey]).doubleValue; + configuration.triggerMinimumTimeInterval = ((NSNumber *)optionsDict[ABKMinimumTriggerTimeIntervalKey]).doubleValue; - configuration.location.automaticLocationCollection = optionsDict[ABKEnableAutomaticLocationCollectionKey]; - [configuration.api addSDKMetadata:@[BRZSDKMetadata.mparticle]]; - configuration.api.sdkFlavor = ((NSNumber *)optionsDict[ABKSDKFlavorKey]).intValue; + NSNumber *automaticLocationTrackingOption = (NSNumber *)optionsDict[ABKEnableAutomaticLocationCollectionKey]; + if (automaticLocationTrackingOption != nil && automaticLocationTrackingOption.boolValue && brazeLocationProvider) { + configuration.location.automaticLocationCollection = YES; + configuration.location.brazeLocationProvider = brazeLocationProvider; + } + self->appboyInstance = [[Braze alloc] initWithConfiguration:configuration]; } @@ -322,8 +364,8 @@ - (void)start { if (self->collectIDFA) { [self->appboyInstance setIdentifierForAdvertiser:[self advertisingIdentifierString]]; - [self->appboyInstance setAdTrackingEnabled:[self isAdvertisingTrackingEnabled]]; } + [self->appboyInstance setAdTrackingEnabled:[self isAppTrackingEnabled]]; #if TARGET_OS_IOS BrazeInAppMessageUI *inAppMessageUI = [[BrazeInAppMessageUI alloc] init]; @@ -994,6 +1036,14 @@ - (nonnull MPKitExecStatus *)userNotificationCenter:(nonnull UNUserNotificationC } #endif +- (MPKitExecStatus *)setATTStatus:(MPATTAuthorizationStatus)status withATTStatusTimestampMillis:(NSNumber *)attStatusTimestampMillis { + BOOL isEnabled = status == MPATTAuthorizationStatusAuthorized; + [appboyInstance setAdTrackingEnabled:isEnabled]; + return [[MPKitExecStatus alloc] initWithSDKCode:@(MPKitInstanceAppboy) returnCode:MPKitReturnCodeSuccess]; +} + +#pragma mark Configuration Dictionary + - (NSMutableDictionary *)simplifiedDictionary:(NSDictionary *)originalDictionary { __block NSMutableDictionary *transformedDictionary = [[NSMutableDictionary alloc] init]; diff --git a/Sources/PrivacyInfo.xcprivacy b/Sources/mParticle-Appboy/PrivacyInfo.xcprivacy similarity index 85% rename from Sources/PrivacyInfo.xcprivacy rename to Sources/mParticle-Appboy/PrivacyInfo.xcprivacy index 8ceb89c..e08a130 100644 --- a/Sources/PrivacyInfo.xcprivacy +++ b/Sources/mParticle-Appboy/PrivacyInfo.xcprivacy @@ -7,12 +7,8 @@ NSPrivacyTrackingDomains NSPrivacyCollectedDataTypes - - - + NSPrivacyAccessedAPITypes - - - + diff --git a/Sources/mParticle-Appboy/include/MPKitAppboy.h b/Sources/mParticle-Appboy/include/MPKitAppboy.h index f2ec884..52455ad 100644 --- a/Sources/mParticle-Appboy/include/MPKitAppboy.h +++ b/Sources/mParticle-Appboy/include/MPKitAppboy.h @@ -10,6 +10,13 @@ #import "mParticle_Apple_SDK-Swift.h" #endif +#if defined(__has_include) && __has_include() + #import +#else + #import BrazeKit-Swift.h +#endif + + @interface MPKitAppboy : NSObject @property (nonatomic, strong, nonnull) NSDictionary *configuration; @@ -22,5 +29,6 @@ #endif + (void)setURLDelegate:(nonnull id)delegate; + (void)setBrazeInstance:(nonnull id)instance; - ++ (void)setBrazeLocationProvider:(nonnull id)instance; ++ (void)setBrazeTrackingPropertyAllowList:(nonnull NSSet *)allowList; @end diff --git a/mParticle-Appboy.podspec b/mParticle-Appboy.podspec index 9d8ce1b..35f0815 100755 --- a/mParticle-Appboy.podspec +++ b/mParticle-Appboy.podspec @@ -17,16 +17,18 @@ Pod::Spec.new do |s| s.ios.deployment_target = "12.0" s.ios.source_files = 'Sources/**/*.{h,m,mm}' - s.ios.dependency 'mParticle-Apple-SDK', '~> 8.0' - s.ios.dependency 'BrazeKit', '~> 8.0' - s.ios.dependency 'BrazeKitCompat', '~> 8.0' - s.ios.dependency 'BrazeUI', '~> 8.0' + s.ios.resource_bundles = { 'mParticle-Appboy-Privacy' => ['Sources/mParticle-Appboy/PrivacyInfo.xcprivacy'] } + s.ios.dependency 'mParticle-Apple-SDK', '~> 8.19' + s.ios.dependency 'BrazeKit', '~> 9.0' + s.ios.dependency 'BrazeKitCompat', '~> 9.0' + s.ios.dependency 'BrazeUI', '~> 9.0' s.tvos.deployment_target = "12.0" s.tvos.source_files = 'Sources/**/*.{h,m,mm}' - s.tvos.dependency 'mParticle-Apple-SDK', '~> 8.0' - s.tvos.dependency 'BrazeKit', '~> 8.0' - s.tvos.dependency 'BrazeKitCompat', '~> 8.0' + s.tvos.resource_bundles = { 'mParticle-Appboy-Privacy' => ['Sources/mParticle-Appboy/PrivacyInfo.xcprivacy'] } + s.tvos.dependency 'mParticle-Apple-SDK', '~> 8.19' + s.tvos.dependency 'BrazeKit', '~> 9.0' + s.tvos.dependency 'BrazeKitCompat', '~> 9.0' end diff --git a/mParticle-Appboy.xcodeproj/project.pbxproj b/mParticle-Appboy.xcodeproj/project.pbxproj index f629621..ad222d8 100644 --- a/mParticle-Appboy.xcodeproj/project.pbxproj +++ b/mParticle-Appboy.xcodeproj/project.pbxproj @@ -141,7 +141,6 @@ children = ( DB76F1C925D2E71D00CAB3EB /* mParticle-Appboy */, DB76F1CE25D2E71D00CAB3EB /* Info.plist */, - D344232F2B960F44006CD046 /* PrivacyInfo.xcprivacy */, ); path = Sources; sourceTree = ""; @@ -151,6 +150,7 @@ children = ( DB76F1CA25D2E71D00CAB3EB /* include */, DB76F1CD25D2E71D00CAB3EB /* MPKitAppboy.m */, + D344232F2B960F44006CD046 /* PrivacyInfo.xcprivacy */, ); path = "mParticle-Appboy"; sourceTree = ""; @@ -921,7 +921,7 @@ repositoryURL = "https://github.com/braze-inc/braze-swift-sdk"; requirement = { kind = upToNextMajorVersion; - minimumVersion = 6.0.0; + minimumVersion = 9.0.0; }; }; /* End XCRemoteSwiftPackageReference section */