Skip to content

Commit b4767f1

Browse files
move new code to swift
1 parent b8326ee commit b4767f1

File tree

7 files changed

+71
-38
lines changed

7 files changed

+71
-38
lines changed

UnitTests/MParticle+PrivateMethods.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252

5353
@property (nonatomic, strong, nonnull) id<MPBackendControllerProtocol> backendController;
5454
@property (nonatomic, strong) id<MPAppNotificationHandlerProtocol> appNotificationHandler;
55+
@property (nonatomic, strong) SceneDelegateHandler *sceneDelegateHandler;
5556
@property (nonatomic, strong) id<SettingsProviderProtocol> settingsProvider;
5657
@property (nonatomic, strong, nullable) id<MPDataPlanFilterProtocol> dataPlanFilter;
5758
@property (nonatomic, strong, nonnull) id<MPListenerControllerProtocol> listenerController;
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import XCTest
2+
#if MPARTICLE_LOCATION_DISABLE
3+
import mParticle_Apple_SDK_NoLocation
4+
#else
5+
import mParticle_Apple_SDK
6+
#endif
7+
8+
class SceneDelegateHandlerMock: OpenURLHandlerProtocol {
9+
10+
var openURLWithOptionsCalled = false
11+
var openURLWithOptionsURLParam: URL?
12+
var openURLWithOptionsOptionsParam: [String : Any]?
13+
14+
func open(_ url: URL, options: [String : Any]?) {
15+
openURLWithOptionsCalled = true
16+
openURLWithOptionsURLParam = url
17+
openURLWithOptionsOptionsParam = options
18+
}
19+
20+
var continueUserActivityCalled = false
21+
var continueUserActivityUserActivityParam: NSUserActivity?
22+
var continueUserActivityRestorationHandlerParam: (([UIUserActivityRestoring]?) -> Void)?
23+
var continueUserActivityReturnValue: Bool = false
24+
25+
func continueUserActivity(_ userActivity: NSUserActivity, restorationHandler: @escaping ([any UIUserActivityRestoring]?) -> Void) -> Bool {
26+
continueUserActivityCalled = true
27+
continueUserActivityUserActivityParam = userActivity
28+
continueUserActivityRestorationHandlerParam = restorationHandler
29+
return continueUserActivityReturnValue
30+
}
31+
}

UnitTests/SwiftTests/MParticle/MParticleSceneDelegateTests.swift

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,42 +6,37 @@ import mParticle_Apple_SDK
66
#endif
77
import XCTest
88

