diff --git a/CHANGELOG.md b/CHANGELOG.md index 767f6ea..f9a23b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,60 @@ +# [8.15.0](https://github.com/mparticle-integrations/mparticle-apple-integration-appboy/releases/tag/v8.15.0) + + +### Features + +* Remove BrazeKitCompat dependency — complete migration to pure BrazeKit/BrazeUI (Braze Swift SDK 14.0+) +* Add subscription group mapping support +* Add email/push subscription state handling via user attributes + +### Bug Fixes + +* Remove legacy `ABK*` constants in favor of Braze Swift SDK equivalents +* Restore `sdkFlavor` reporting to Braze via `BRZSDKFlavorMparticle` + +# [8.14.0](https://github.com/mparticle-integrations/mparticle-apple-integration-appboy/compare/v8.13.2...v8.14.0) (2025-05-27) + + +### Features + +* Update Braze to v14.0.0 + +# [8.13.2](https://github.com/mparticle-integrations/mparticle-apple-integration-appboy/compare/v8.13.1...v8.13.2) (2025-06-12) + + +### Bug Fixes + +* Forward commerce event custom attributes for purchase ([#107](https://github.com/mparticle-integrations/mparticle-apple-integration-appboy/issues/107)) + +# [8.13.1](https://github.com/mparticle-integrations/mparticle-apple-integration-appboy/compare/v8.13.0...v8.13.1) (2025-05-27) + + +### Features + +* Update Braze to v12.0.0 ([#106](https://github.com/mparticle-integrations/mparticle-apple-integration-appboy/issues/106)) + +# [8.13.0](https://github.com/mparticle-integrations/mparticle-apple-integration-appboy/compare/v8.12.1...v8.13.0) (2025-04-22) + + +### Features + +* Add support to forward SubscriptionGroupIds ([#105](https://github.com/mparticle-integrations/mparticle-apple-integration-appboy/issues/105)) + +# [8.12.1](https://github.com/mparticle-integrations/mparticle-apple-integration-appboy/compare/v8.12.0...v8.12.1) (2025-04-03) + + +### Bug Fixes + +* Update Braze to 11.9 to include iCloud restore fix ([#104](https://github.com/mparticle-integrations/mparticle-apple-integration-appboy/issues/104)) +* Users attributes email and push subscribe mapping ([#103](https://github.com/mparticle-integrations/mparticle-apple-integration-appboy/issues/103)) + +# [8.12.0](https://github.com/mparticle-integrations/mparticle-apple-integration-appboy/compare/v8.11.0...v8.12.0) (2024-12-11) + + +### Features + +* Use replaceSkuWithProductName option ([#101](https://github.com/mparticle-integrations/mparticle-apple-integration-appboy/issues/101)) + # [8.11.0](https://github.com/mparticle-integrations/mparticle-apple-integration-appboy/compare/v8.10.2...v8.11.0) (2024-11-19) diff --git a/Package.swift b/Package.swift index 83c1692..a237b56 100644 --- a/Package.swift +++ b/Package.swift @@ -30,7 +30,6 @@ let package = Package( .product(name: "mParticle-Apple-SDK", package: "mParticle-Apple-SDK"), .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")] ), @@ -40,7 +39,6 @@ let package = Package( .product(name: "mParticle-Apple-SDK-NoLocation", package: "mParticle-Apple-SDK"), .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"), ], path: "SPM/mParticle-Appboy-NoLocation", resources: [.process("PrivacyInfo.xcprivacy")] diff --git a/Sources/mParticle-Appboy/MPKitAppboy.m b/Sources/mParticle-Appboy/MPKitAppboy.m index 79ab1af..e40d50a 100644 --- a/Sources/mParticle-Appboy/MPKitAppboy.m +++ b/Sources/mParticle-Appboy/MPKitAppboy.m @@ -2,11 +2,9 @@ #if TARGET_OS_IOS @import BrazeKit; - @import BrazeKitCompat; @import BrazeUI; #else @import BrazeKit; - @import BrazeKitCompat; #endif static NSString *const eabAPIKey = @"apiKey"; @@ -60,6 +58,14 @@ static NSString *const BGoogleAdUserDataKey = @"$google_ad_user_data"; static NSString *const BGoogleAdPersonalizationKey = @"$google_ad_personalization"; +// Braze configuration option keys used internally by the options dictionary +static NSString *const kMPBrazeConfigEndpoint = @"endpoint"; +static NSString *const kMPBrazeConfigRequestPolicy = @"requestPolicy"; +static NSString *const kMPBrazeConfigFlushInterval = @"flushInterval"; +static NSString *const kMPBrazeConfigSessionTimeout = @"sessionTimeout"; +static NSString *const kMPBrazeConfigTriggerMinimumTimeInterval = @"triggerMinimumTimeInterval"; +static NSString *const kMPBrazeConfigAutomaticLocationCollection = @"automaticLocationCollection"; + #if TARGET_OS_IOS static id inAppMessageControllerDelegate = nil; static BOOL shouldDisableNotificationHandling = NO; @@ -371,20 +377,20 @@ - (id const)providerKitInstance { - (void)start { if (!self->appboyInstance) { NSDictionary *optionsDict = [self optionsDictionary]; - BRZConfiguration *configuration = [[BRZConfiguration alloc] initWithApiKey:self.configuration[eabAPIKey] endpoint:optionsDict[ABKEndpointKey]]; + BRZConfiguration *configuration = [[BRZConfiguration alloc] initWithApiKey:self.configuration[eabAPIKey] endpoint:optionsDict[kMPBrazeConfigEndpoint]]; [configuration.api addSDKMetadata:@[BRZSDKMetadata.mparticle]]; - configuration.api.sdkFlavor = ((NSNumber *)optionsDict[ABKSDKFlavorKey]).intValue; - configuration.api.requestPolicy = ((NSNumber *)optionsDict[ABKRequestProcessingPolicyOptionKey]).intValue; - NSNumber *flushIntervalOption = (NSNumber *)optionsDict[ABKFlushIntervalOptionKey] ?: @10; // If not set, use the default 10 seconds specified in Braze SDK header + configuration.api.sdkFlavor = BRZSDKFlavorMparticle; + configuration.api.requestPolicy = ((NSNumber *)optionsDict[kMPBrazeConfigRequestPolicy]).intValue; + NSNumber *flushIntervalOption = (NSNumber *)optionsDict[kMPBrazeConfigFlushInterval] ?: @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.sessionTimeout = ((NSNumber *)optionsDict[kMPBrazeConfigSessionTimeout]).doubleValue; - configuration.triggerMinimumTimeInterval = ((NSNumber *)optionsDict[ABKMinimumTriggerTimeIntervalKey]).doubleValue; + configuration.triggerMinimumTimeInterval = ((NSNumber *)optionsDict[kMPBrazeConfigTriggerMinimumTimeInterval]).doubleValue; - NSNumber *automaticLocationTrackingOption = (NSNumber *)optionsDict[ABKEnableAutomaticLocationCollectionKey]; + NSNumber *automaticLocationTrackingOption = (NSNumber *)optionsDict[kMPBrazeConfigAutomaticLocationCollection]; if (automaticLocationTrackingOption != nil && automaticLocationTrackingOption.boolValue && brazeLocationProvider) { configuration.location.automaticLocationCollection = YES; configuration.location.brazeLocationProvider = brazeLocationProvider; @@ -444,8 +450,9 @@ - (void)stop { } - (NSMutableDictionary *)optionsDictionary { + // This maps the mParticle keys (prefixed with ABK) to the Braze Swift SDK configuration keys (prefixed with kMPBrazeConfig) NSArray *serverKeys = @[@"ABKRequestProcessingPolicyOptionKey", @"ABKFlushIntervalOptionKey", @"ABKSessionTimeoutKey", @"ABKMinimumTriggerTimeIntervalKey"]; - NSArray *appboyKeys = @[ABKRequestProcessingPolicyOptionKey, ABKFlushIntervalOptionKey, ABKSessionTimeoutKey, ABKMinimumTriggerTimeIntervalKey]; + NSArray *configKeys = @[kMPBrazeConfigRequestPolicy, kMPBrazeConfigFlushInterval, kMPBrazeConfigSessionTimeout, kMPBrazeConfigTriggerMinimumTimeInterval]; NSMutableDictionary *optionsDictionary = [[NSMutableDictionary alloc] initWithCapacity:serverKeys.count]; NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init]; numberFormatter.numberStyle = NSNumberFormatterNoStyle; @@ -454,7 +461,6 @@ - (void)stop { NSString *optionValue = self.configuration[serverKey]; if (optionValue != nil && (NSNull *)optionValue != [NSNull null]) { - NSString *appboyKey = appboyKeys[idx]; NSNumber *numberValue = nil; @try { numberValue = [numberFormatter numberFromString:optionValue]; @@ -462,34 +468,24 @@ - (void)stop { numberValue = nil; } if (numberValue != nil) { - optionsDictionary[appboyKey] = numberValue; + optionsDictionary[configKeys[idx]] = numberValue; } } }]; if (self.host.length) { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wincompatible-pointer-types" - optionsDictionary[ABKEndpointKey] = self.host; -#pragma clang diagnostic pop + optionsDictionary[kMPBrazeConfigEndpoint] = self.host; } if (optionsDictionary.count == 0) { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wincompatible-pointer-types" optionsDictionary = [[NSMutableDictionary alloc] initWithCapacity:serverKeys.count]; } - optionsDictionary[ABKSDKFlavorKey] = @(MPARTICLE); -#pragma clang diagnostic pop - + #if TARGET_OS_IOS - optionsDictionary[ABKEnableAutomaticLocationCollectionKey] = @(YES); + optionsDictionary[kMPBrazeConfigAutomaticLocationCollection] = @(YES); if (self.configuration[@"ABKDisableAutomaticLocationCollectionKey"]) { if ([self.configuration[@"ABKDisableAutomaticLocationCollectionKey"] caseInsensitiveCompare:@"true"] == NSOrderedSame) { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wincompatible-pointer-types" - optionsDictionary[ABKEnableAutomaticLocationCollectionKey] = @(NO); -#pragma clang diagnostic pop + optionsDictionary[kMPBrazeConfigAutomaticLocationCollection] = @(NO); } } #endif diff --git a/mParticle-Appboy.podspec b/mParticle-Appboy.podspec index eff024c..9354bdf 100755 --- a/mParticle-Appboy.podspec +++ b/mParticle-Appboy.podspec @@ -20,7 +20,6 @@ Pod::Spec.new do |s| s.ios.resource_bundles = { 'mParticle-Appboy-Privacy' => ['Sources/mParticle-Appboy/PrivacyInfo.xcprivacy'] } s.ios.dependency 'mParticle-Apple-SDK', '~> 8.19' s.ios.dependency 'BrazeKit', '~> 14.0' - s.ios.dependency 'BrazeKitCompat', '~> 14.0' s.ios.dependency 'BrazeUI', '~> 14.0' s.tvos.deployment_target = "12.0" @@ -28,7 +27,6 @@ Pod::Spec.new do |s| s.tvos.resource_bundles = { 'mParticle-Appboy-Privacy' => ['Sources/mParticle-Appboy/PrivacyInfo.xcprivacy'] } s.tvos.dependency 'mParticle-Apple-SDK', '~> 8.19' s.tvos.dependency 'BrazeKit', '~> 14.0' - s.tvos.dependency 'BrazeKitCompat', '~> 14.0' end diff --git a/mParticle-Appboy.xcodeproj/project.pbxproj b/mParticle-Appboy.xcodeproj/project.pbxproj index ad222d8..6258665 100644 --- a/mParticle-Appboy.xcodeproj/project.pbxproj +++ b/mParticle-Appboy.xcodeproj/project.pbxproj @@ -17,9 +17,7 @@ 539B2E952A13D62200C8339D /* OCMock in Frameworks */ = {isa = PBXBuildFile; productRef = 539B2E942A13D62200C8339D /* OCMock */; }; 539B2E982A13D66300C8339D /* mParticle-Apple-SDK in Frameworks */ = {isa = PBXBuildFile; productRef = 539B2E972A13D66300C8339D /* mParticle-Apple-SDK */; }; 539B2E9A2A13D66A00C8339D /* mParticle-Apple-SDK in Frameworks */ = {isa = PBXBuildFile; productRef = 539B2E992A13D66A00C8339D /* mParticle-Apple-SDK */; }; - 539B2E9D2A13D69F00C8339D /* BrazeKitCompat in Frameworks */ = {isa = PBXBuildFile; productRef = 539B2E9C2A13D69F00C8339D /* BrazeKitCompat */; }; 539B2E9F2A13D69F00C8339D /* BrazeUI in Frameworks */ = {isa = PBXBuildFile; productRef = 539B2E9E2A13D69F00C8339D /* BrazeUI */; }; - 539B2EA12A13D6AB00C8339D /* BrazeKitCompat in Frameworks */ = {isa = PBXBuildFile; productRef = 539B2EA02A13D6AB00C8339D /* BrazeKitCompat */; }; D31A98A92153F73400358293 /* mParticle_AppboyTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D31A98A82153F73400358293 /* mParticle_AppboyTests.m */; }; D31A98AB2153F73400358293 /* mParticle_Appboy.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DB94016C1CB703F2007ABB18 /* mParticle_Appboy.framework */; }; D34423302B960F44006CD046 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = D344232F2B960F44006CD046 /* PrivacyInfo.xcprivacy */; }; @@ -96,7 +94,6 @@ files = ( 5387EC022A18051200219E89 /* BrazeKit in Frameworks */, 539B2E9F2A13D69F00C8339D /* BrazeUI in Frameworks */, - 539B2E9D2A13D69F00C8339D /* BrazeKitCompat in Frameworks */, 539B2E982A13D66300C8339D /* mParticle-Apple-SDK in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -105,7 +102,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 539B2EA12A13D6AB00C8339D /* BrazeKitCompat in Frameworks */, 539B2E9A2A13D66A00C8339D /* mParticle-Apple-SDK in Frameworks */, 5387EC002A18050500219E89 /* BrazeKit in Frameworks */, ); @@ -285,7 +281,6 @@ name = "mParticle-Appboy"; packageProductDependencies = ( 539B2E972A13D66300C8339D /* mParticle-Apple-SDK */, - 539B2E9C2A13D69F00C8339D /* BrazeKitCompat */, 539B2E9E2A13D69F00C8339D /* BrazeUI */, 5387EC012A18051200219E89 /* BrazeKit */, ); @@ -309,7 +304,6 @@ name = "mParticle-Appboy-tvOS"; packageProductDependencies = ( 539B2E992A13D66A00C8339D /* mParticle-Apple-SDK */, - 539B2EA02A13D6AB00C8339D /* BrazeKitCompat */, 5387EBFF2A18050500219E89 /* BrazeKit */, ); productName = "mParticle-Appboy-tvOS"; @@ -450,10 +444,6 @@ target = 531861FB2A13E147006FFE90 /* AppboyTestHost */; targetProxy = 531862102A13E17D006FFE90 /* PBXContainerItemProxy */; }; - 539B2EA32A13D94E00C8339D /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - productRef = 539B2EA22A13D94E00C8339D /* BrazeKitCompat */; - }; 539B2EA52A13D95200C8339D /* PBXTargetDependency */ = { isa = PBXTargetDependency; productRef = 539B2EA42A13D95200C8339D /* BrazeUI */; @@ -921,7 +911,7 @@ repositoryURL = "https://github.com/braze-inc/braze-swift-sdk"; requirement = { kind = upToNextMajorVersion; - minimumVersion = 9.0.0; + minimumVersion = 14.0.0; }; }; /* End XCRemoteSwiftPackageReference section */ @@ -952,26 +942,11 @@ package = 539B2E962A13D66300C8339D /* XCRemoteSwiftPackageReference "mparticle-apple-sdk" */; productName = "mParticle-Apple-SDK"; }; - 539B2E9C2A13D69F00C8339D /* BrazeKitCompat */ = { - isa = XCSwiftPackageProductDependency; - package = 539B2E9B2A13D69F00C8339D /* XCRemoteSwiftPackageReference "braze-swift-sdk" */; - productName = BrazeKitCompat; - }; 539B2E9E2A13D69F00C8339D /* BrazeUI */ = { isa = XCSwiftPackageProductDependency; package = 539B2E9B2A13D69F00C8339D /* XCRemoteSwiftPackageReference "braze-swift-sdk" */; productName = BrazeUI; }; - 539B2EA02A13D6AB00C8339D /* BrazeKitCompat */ = { - isa = XCSwiftPackageProductDependency; - package = 539B2E9B2A13D69F00C8339D /* XCRemoteSwiftPackageReference "braze-swift-sdk" */; - productName = BrazeKitCompat; - }; - 539B2EA22A13D94E00C8339D /* BrazeKitCompat */ = { - isa = XCSwiftPackageProductDependency; - package = 539B2E9B2A13D69F00C8339D /* XCRemoteSwiftPackageReference "braze-swift-sdk" */; - productName = BrazeKitCompat; - }; 539B2EA42A13D95200C8339D /* BrazeUI */ = { isa = XCSwiftPackageProductDependency; package = 539B2E9B2A13D69F00C8339D /* XCRemoteSwiftPackageReference "braze-swift-sdk" */; diff --git a/mParticle_AppboyTests/mParticle_AppboyTests.m b/mParticle_AppboyTests/mParticle_AppboyTests.m index 0e1cd34..277f015 100644 --- a/mParticle_AppboyTests/mParticle_AppboyTests.m +++ b/mParticle_AppboyTests/mParticle_AppboyTests.m @@ -3,12 +3,17 @@ @import XCTest; @import OCMock; #if TARGET_OS_IOS - @import BrazeKitCompat; @import BrazeUI; -#else - @import BrazeKitCompat; #endif +// Keys matching MPKitAppboy optionsDictionary +static NSString *const kMPBrazeConfigEndpoint = @"endpoint"; +static NSString *const kMPBrazeConfigRequestPolicy = @"requestPolicy"; +static NSString *const kMPBrazeConfigFlushInterval = @"flushInterval"; +static NSString *const kMPBrazeConfigSessionTimeout = @"sessionTimeout"; +static NSString *const kMPBrazeConfigTriggerMinimumTimeInterval = @"triggerMinimumTimeInterval"; +static NSString *const kMPBrazeConfigAutomaticLocationCollection = @"automaticLocationCollection"; + @interface MPKitAppboy () - (Braze *)appboyInstance; @@ -50,8 +55,7 @@ - (void)testStartwithSimpleConfig { [appBoy didFinishLaunchingWithConfiguration:kitConfiguration]; - NSDictionary *testOptionsDictionary = @{ABKEnableAutomaticLocationCollectionKey:@(YES), - ABKSDKFlavorKey:@7 + NSDictionary *testOptionsDictionary = @{kMPBrazeConfigAutomaticLocationCollection: @(YES) }; NSDictionary *optionsDictionary = [appBoy optionsDictionary]; @@ -73,12 +77,11 @@ - (void)testStartwithAdvancedConfig { [appBoy didFinishLaunchingWithConfiguration:kitConfiguration]; - NSDictionary *testOptionsDictionary = @{ABKEnableAutomaticLocationCollectionKey:@(YES), - ABKSDKFlavorKey:@7, - @"ABKRquestProcessingPolicy": @(1), - @"ABKFlushInterval":@(2), - @"ABKSessionTimeout":@(3), - @"ABKMinimumTriggerTimeInterval":@(4) + NSDictionary *testOptionsDictionary = @{kMPBrazeConfigAutomaticLocationCollection: @(YES), + kMPBrazeConfigRequestPolicy: @(1), + kMPBrazeConfigFlushInterval: @(2), + kMPBrazeConfigSessionTimeout: @(3), + kMPBrazeConfigTriggerMinimumTimeInterval: @(4) }; NSDictionary *optionsDictionary = [appBoy optionsDictionary];