diff --git a/UnitTests/ObjCTests/MPKitConfigurationTests.mm b/UnitTests/ObjCTests/MPKitConfigurationTests.mm index bd1a69e67..410e07351 100644 --- a/UnitTests/ObjCTests/MPKitConfigurationTests.mm +++ b/UnitTests/ObjCTests/MPKitConfigurationTests.mm @@ -81,7 +81,7 @@ - (void)tearDown { - (void)testInstance { XCTAssertNotNil(kitConfiguration); - XCTAssertEqualObjects(kitConfiguration.configurationHash, @(969680750)); + XCTAssertEqualObjects(kitConfiguration.configurationHash, @(762651950)); XCTAssertEqualObjects(kitConfiguration.integrationId, @37); XCTAssertEqualObjects(kitConfiguration.attributeValueFilteringHashedAttribute, @"12345"); XCTAssertEqualObjects(kitConfiguration.attributeValueFilteringHashedValue, @"54321"); @@ -183,7 +183,7 @@ - (void)testInvalidConfiguration { kitConfig = [[MPKitConfiguration alloc] initWithDictionary:configuration]; XCTAssertNotNil(kitConfig); - XCTAssertEqualObjects(kitConfig.configurationHash, @(-1872513399)); + XCTAssertEqualObjects(kitConfig.configurationHash, @(1495473349)); XCTAssertEqualObjects(kitConfig.integrationId, @80); XCTAssertNil(kitConfig.filters); diff --git a/UnitTests/SwiftTests/MParticle/MParticleSceneDelegateTests.swift b/UnitTests/SwiftTests/MParticle/MParticleSceneDelegateTests.swift deleted file mode 100644 index 4a36185f7..000000000 --- a/UnitTests/SwiftTests/MParticle/MParticleSceneDelegateTests.swift +++ /dev/null @@ -1,76 +0,0 @@ - -#if MPARTICLE_LOCATION_DISABLE -import mParticle_Apple_SDK_NoLocation -#else -import mParticle_Apple_SDK -#endif -import XCTest - -final class MParticleSceneDelegateTests: MParticleTestBase { - - // MARK: - Properties - - var testURL: URL! - var testUserActivity: NSUserActivity! - - override func setUp() { - super.setUp() - testURL = URL(string: "myapp://test/path?param=value")! - testUserActivity = NSUserActivity(activityType: "com.test.activity") - testUserActivity.title = "Test Activity" - testUserActivity.userInfo = ["key": "value"] - - // The implementation calls [MParticle sharedInstance], so we need to set the mock on the shared instance - MParticle.sharedInstance().appNotificationHandler = appNotificationHandler - - // Reset mock state for each test - appNotificationHandler.continueUserActivityCalled = false - appNotificationHandler.continueUserActivityUserActivityParam = nil - appNotificationHandler.continueUserActivityRestorationHandlerParam = nil - appNotificationHandler.openURLWithOptionsCalled = false - appNotificationHandler.openURLWithOptionsURLParam = nil - appNotificationHandler.openURLWithOptionsOptionsParam = nil - } - - // MARK: - handleUserActivity Tests - - func test_handleUserActivity_invokesAppNotificationHandler() { - // Act - mparticle.handleUserActivity(testUserActivity) - - // Assert - handleUserActivity directly calls the app notification handler - XCTAssertTrue(appNotificationHandler.continueUserActivityCalled) - XCTAssertEqual(appNotificationHandler.continueUserActivityUserActivityParam, testUserActivity) - XCTAssertNotNil(appNotificationHandler.continueUserActivityRestorationHandlerParam) - } - - func test_handleUserActivity_withWebBrowsingActivity() { - // Arrange - let webActivity = NSUserActivity(activityType: NSUserActivityTypeBrowsingWeb) - webActivity.title = "Web Page" - webActivity.webpageURL = URL(string: "https://example.com/page") - - // Act - mparticle.handleUserActivity(webActivity) - - // Assert - Direct call to app notification handler - XCTAssertTrue(appNotificationHandler.continueUserActivityCalled) - XCTAssertEqual(appNotificationHandler.continueUserActivityUserActivityParam, webActivity) - } - - func test_handleUserActivity_restorationHandlerIsEmpty() { - // Act - mparticle.handleUserActivity(testUserActivity) - - // Assert - XCTAssertTrue(appNotificationHandler.continueUserActivityCalled) - - // Verify the restoration handler is provided and safe to call - let restorationHandler = appNotificationHandler.continueUserActivityRestorationHandlerParam - XCTAssertNotNil(restorationHandler) - - // Test that calling the restoration handler doesn't crash - XCTAssertNoThrow(restorationHandler?(nil)) - XCTAssertNoThrow(restorationHandler?([])) - } -} diff --git a/mParticle-Apple-SDK.xcodeproj/project.pbxproj b/mParticle-Apple-SDK.xcodeproj/project.pbxproj index 95a14fe2c..ce47935b6 100644 --- a/mParticle-Apple-SDK.xcodeproj/project.pbxproj +++ b/mParticle-Apple-SDK.xcodeproj/project.pbxproj @@ -566,8 +566,6 @@ 7E0387842DB913D2003B7D5E /* MPRokt.m in Sources */ = {isa = PBXBuildFile; fileRef = 7E0387802DB913D2003B7D5E /* MPRokt.m */; }; 7E15B2062D94617900C1FF3E /* MPRoktTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7E15B2052D94617900C1FF3E /* MPRoktTests.m */; }; 7E15B2072D94617900C1FF3E /* MPRoktTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7E15B2052D94617900C1FF3E /* MPRoktTests.m */; }; - 7E573D2A2ECB65D90087185D /* MParticleSceneDelegateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E573D292ECB65D90087185D /* MParticleSceneDelegateTests.swift */; }; - 7E573D2B2ECB65D90087185D /* MParticleSceneDelegateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E573D292ECB65D90087185D /* MParticleSceneDelegateTests.swift */; }; B31360F92E012760000DFBC9 /* MPRoktEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = B31360F72E012760000DFBC9 /* MPRoktEvent.swift */; }; B3D778622E02F55F00D887A4 /* MPRoktEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = B31360F72E012760000DFBC9 /* MPRoktEvent.swift */; }; D30CD0CB2CFF5FB100F5148A /* MPStateMachine.h in Headers */ = {isa = PBXBuildFile; fileRef = 53A79B0629CDFB1F00E7489F /* MPStateMachine.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -925,7 +923,6 @@ 7E03877F2DB913D2003B7D5E /* MPRokt.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPRokt.h; sourceTree = ""; }; 7E0387802DB913D2003B7D5E /* MPRokt.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MPRokt.m; sourceTree = ""; }; 7E15B2052D94617900C1FF3E /* MPRoktTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MPRoktTests.m; sourceTree = ""; }; - 7E573D292ECB65D90087185D /* MParticleSceneDelegateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MParticleSceneDelegateTests.swift; sourceTree = ""; }; B31360F72E012760000DFBC9 /* MPRoktEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPRoktEvent.swift; sourceTree = ""; }; D33C8B312B8510C20012EDFD /* MPAudience.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPAudience.h; sourceTree = ""; }; D33C8B322B8510C20012EDFD /* MPAudience.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MPAudience.m; sourceTree = ""; }; @@ -1507,7 +1504,6 @@ isa = PBXGroup; children = ( 7231B8342EB95F9F001565E5 /* MParticleBreadcrumbTests.swift */, - 7E573D292ECB65D90087185D /* MParticleSceneDelegateTests.swift */, 7231B83E2EB9627D001565E5 /* MParticleErrorTests.swift */, 7231B83B2EB961F2001565E5 /* MParticleLTVTests.swift */, 7231B84B2EB963B3001565E5 /* MParticleKitBatchTests.swift */, @@ -1914,7 +1910,6 @@ 534CD26929CE2CE1008452B3 /* MPSurrogateAppDelegateTests.m in Sources */, 534CD26A29CE2CE1008452B3 /* MPGDPRConsentTests.m in Sources */, 356D4A5A2E58B09D00CB69FE /* SettingsProviderMock.swift in Sources */, - 7E573D2A2ECB65D90087185D /* MParticleSceneDelegateTests.swift in Sources */, 534CD26B29CE2CE1008452B3 /* MPBackendControllerTests.m in Sources */, 534CD26C29CE2CE1008452B3 /* MPKitConfigurationTests.mm in Sources */, 7231B80E2EB3C4AC001565E5 /* MPKitMock.swift in Sources */, @@ -2134,7 +2129,6 @@ 53A79CD129CE019F00E7489F /* MPSurrogateAppDelegateTests.m in Sources */, 53A79CE729CE019F00E7489F /* MPGDPRConsentTests.m in Sources */, 356D4A592E58B09D00CB69FE /* SettingsProviderMock.swift in Sources */, - 7E573D2B2ECB65D90087185D /* MParticleSceneDelegateTests.swift in Sources */, 53A79CD229CE019F00E7489F /* MPBackendControllerTests.m in Sources */, 53A79CF329CE019F00E7489F /* MPKitConfigurationTests.mm in Sources */, 7231B80D2EB3C4AC001565E5 /* MPKitMock.swift in Sources */, @@ -2368,7 +2362,6 @@ "$(inherited)", ); INFOPLIST_FILE = ./UnitTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = "com.mparticle.mParticle-Apple-SDK-NoLocationTests"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -2381,7 +2374,6 @@ SWIFT_OBJC_BRIDGING_HEADER = "./UnitTests/mParticle_iOS_SDKTests-Bridging-Header.h"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2,3"; - TVOS_DEPLOYMENT_TARGET = 15.6; }; name = Debug; }; @@ -2398,7 +2390,6 @@ "$(inherited)", ); INFOPLIST_FILE = ./UnitTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = "com.mparticle.mParticle-Apple-SDK-NoLocationTests"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -2411,7 +2402,6 @@ SWIFT_OBJC_BRIDGING_HEADER = "./UnitTests/mParticle_iOS_SDKTests-Bridging-Header.h"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2,3"; - TVOS_DEPLOYMENT_TARGET = 15.6; }; name = Release; }; @@ -2629,7 +2619,6 @@ CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = DLD43Y3TRP; INFOPLIST_FILE = ./UnitTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = "com.mparticle.mParticle-Apple-SDKTests"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -2641,7 +2630,6 @@ SWIFT_OBJC_BRIDGING_HEADER = "./UnitTests/mParticle_iOS_SDKTests-Bridging-Header.h"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2,3"; - TVOS_DEPLOYMENT_TARGET = 15.6; }; name = Debug; }; @@ -2654,7 +2642,6 @@ CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = DLD43Y3TRP; INFOPLIST_FILE = ./UnitTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = "com.mparticle.mParticle-Apple-SDKTests"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -2666,7 +2653,6 @@ SWIFT_OBJC_BRIDGING_HEADER = "./UnitTests/mParticle_iOS_SDKTests-Bridging-Header.h"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2,3"; - TVOS_DEPLOYMENT_TARGET = 15.6; }; name = Release; }; diff --git a/mParticle-Apple-SDK/Include/mParticle.h b/mParticle-Apple-SDK/Include/mParticle.h index cd6685da5..344b18d96 100644 --- a/mParticle-Apple-SDK/Include/mParticle.h +++ b/mParticle-Apple-SDK/Include/mParticle.h @@ -754,9 +754,6 @@ Defaults to false. Prevents the eventsHost above from overwriting the alias endp #endif /** - DEPRECATED: https://developer.apple.com/documentation/uikit/uiapplicationdelegate/application(_:open:sourceapplication:annotation:) - Use a UIScene lifecycle, mParticle's handleURLContext: method, and scene(_:openURLContexts:) from UISceneDelegate instead. - Informs the mParticle SDK the app has been asked to open a resource identified by a URL. This method should be called only if proxiedAppDelegate is disabled. @param url The URL resource to open @@ -764,47 +761,25 @@ Defaults to false. Prevents the eventsHost above from overwriting the alias endp @param annotation A property list object supplied by the source app @see proxiedAppDelegate */ -- (void)openURL:(NSURL *)url sourceApplication:(nullable NSString *)sourceApplication annotation:(nullable id)annotation DEPRECATED_MSG_ATTRIBUTE("iOS 27 will no longer support this protocol method"); +- (void)openURL:(NSURL *)url sourceApplication:(nullable NSString *)sourceApplication annotation:(nullable id)annotation; /** - DEPRECATED: https://developer.apple.com/documentation/uikit/uiapplicationdelegate/application(_:open:sourceapplication:annotation:) - Use a UIScene lifecycle, mParticle's handleURLContext: method, and scene(_:openURLContexts:) from UISceneDelegate instead. - Informs the mParticle SDK the app has been asked to open a resource identified by a URL. This method should be called only if proxiedAppDelegate is disabled. This method is only available for iOS 9 and above. @param url The URL resource to open @param options The dictionary of launch options @see proxiedAppDelegate */ -- (void)openURL:(NSURL *)url options:(nullable NSDictionary *)options DEPRECATED_MSG_ATTRIBUTE("iOS 27 will no longer support this protocol method"); +- (void)openURL:(NSURL *)url options:(nullable NSDictionary *)options; /** - DEPRECATED: https://developer.apple.com/documentation/uikit/uiapplicationdelegate/application(_:continue:restorationhandler:) - Use UIScene lifecycle, mParticle's handleUserActivity: method, and scene(_:continue:) from UISceneDelegate instead. - Informs the mParticle SDK the app has been asked to open to continue an NSUserActivity. This method should be called only if proxiedAppDelegate is disabled. This method is only available for iOS 9 and above. @param userActivity The NSUserActivity that caused the app to be opened @param restorationHandler A block to execute if your app creates objects to perform the task. @see proxiedAppDelegate */ -- (BOOL)continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(void(^ _Nonnull)(NSArray> * __nullable restorableObjects))restorationHandler DEPRECATED_MSG_ATTRIBUTE("iOS 27 will no longer support this protocol method"); - -/** - Informs the mParticle SDK the app has been asked to open a resource identified by a URL. - This method should be called only if proxiedAppDelegate is disabled. This method is only available for iOS 13 and above. - @param urlContext The UIOpenURLContext provided by the SceneDelegate - @see proxiedAppDelegate - */ -- (void)handleURLContext:(UIOpenURLContext *)urlContext NS_SWIFT_NAME(handleURLContext(_:)) API_AVAILABLE(ios(13.0)); - -/** - Informs the mParticle SDK the app has been asked to open to continue an NSUserActivity. - This method should be called only if proxiedAppDelegate is disabled. - @param userActivity The NSUserActivity that caused the app to be opened - @see proxiedAppDelegate - */ -- (void)handleUserActivity:(NSUserActivity *)userActivity NS_SWIFT_NAME(handleUserActivity(_:)); +- (BOOL)continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(void(^ _Nonnull)(NSArray> * __nullable restorableObjects))restorationHandler; /** DEPRECATED: This method will permanently remove ALL MParticle data from the device, including MParticle UserDefaults and Database, it will also halt any further upload or download behavior that may be prepared diff --git a/mParticle-Apple-SDK/Kits/MPKitConfiguration.mm b/mParticle-Apple-SDK/Kits/MPKitConfiguration.mm index 51b3dd7a5..a3050d972 100644 --- a/mParticle-Apple-SDK/Kits/MPKitConfiguration.mm +++ b/mParticle-Apple-SDK/Kits/MPKitConfiguration.mm @@ -23,11 +23,7 @@ - (instancetype)initWithDictionary:(NSDictionary *)configurationDictionary { return nil; } - NSJSONWritingOptions options = 0; - if (@available(iOS 11.0, tvOS 11.0, *)) { - options = NSJSONWritingSortedKeys; - } - NSData *ekConfigData = [NSJSONSerialization dataWithJSONObject:configurationDictionary options:options error:nil]; + NSData *ekConfigData = [NSJSONSerialization dataWithJSONObject:configurationDictionary options:0 error:nil]; NSString *ekConfigString = [[NSString alloc] initWithData:ekConfigData encoding:NSUTF8StringEncoding]; _configurationHash = @([[MPIHasher hashString:ekConfigString] intValue]); @@ -118,11 +114,16 @@ - (id)initWithCoder:(NSCoder *)coder { @try { configurationDictionary = [coder decodeObjectOfClass:[NSDictionary class] forKey:@"configurationDictionary"]; } + @catch ( NSException *e) { configurationDictionary = nil; MPILogError(@"Exception decoding MPKitConfiguration Attributes: %@", [e reason]); } + @finally { + self = [self initWithDictionary:configurationDictionary]; + } + self = [self initWithDictionary:configurationDictionary]; if (!self) { return nil; diff --git a/mParticle-Apple-SDK/mParticle.m b/mParticle-Apple-SDK/mParticle.m index 232d6857d..1e1fd9d78 100644 --- a/mParticle-Apple-SDK/mParticle.m +++ b/mParticle-Apple-SDK/mParticle.m @@ -697,46 +697,6 @@ - (BOOL)continueUserActivity:(nonnull NSUserActivity *)userActivity restorationH return [self.appNotificationHandler continueUserActivity:userActivity restorationHandler:restorationHandler]; } -- (void)handleURLContext:(UIOpenURLContext *)urlContext API_AVAILABLE(ios(13.0)){ - NSString *messageURL = [NSString stringWithFormat:@"Opening URLContext URL: %@", urlContext.URL]; - [logger debug:messageURL]; - NSString *messageSource = [NSString stringWithFormat:@"Source: %@", urlContext.options.sourceApplication ? urlContext.options.sourceApplication : @"unknown"]; - [logger debug:messageSource]; - NSString *messageAnnotation = [NSString stringWithFormat:@"Annotation: %@", urlContext.options.annotation]; - [logger debug:messageAnnotation]; -#if TARGET_OS_IOS == 1 - if (@available(iOS 14.5, *)) { - NSString *messageEventAttribution = [NSString stringWithFormat:@"Event Attribution: %@", urlContext.options.eventAttribution]; - [logger debug:messageEventAttribution]; - } -#endif - NSString *messageOpenInPlace = [NSString stringWithFormat:@"Open in place: %@", urlContext.options.openInPlace ? @"True" : @"False"]; - [logger debug:messageOpenInPlace]; - - // Currently only one kit integration uses this dictionary for this key - // https://github.com/mparticle-integrations/mparticle-apple-integration-flurry/blob/a0856e271aa9a63a6668805582395dea63f96af5/mParticle-Flurry/MPKitFlurry.m#L148C38-L148C85 - NSDictionary *options = @{@"UIApplicationOpenURLOptionsSourceApplicationKey": urlContext.options.sourceApplication}; - - [self.appNotificationHandler openURL:urlContext.URL options:options]; -} - -- (void)handleUserActivity:(NSUserActivity *)userActivity { - NSString *message = [NSString stringWithFormat:@"User Activity Received"]; - [logger debug:message]; - NSString *messageType = [NSString stringWithFormat:@"User Activity Type: %@", userActivity.activityType]; - [logger debug:messageType]; - NSString *messageTitle = [NSString stringWithFormat:@"User Activity Title: %@", userActivity.title]; - [logger debug:messageTitle]; - NSString *messageUserInfo = [NSString stringWithFormat:@"User Activity User Info: %@", userActivity.userInfo]; - [logger debug:messageUserInfo]; - if (userActivity.activityType == NSUserActivityTypeBrowsingWeb) { - NSString *messageURL = [NSString stringWithFormat:@"Opening UserActivity URL: %@", userActivity.webpageURL]; - [logger debug:messageURL]; - } - // When provided by the SceneDelegate NSUserActivity is not paired with a restorationHandler - [self.appNotificationHandler continueUserActivity: userActivity restorationHandler:^(NSArray> * _Nullable restorableObjects) {}]; -} - - (void)reset:(void (^)(void))completion { [executor executeOnMessage:^{ [self.kitContainer flushSerializedKits];