Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion IntegrationTests/Sources/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import Foundation
import mParticle_Apple_SDK_NoLocation

@discardableResult
func wait(timeout: UInt32 = 5) {
mparticle.upload()
sleep(timeout)
Expand Down
36 changes: 36 additions & 0 deletions MIGRATING.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,42 @@ This change only affects users who:

The `MPListenerController` class has been removed. The SDK no longer invokes any listener callbacks.

### Direct Routing Enabled by Default

API requests now route directly to regional endpoints based on your API key prefix:

**Before:**

- `nativesdks.mparticle.com`
- `tracking-nativesdks.mparticle.com`
- `identity.mparticle.com`
- `tracking-identity.mparticle.com`
- `config2.mparticle.com`

**After:**

- `nativesdks.[pod].mparticle.com`
- `tracking-nativesdks.[pod].mparticle.com`
- `identity.[pod].mparticle.com`
- `tracking-identity.[pod].mparticle.com`
- `config2.mparticle.com`

> [!NOTE]
> The `config2.mparticle.com` subdomain is used to fetch SDK configuration and will not change.

Examples:

| API Key Format | Events Endpoint | Events Tracking Endpoint | Identity Endpoint | Identity Tracking Endpoint |
| --------------------------- | ------------------------------ | --------------------------------------- | ---------------------------- | ------------------------------------- |
| `xxxxx` (legacy, no prefix) | `nativesdks.us1.mparticle.com` | `tracking-nativesdks.us1.mparticle.com` | `identity.us1.mparticle.com` | `tracking-identity.us1.mparticle.com` |
| `us1-xxxxx` | `nativesdks.us1.mparticle.com` | `tracking-nativesdks.us1.mparticle.com` | `identity.us1.mparticle.com` | `tracking-identity.us1.mparticle.com` |
| `us2-xxxxx` | `nativesdks.us2.mparticle.com` | `tracking-nativesdks.us2.mparticle.com` | `identity.us2.mparticle.com` | `tracking-identity.us2.mparticle.com` |
| `eu1-xxxxx` | `nativesdks.eu1.mparticle.com` | `tracking-nativesdks.eu1.mparticle.com` | `identity.eu1.mparticle.com` | `tracking-identity.eu1.mparticle.com` |
| `au1-xxxxx` | `nativesdks.au1.mparticle.com` | `tracking-nativesdks.au1.mparticle.com` | `identity.au1.mparticle.com` | `tracking-identity.au1.mparticle.com` |

> [!NOTE]
> If your app has strict App Transport Security (ATS) settings, you may need to add `NSIncludesSubdomains` set to `YES` for the `mparticle.com` domain in your Info.plist to allow connections to regional subdomains.

### Removed Deprecated UIApplicationDelegate Methods

Apple has deprecated several `UIApplicationDelegate` protocol methods in favor of the modern `UIScene` lifecycle introduced in iOS 13. The mParticle SDK previously provided wrapper methods for these deprecated delegate methods, but these have been removed as they are scheduled for removal by Apple in iOS 27.
Expand Down
2 changes: 1 addition & 1 deletion UnitTests/ObjCTests/MPNetworkCommunication+Tests.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ extern NSString * _Nonnull const kMPURLHostIdentitySubdomain;

@interface MPNetworkCommunication_PRIVATE(Tests)

- (nonnull NSString *)defaultHostWithSubdomain:(nonnull NSString *)subdomain apiKey:(nonnull NSString *)apiKey enableDirectRouting:(BOOL)enableDirectRouting;
- (nonnull NSString *)defaultHostWithSubdomain:(nonnull NSString *)subdomain apiKey:(nonnull NSString *)apiKey;
- (nonnull NSString *)defaultEventHost;
- (nonnull NSString *)defaultIdentityHost;

Expand Down
30 changes: 3 additions & 27 deletions UnitTests/ObjCTests/MPNetworkCommunicationTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ - (void)testModifyURL {

[self deswizzle];

XCTAssert([modifyURL.absoluteString rangeOfString:@"https://identity.mparticle.com/v1/0/modify"].location != NSNotFound);
XCTAssert([modifyURL.absoluteString rangeOfString:@"https://identity.us1.mparticle.com/v1/0/modify"].location != NSNotFound);
XCTAssert([modifyURL.accessibilityHint isEqualToString:@"identity"]);
}

Expand Down Expand Up @@ -200,7 +200,7 @@ - (void)testAliasURL {

[self deswizzle];

XCTAssert([aliasURL.absoluteString rangeOfString:@"https://nativesdks.mparticle.com/v1/identity/"].location != NSNotFound);
XCTAssert([aliasURL.absoluteString rangeOfString:@"https://nativesdks.us1.mparticle.com/v1/identity/"].location != NSNotFound);
XCTAssert([aliasURL.accessibilityHint isEqualToString:@"identity"]);
}

Expand Down Expand Up @@ -252,7 +252,7 @@ - (void)testAliasURLWithEventsOnly {

[self deswizzle];

XCTAssert([aliasURL.absoluteString rangeOfString:@"https://nativesdks.mparticle.com/v1/identity/"].location != NSNotFound);
XCTAssert([aliasURL.absoluteString rangeOfString:@"https://nativesdks.us1.mparticle.com/v1/identity/"].location != NSNotFound);
XCTAssert([aliasURL.accessibilityHint isEqualToString:@"identity"]);
}

Expand Down Expand Up @@ -938,31 +938,7 @@ - (void)testPodURLRoutingAndTrackingURL {
];
MPNetworkCommunication_PRIVATE *networkCommunication = [[MPNetworkCommunication_PRIVATE alloc] init];
MPStateMachine_PRIVATE *stateMachine = [MParticle sharedInstance].stateMachine;
NSString *oldEventHost = @"nativesdks.mparticle.com";
NSString *oldIdentityHost = @"identity.mparticle.com";

stateMachine.enableDirectRouting = NO;
stateMachine.attAuthorizationStatus = @(MPATTAuthorizationStatusNotDetermined);
for (NSArray *test in testKeys) {
NSString *key = test[0];
stateMachine.apiKey = key;

XCTAssertEqualObjects(oldEventHost, [networkCommunication defaultEventHost]);
XCTAssertEqualObjects(oldIdentityHost, [networkCommunication defaultIdentityHost]);
}

NSString *newEventHost = @"tracking-nativesdks.mparticle.com";
NSString *newIdentityHost = @"tracking-identity.mparticle.com";
stateMachine.attAuthorizationStatus = @(MPATTAuthorizationStatusAuthorized);
for (NSArray *test in testKeys) {
NSString *key = test[0];
stateMachine.apiKey = key;

XCTAssertEqualObjects(newEventHost, [networkCommunication defaultEventHost]);
XCTAssertEqualObjects(newIdentityHost, [networkCommunication defaultIdentityHost]);
}

stateMachine.enableDirectRouting = YES;
stateMachine.attAuthorizationStatus = @(MPATTAuthorizationStatusNotDetermined);
for (NSArray *test in testKeys) {
NSString *key = test[0];
Expand Down
18 changes: 18 additions & 0 deletions UnitTests/ObjCTests/MPResponseConfigTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -183,5 +183,23 @@ - (void)testDeleteDueToMaxConfigAge {
[self waitForExpectationsWithTimeout:DEFAULT_TIMEOUT handler:nil];
}

- (void)testIgnoresLegacyDirectRoutingConfig {
NSDictionary *configuration = @{
kMPRemoteConfigKitsKey: [NSNull null],
kMPRemoteConfigCustomModuleSettingsKey: [NSNull null],
kMPRemoteConfigRampKey: @100,
kMPRemoteConfigTriggerKey: [NSNull null],
kMPRemoteConfigExceptionHandlingModeKey: kMPRemoteConfigExceptionHandlingModeIgnore,
kMPRemoteConfigSessionTimeoutKey: @112,
@"dur": @NO
};

MPResponseConfig *responseConfig = [[MPResponseConfig alloc] initWithConfiguration:configuration
stateMachine:[MParticle sharedInstance].stateMachine
backendController:[MParticle sharedInstance].backendController];

XCTAssertNotNil(responseConfig, @"Config should parse successfully even with legacy dur key");
}


@end
12 changes: 6 additions & 6 deletions UnitTests/ObjCTests/MPURLRequestBuilderTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,7 @@ - (void)testSignatureRelativePath {
MPURLRequestBuilder *builder = [MPURLRequestBuilder newBuilderWithURL:baseURL];

NSString *result = builder.url.defaultURL.absoluteString;
XCTAssertEqualObjects(result, @"https://identity.mparticle.com/v1/12/modify");
XCTAssertEqualObjects(result, @"https://identity.us1.mparticle.com/v1/12/modify");
result = builder.url.url.absoluteString;
XCTAssertEqualObjects(result, @"https://identity.mp.example.com/v1/12/modify");

Expand All @@ -458,7 +458,7 @@ - (void)testSignatureRelativePath {
builder = [MPURLRequestBuilder newBuilderWithURL:baseURL];

result = builder.url.defaultURL.absoluteString;
XCTAssertEqualObjects(result, @"https://identity.mparticle.com/v1/12/modify");
XCTAssertEqualObjects(result, @"https://identity.us1.mparticle.com/v1/12/modify");
result = builder.url.url.absoluteString;
XCTAssertTrue([result isEqualToString:@"https://https://example.com/12/modify"] || [result isEqualToString:@"https://https//example.com/12/modify"]);

Expand All @@ -467,18 +467,18 @@ - (void)testSignatureRelativePath {
builder = [MPURLRequestBuilder newBuilderWithURL:baseURL];

result = builder.url.defaultURL.absoluteString;
XCTAssertEqualObjects(result, @"https://identity.mparticle.com/v1/12/modify");
XCTAssertEqualObjects(result, @"https://identity.us1.mparticle.com/v1/12/modify");
result = builder.url.url.absoluteString;
XCTAssertEqualObjects(result, @"https://identity.mparticle.com/12/modify");
XCTAssertEqualObjects(result, @"https://identity.us1.mparticle.com/12/modify");

networkOptions = nil;
baseURL = [networkCommunication modifyURL];
builder = [MPURLRequestBuilder newBuilderWithURL:baseURL];

result = builder.url.defaultURL.absoluteString;
XCTAssertEqualObjects(result, @"https://identity.mparticle.com/v1/12/modify");
XCTAssertEqualObjects(result, @"https://identity.us1.mparticle.com/v1/12/modify");
result = builder.url.url.absoluteString;
XCTAssertEqualObjects(result, @"https://identity.mparticle.com/12/modify");
XCTAssertEqualObjects(result, @"https://identity.us1.mparticle.com/12/modify");
}

@end
1 change: 0 additions & 1 deletion mParticle-Apple-SDK/Include/MPStateMachine.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@
@property (nonatomic) BOOL automaticSessionTracking;
@property (nonatomic) BOOL allowASR;
@property (nonatomic, nullable) MPDataPlanOptions *dataPlanOptions;
@property (nonatomic) BOOL enableDirectRouting;
@property (nonatomic) BOOL enableAudienceAPI;
@property (nonatomic) BOOL enableIdentityCaching;

Expand Down
1 change: 0 additions & 1 deletion mParticle-Apple-SDK/MPConstants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,6 @@ enum RemoteConfig {
static let kMPRemoteConfigAliasMaxWindow = "alias_max_window"
static let kMPRemoteConfigAllowASR = "iasr"
static let kMPRemoteConfigExcludeAnonymousUsersKey = "eau"
static let kMPRemoteConfigDirectURLRouting = "dur"
static let kMPRemoteConfigFlagsKey = "flags"
static let kMPRemoteConfigAudienceAPIKey = "AudienceAPI"
static let kMPRemoteConfigDataPlanningResults = "dpr"
Expand Down
1 change: 0 additions & 1 deletion mParticle-Apple-SDK/MPIConstants.h
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,6 @@ extern NSString * _Nonnull const kMPRemoteConfigRestrictIDFA;
extern NSString * _Nonnull const kMPRemoteConfigAliasMaxWindow;
extern NSString * _Nonnull const kMPRemoteConfigAllowASR;
extern NSString * _Nonnull const kMPRemoteConfigExcludeAnonymousUsersKey;
extern NSString * _Nonnull const kMPRemoteConfigDirectURLRouting;

extern NSString * _Nonnull const kMPRemoteConfigBlockUnplannedEvents;
extern NSString * _Nonnull const kMPRemoteConfigBlockUnplannedEventAttributes;
Expand Down
1 change: 0 additions & 1 deletion mParticle-Apple-SDK/MPIConstants.m
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,6 @@
NSString *const kMPRemoteConfigAliasMaxWindow = @"alias_max_window";
NSString *const kMPRemoteConfigAllowASR = @"iasr";
NSString *const kMPRemoteConfigExcludeAnonymousUsersKey = @"eau";
NSString *const kMPRemoteConfigDirectURLRouting = @"dur";
NSString *const kMPRemoteConfigDataPlanningResults = @"dpr";
NSString *const kMPRemoteConfigDataPlanning = @"dtpn";
NSString *const kMPRemoteConfigDataPlanningBlock = @"blok";
Expand Down
25 changes: 10 additions & 15 deletions mParticle-Apple-SDK/Network/MPNetworkCommunication.m
Original file line number Diff line number Diff line change
Expand Up @@ -119,35 +119,30 @@ - (instancetype)init {

#pragma mark Private accessors

- (NSString *)defaultHostWithSubdomain:(NSString *)subdomain apiKey:(NSString *)apiKey enableDirectRouting:(BOOL)enableDirectRouting {
if (enableDirectRouting) {
NSArray *splitKey = [apiKey componentsSeparatedByString:@"-"];
if (splitKey.count <= 1) {
// Handle case with no prefix, default to US1 (old keys)
return [NSString stringWithFormat:@"%@.us1.mparticle.com", subdomain];
}
return [NSString stringWithFormat:@"%@.%@.mparticle.com", subdomain, splitKey[0]];
- (NSString *)defaultHostWithSubdomain:(NSString *)subdomain apiKey:(NSString *)apiKey {
NSArray *splitKey = [apiKey componentsSeparatedByString:@"-"];
if (splitKey.count <= 1) {
// Handle case with no prefix, default to US1 (old keys)
return [NSString stringWithFormat:@"%@.us1.mparticle.com", subdomain];
}

// Handle feature flag disabled (old behavior)
return [NSString stringWithFormat:@"%@.mparticle.com", subdomain];
return [NSString stringWithFormat:@"%@.%@.mparticle.com", subdomain, splitKey[0]];
}

- (NSString *)defaultEventHost {
MPStateMachine_PRIVATE *stateMachine = [MParticle sharedInstance].stateMachine;
if (stateMachine.attAuthorizationStatus.integerValue == MPATTAuthorizationStatusAuthorized) {
return [self defaultHostWithSubdomain:kMPURLHostEventTrackingSubdomain apiKey:stateMachine.apiKey enableDirectRouting:stateMachine.enableDirectRouting];
return [self defaultHostWithSubdomain:kMPURLHostEventTrackingSubdomain apiKey:stateMachine.apiKey];
} else {
return [self defaultHostWithSubdomain:kMPURLHostEventSubdomain apiKey:stateMachine.apiKey enableDirectRouting:stateMachine.enableDirectRouting];
return [self defaultHostWithSubdomain:kMPURLHostEventSubdomain apiKey:stateMachine.apiKey];
}
}

- (NSString *)defaultIdentityHost {
MPStateMachine_PRIVATE *stateMachine = [MParticle sharedInstance].stateMachine;
if (stateMachine.attAuthorizationStatus.integerValue == MPATTAuthorizationStatusAuthorized) {
return [self defaultHostWithSubdomain:kMPURLHostIdentityTrackingSubdomain apiKey:stateMachine.apiKey enableDirectRouting:stateMachine.enableDirectRouting];
return [self defaultHostWithSubdomain:kMPURLHostIdentityTrackingSubdomain apiKey:stateMachine.apiKey];
} else {
return [self defaultHostWithSubdomain:kMPURLHostIdentitySubdomain apiKey:stateMachine.apiKey enableDirectRouting:stateMachine.enableDirectRouting];
return [self defaultHostWithSubdomain:kMPURLHostIdentitySubdomain apiKey:stateMachine.apiKey];
}
}

Expand Down
1 change: 0 additions & 1 deletion mParticle-Apple-SDK/Utils/MPResponseConfig.swift
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ internal import mParticle_Apple_SDK_Swift
stateMachine.configureDataBlocking(config[RemoteConfig.kMPRemoteConfigDataPlanningResults] as? [AnyHashable: Any])

stateMachine.allowASR = config[RemoteConfig.kMPRemoteConfigAllowASR] as? Bool ?? false
stateMachine.enableDirectRouting = config[RemoteConfig.kMPRemoteConfigDirectURLRouting] as? Bool ?? false
if let remoteConfigFlags = config[RemoteConfig.kMPRemoteConfigFlagsKey] as? [AnyHashable: Any] {
if let audienceAPIFlag = remoteConfigFlags[RemoteConfig.kMPRemoteConfigAudienceAPIKey] as? String {
stateMachine.enableAudienceAPI = audienceAPIFlag == "True"
Expand Down
Loading