9-
final class MParticleSceneDelegateTests: MParticleTestBase {
9+
final class MParticleSceneDelegateTests: XCTestCase {
1010

1111
// MARK: - Properties
12-
12+
var mparticle: MParticle!
13+
var sceneMock: SceneDelegateHandlerMock!
1314
var testURL: URL!
1415
var testUserActivity: NSUserActivity!
1516

1617
override func setUp() {
1718
super.setUp()
19+
mparticle = MParticle()
1820
testURL = URL(string: "myapp://test/path?param=value")!
1921
testUserActivity = NSUserActivity(activityType: "com.test.activity")
2022
testUserActivity.title = "Test Activity"
2123
testUserActivity.userInfo = ["key": "value"]
2224

2325
// The implementation calls [MParticle sharedInstance], so we need to set the mock on the shared instance
24-
MParticle.sharedInstance().appNotificationHandler = appNotificationHandler
25-
26-
// Reset mock state for each test
27-
appNotificationHandler.continueUserActivityCalled = false
28-
appNotificationHandler.continueUserActivityUserActivityParam = nil
29-
appNotificationHandler.continueUserActivityRestorationHandlerParam = nil
30-
appNotificationHandler.openURLWithOptionsCalled = false
31-
appNotificationHandler.openURLWithOptionsURLParam = nil
32-
appNotificationHandler.openURLWithOptionsOptionsParam = nil
26+
sceneMock = SceneDelegateHandlerMock()
27+
let sceneHandler = SceneDelegateHandler(logger: MPLog(logLevel: .verbose), appNotificationHandler: sceneMock)
28+
mparticle.sceneDelegateHandler = sceneHandler
3329
}
3430

35-
// MARK: - handleUserActivity Tests
36-
31+
// MARK: - handleUserActivity Tests
3732
func test_handleUserActivity_invokesAppNotificationHandler() {
3833
// Act
3934
mparticle.handleUserActivity(testUserActivity)
4035

4136
// Assert - handleUserActivity directly calls the app notification handler
42-
XCTAssertTrue(appNotificationHandler.continueUserActivityCalled)
43-
XCTAssertEqual(appNotificationHandler.continueUserActivityUserActivityParam, testUserActivity)
44-
XCTAssertNotNil(appNotificationHandler.continueUserActivityRestorationHandlerParam)
37+
XCTAssertTrue(sceneMock.continueUserActivityCalled)
38+
XCTAssertEqual(sceneMock.continueUserActivityUserActivityParam, testUserActivity)
39+
XCTAssertNotNil(sceneMock.continueUserActivityRestorationHandlerParam)
4540
}
4641

4742
func test_handleUserActivity_withWebBrowsingActivity() {
@@ -54,19 +49,19 @@ final class MParticleSceneDelegateTests: MParticleTestBase {
5449
mparticle.handleUserActivity(webActivity)
5550

5651
// Assert - Direct call to app notification handler
57-
XCTAssertTrue(appNotificationHandler.continueUserActivityCalled)
58-
XCTAssertEqual(appNotificationHandler.continueUserActivityUserActivityParam, webActivity)
52+
XCTAssertTrue(sceneMock.continueUserActivityCalled)
53+
XCTAssertEqual(sceneMock.continueUserActivityUserActivityParam, webActivity)
5954
}
6055

6156
func test_handleUserActivity_restorationHandlerIsEmpty() {
6257
// Act
6358
mparticle.handleUserActivity(testUserActivity)
6459

6560
// Assert
66-
XCTAssertTrue(appNotificationHandler.continueUserActivityCalled)
61+
XCTAssertTrue(sceneMock.continueUserActivityCalled)
6762

6863
// Verify the restoration handler is provided and safe to call
69-
let restorationHandler = appNotificationHandler.continueUserActivityRestorationHandlerParam
64+
let restorationHandler = sceneMock.continueUserActivityRestorationHandlerParam
7065
XCTAssertNotNil(restorationHandler)
7166

7267
// Test that calling the restoration handler doesn't crash

mParticle-Apple-SDK.xcodeproj/project.pbxproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,8 @@
570570
7E15B2072D94617900C1FF3E /* MPRoktTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7E15B2052D94617900C1FF3E /* MPRoktTests.m */; };
571571
7E573D2A2ECB65D90087185D /* MParticleSceneDelegateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E573D292ECB65D90087185D /* MParticleSceneDelegateTests.swift */; };
572572
7E573D2B2ECB65D90087185D /* MParticleSceneDelegateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E573D292ECB65D90087185D /* MParticleSceneDelegateTests.swift */; };
573+
7E87E0C12EE093E100A18E3A /* SceneDelegateHandlerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E87E0BE2EE093E100A18E3A /* SceneDelegateHandlerMock.swift */; };
574+
7E87E0C22EE093E100A18E3A /* SceneDelegateHandlerMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E87E0BE2EE093E100A18E3A /* SceneDelegateHandlerMock.swift */; };
573575
B31360F92E012760000DFBC9 /* MPRoktEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = B31360F72E012760000DFBC9 /* MPRoktEvent.swift */; };
574576
B3D778622E02F55F00D887A4 /* MPRoktEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = B31360F72E012760000DFBC9 /* MPRoktEvent.swift */; };
575577
D30CD0CB2CFF5FB100F5148A /* MPStateMachine.h in Headers */ = {isa = PBXBuildFile; fileRef = 53A79B0629CDFB1F00E7489F /* MPStateMachine.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -929,6 +931,7 @@
929931
7E0387802DB913D2003B7D5E /* MPRokt.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MPRokt.m; sourceTree = "<group>"; };
930932
7E15B2052D94617900C1FF3E /* MPRoktTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MPRoktTests.m; sourceTree = "<group>"; };
931933
7E573D292ECB65D90087185D /* MParticleSceneDelegateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MParticleSceneDelegateTests.swift; sourceTree = "<group>"; };
934+
7E87E0BE2EE093E100A18E3A /* SceneDelegateHandlerMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SceneDelegateHandlerMock.swift; path = UnitTests/Mocks/SceneDelegateHandlerMock.swift; sourceTree = "<group>"; };
932935
B31360F72E012760000DFBC9 /* MPRoktEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPRoktEvent.swift; sourceTree = "<group>"; };
933936
D33C8B312B8510C20012EDFD /* MPAudience.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPAudience.h; sourceTree = "<group>"; };
934937
D33C8B322B8510C20012EDFD /* MPAudience.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MPAudience.m; sourceTree = "<group>"; };
@@ -1011,6 +1014,7 @@
10111014
53A79A6F29CCCD6400E7489F = {
10121015
isa = PBXGroup;
10131016
children = (
1017+
7E87E0BE2EE093E100A18E3A /* SceneDelegateHandlerMock.swift */,
10141018
D3BA75152B614E3D008C3C65 /* PrivacyInfo.xcprivacy */,
10151019
53A79CFE29CE12AB00E7489F /* mParticle-Apple-SDK.modulemap */,
10161020
53A79CFF29CE23D600E7489F /* mParticle-Apple-SDK-NoLocation.modulemap */,
@@ -1948,6 +1952,7 @@
19481952
534CD27B29CE2CE1008452B3 /* MPZipTests.m in Sources */,
19491953
7231B8522EB964A1001565E5 /* MParticleOpenURLTests.swift in Sources */,
19501954
53E20DC82CBFFCD200146A97 /* NSArray+MPCaseInsensitiveTests.swift in Sources */,
1955+
7E87E0C22EE093E100A18E3A /* SceneDelegateHandlerMock.swift in Sources */,
19511956
534CD27C29CE2CE1008452B3 /* MPIntegrationAttributesTest.m in Sources */,
19521957
356752932E60928B00DEEE23 /* MPStateMachineMock.swift in Sources */,
19531958
534CD27D29CE2CE1008452B3 /* MPDataModelTests.m in Sources */,
@@ -2169,6 +2174,7 @@
21692174
53E20DC72CBFFCD200146A97 /* NSArray+MPCaseInsensitiveTests.swift in Sources */,
21702175
7231B8532EB964A1001565E5 /* MParticleOpenURLTests.swift in Sources */,
21712176
53A79CEC29CE019F00E7489F /* MPZipTests.m in Sources */,
2177+
7E87E0C12EE093E100A18E3A /* SceneDelegateHandlerMock.swift in Sources */,
21722178
356752942E60928B00DEEE23 /* MPStateMachineMock.swift in Sources */,
21732179
53A79CCC29CE019F00E7489F /* MPIntegrationAttributesTest.m in Sources */,
21742180
53A79CBD29CE019F00E7489F /* MPDataModelTests.m in Sources */,

mParticle-Apple-SDK/Include/mParticle.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -790,13 +790,15 @@ Defaults to false. Prevents the eventsHost above from overwriting the alias endp
790790
*/
791791
- (BOOL)continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(void(^ _Nonnull)(NSArray<id<UIUserActivityRestoring>> * __nullable restorableObjects))restorationHandler DEPRECATED_MSG_ATTRIBUTE("iOS 27 will no longer support this protocol method");
792792

793+
#if TARGET_OS_IOS == 1
793794
/**
794795
Informs the mParticle SDK the app has been asked to open a resource identified by a URL.
795796
This method should be called only if proxiedAppDelegate is disabled. This method is only available for iOS 13 and above.
796797
@param urlContext The UIOpenURLContext provided by the SceneDelegate
797798
@see proxiedAppDelegate
798799
*/
799800
- (void)handleURLContext:(UIOpenURLContext *)urlContext NS_SWIFT_NAME(handleURLContext(_:)) API_AVAILABLE(ios(13.0));
801+
#endif
800802

801803
/**
802804
Informs the mParticle SDK the app has been asked to open to continue an NSUserActivity.

mParticle-Apple-SDK/SceneDelegateHandler.swift

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,7 @@
1-
//
2-
// SceneDelegateHandler.swift
3-
// mParticle-Apple-SDK
4-
//
5-
// Created by Denis Chilik on 12/2/25.
6-
//
7-
81
import Foundation
92

103
@objc
11-
public protocol OpenUrlHandlerProtocol {
4+
public protocol OpenURLHandlerProtocol {
125
func open(_ url: URL, options: [String: Any]?)
136
func continueUserActivity(
147
_ userActivity: NSUserActivity,
@@ -19,31 +12,32 @@ public protocol OpenUrlHandlerProtocol {
1912
@objcMembers
2013
public class SceneDelegateHandler: NSObject {
2114
private let logger: MPLog
22-
private let appNotificationHandler: OpenUrlHandlerProtocol
15+
private let appNotificationHandler: OpenURLHandlerProtocol
2316

24-
public init(logger: MPLog, appNotificationHandler: OpenUrlHandlerProtocol) {
17+
public init(logger: MPLog, appNotificationHandler: OpenURLHandlerProtocol) {
2518
self.logger = logger
2619
self.appNotificationHandler = appNotificationHandler
2720
}
2821

22+
#if os(iOS)
23+
@available(iOS 13.0, *)
2924
@available(iOSApplicationExtension 13.0, *)
3025
public func handle(urlContext: UIOpenURLContext) {
3126
logger.debug("Opening URLContext URL: \(urlContext.url)")
3227
logger.debug("Source: \(String(describing: urlContext.options.sourceApplication ?? "unknown"))")
3328
logger.debug("Annotation: \(String(describing: urlContext.options.annotation))")
34-
#if os(iOS)
3529
if #available(iOS 14.5, *) {
3630
logger.debug("Event Attribution: \(String(describing: urlContext.options.eventAttribution))")
3731
}
38-
#endif
3932
logger.debug("Open in place: \(urlContext.options.openInPlace ? "True" : "False")")
4033

4134
let options = ["UIApplicationOpenURLOptionsSourceApplicationKey": urlContext.options.sourceApplication];
4235

4336
self.appNotificationHandler.open(urlContext.url, options: options as [String: Any])
4437
}
38+
#endif
4539

46-
public func continueUserActivity(_ userActivity: NSUserActivity) {
40+
public func handleUserActivity(_ userActivity: NSUserActivity) {
4741
logger.debug("User Activity Received")
4842
logger.debug("User Activity Type: \(userActivity.activityType)")
4943
logger.debug("User Activity Title: \(userActivity.title ?? "")")

mParticle-Apple-SDK/mParticle.m

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ @interface MParticle() <MPBackendControllerDelegate
5454
@property (nonatomic, strong) id<MPStateMachineProtocol> stateMachine;
5555
@property (nonatomic, strong) MPKitContainer_PRIVATE *kitContainer_PRIVATE;
5656
@property (nonatomic, strong) id<MPKitContainerProtocol> kitContainer;
57-
@property (nonatomic, strong) id<MPAppNotificationHandlerProtocol, OpenUrlHandlerProtocol> appNotificationHandler;
57+
@property (nonatomic, strong) id<MPAppNotificationHandlerProtocol, OpenURLHandlerProtocol> appNotificationHandler;
58+
@property (nonatomic, strong) SceneDelegateHandler *sceneDelegateHandler;
5859
@property (nonatomic, strong, nonnull) id<MPBackendControllerProtocol> backendController;
5960
@property (nonatomic, strong, nonnull) MParticleOptions *options;
6061
@property (nonatomic, strong, nullable) MPKitActivity *kitActivity;
@@ -98,6 +99,7 @@ @implementation MParticle
9899
@synthesize listenerController = _listenerController;
99100
static id<ExecutorProtocol> executor;
100101
MPLog* logger;
102+
@synthesize sceneDelegateHandler = _sceneDelegateHandler;
101103

102104
+ (void)initialize {
103105
if (self == [MParticle class]) {
@@ -149,13 +151,14 @@ - (instancetype)init {
149151
_collectSearchAdsAttribution = NO;
150152
_trackNotifications = YES;
151153
_automaticSessionTracking = YES;
152-
_appNotificationHandler = [[MPAppNotificationHandler alloc] init];
154+
_appNotificationHandler = (id<MPAppNotificationHandlerProtocol, OpenURLHandlerProtocol>)[[MPAppNotificationHandler alloc] init];
153155
_stateMachine = [[MPStateMachine_PRIVATE alloc] init];
154156
_webView = [[MParticleWebView_PRIVATE alloc] initWithMessageQueue:executor.messageQueue];
155157
_listenerController = MPListenerController.sharedInstance;
156158
_appEnvironmentProvider = [[AppEnvironmentProvider alloc] init];
157159
_notificationController = [[MPNotificationController_PRIVATE alloc] init];
158160
logger = [[MPLog alloc] initWithLogLevel:_stateMachine.logLevel];
161+
_sceneDelegateHandler = [[SceneDelegateHandler alloc] initWithLogger:logger appNotificationHandler:_appNotificationHandler];
159162

160163
return self;
161164
}
@@ -700,13 +703,14 @@ - (BOOL)continueUserActivity:(nonnull NSUserActivity *)userActivity restorationH
700703

701704

702705

706+
#if TARGET_OS_IOS == 1
703707
- (void)handleURLContext:(UIOpenURLContext *)urlContext API_AVAILABLE(ios(13.0)) {
704-
MPartiche.shredInstanse.hsceneDelegareHandler.andleURLContext
705-
[handler handleWithUrlContext:urlContext];
708+
[self.sceneDelegateHandler handleWithUrlContext:urlContext];
706709
}
710+
#endif
707711

708712
- (void)handleUserActivity:(NSUserActivity *)userActivity {
709-
[handler handleUserActivity:userActivity];
713+
[self.sceneDelegateHandler handleUserActivity:userActivity];
710714
}
711715

712716
- (void)reset:(void (^)(void))completion {

0 commit comments

Comments
 (0)