Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
0df8b86
Added API - setThirdPartyAPIsTimeout, ODM and Apple attribution token…
NidhiDixit09 Aug 22, 2025
f4fc6fd
Added Unit tests
NidhiDixit09 Aug 23, 2025
6b77087
Added unit tests, code cleanup.
NidhiDixit09 Aug 25, 2025
6d05846
Updated platform version
NidhiDixit09 Aug 25, 2025
2e7c233
Update verify.yml
NidhiDixit09 Aug 25, 2025
5679df4
Update verify.yml
NidhiDixit09 Aug 25, 2025
dd71d49
Update Scanfile
NidhiDixit09 Aug 25, 2025
a0abe59
Update verify.yml
NidhiDixit09 Aug 25, 2025
bcedd58
Unit test fixes.
NidhiDixit09 Aug 25, 2025
ed494df
Reverted Deployment target.
NidhiDixit09 Aug 25, 2025
533e0c1
Reverted refactoring of class BNCODMInfoCollector class
NidhiDixit09 Aug 26, 2025
dcc5db1
Removed extra spaces.
NidhiDixit09 Aug 26, 2025
5026d2d
Reverted GHA changes
NidhiDixit09 Aug 26, 2025
67217f4
Reverted previous changes and refactored BNCODMInfoCollector class
NidhiDixit09 Aug 26, 2025
d07026a
Removed extra param from the comments.
NidhiDixit09 Aug 26, 2025
7de6ddd
Removed extra header file.
NidhiDixit09 Aug 26, 2025
e7b7733
Code cleanup and refactoring of appleAttributionToken function.
NidhiDixit09 Aug 27, 2025
2cd4f5c
Temp changes for Github Runner Bug.
NidhiDixit09 Aug 27, 2025
0655535
Temp change for ODM timeout test
NidhiDixit09 Aug 27, 2025
f27b347
Fixed Unit tests.
NidhiDixit09 Aug 27, 2025
6220b10
Replaced ODM framework binary with SPM
NidhiDixit09 Aug 27, 2025
0859ddf
testing - temp change.
NidhiDixit09 Aug 27, 2025
17ab689
Update project.pbxproj
NidhiDixit09 Aug 27, 2025
1397945
Integration Tests temp.
NidhiDixit09 Aug 27, 2025
0f8b453
Update project.pbxproj
NidhiDixit09 Aug 27, 2025
75e6ce4
Disabling ODM Integration Tests - Never Worked
NidhiDixit09 Aug 27, 2025
151a073
Update Branch-TestBed-CI.xctestplan
NidhiDixit09 Aug 27, 2025
766f9a7
Updated error message.
NidhiDixit09 Aug 27, 2025
6d02ced
Updated API name and moved loadDataFromThirdPartyAPIs call to dataFor…
NidhiDixit09 Aug 28, 2025
35482fc
Updated new API name in unit tests.
NidhiDixit09 Aug 28, 2025
4b413b2
synchronized fetchODMInfoFromDeviceWithInitDate function.
NidhiDixit09 Aug 29, 2025
0a705cc
Updated Variable Name.
NidhiDixit09 Aug 29, 2025
bd8cc80
Commit message 1
NidhiDixit09 Aug 29, 2025
6cabb14
Commit message 2
NidhiDixit09 Aug 29, 2025
a842bd5
Commit message 3
NidhiDixit09 Aug 29, 2025
d254527
Commit message 333
NidhiDixit09 Aug 29, 2025
fb5ee35
Reverted GHA updates.
NidhiDixit09 Aug 29, 2025
f0a1276
Merge branch 'master' into EMT-2370-setThirdPartyAPIsTimeout
NidhiDixit09 Aug 29, 2025
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
4 changes: 2 additions & 2 deletions Branch-TestBed/Branch-SDK-Tests/BNCAPIServerTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,7 @@ - (void)testSetSafeTrackServiceURLWithUserTrackingDomain {
XCTAssertEqualObjects(storedUrl, expectedUrl);

storedUrl = [[BNCServerAPI sharedInstance] validationServiceURL];
expectedUrl = @"https://links.toTestDomain.com/v1/app-link-settings";
expectedUrl = @"https://api3.branch.io/v1/app-link-settings";
XCTAssertEqualObjects(storedUrl, expectedUrl);

[BNCServerAPI sharedInstance].useTrackingDomain = NO;
Expand Down Expand Up @@ -501,7 +501,7 @@ - (void)testSetSafeTrackServiceURLWithOutUserTrackingDomain {
XCTAssertEqualObjects(storedUrl, expectedUrl);

storedUrl = [[BNCServerAPI sharedInstance] validationServiceURL];
expectedUrl = @"https://links.toTestDomain.com/v1/app-link-settings";
expectedUrl = @"https://api3.branch.io/v1/app-link-settings";
XCTAssertEqualObjects(storedUrl, expectedUrl);

[BNCServerAPI sharedInstance].useTrackingDomain = NO;
Expand Down
16 changes: 9 additions & 7 deletions Branch-TestBed/Branch-SDK-Tests/BNCODMTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ - (void)testSetODMandSDKRequests {
}

- (void)testODMTimeOut {

NSString* requestUUID = [[NSUUID UUID ] UUIDString];
NSNumber* requestCreationTimeStamp = BNCWireFormatFromDate([NSDate date]);
NSString *odm = @"testODMString";
Expand All @@ -80,21 +80,23 @@ - (void)testODMTimeOut {

sleep(10);

NSDictionary *jsonOpen = [factory dataForOpenWithURLString:@"https://branch.io"];
BNCRequestFactory *factory2 = [[BNCRequestFactory alloc] initWithBranchKey:@"key_abcd" UUID:requestUUID TimeStamp:requestCreationTimeStamp];
NSDictionary *jsonOpen = [factory2 dataForOpenWithURLString:@"https://branch.io"];
XCTAssertTrue(![odm isEqualToString:[jsonOpen objectForKey:@"odm_info"]]);

self.prefHelper.odmInfo = nil;
self.prefHelper.odmInfoInitDate = nil;

}


- (void) testODMAPIsNotLoaded {

XCTestExpectation *expectation = [self expectationWithDescription:@"Check if ODCManager class is loaded."];
[[BNCODMInfoCollector instance ] loadODMInfoWithTimeOut:DISPATCH_TIME_FOREVER andCompletionHandler:^(NSString * _Nullable odmInfo, NSError * _Nullable error) {
if (error.code == BNCClassNotFoundError){
[expectation fulfill];
}
[[BNCODMInfoCollector instance ] loadODMInfoWithCompletionHandler:^(NSString * _Nullable odmInfo, NSError * _Nullable error) {
if (error.code == BNCClassNotFoundError){
[expectation fulfill];
}
}];
[self waitForExpectationsWithTimeout:15 handler:nil];
}
Expand Down
23 changes: 23 additions & 0 deletions Branch-TestBed/Branch-SDK-Tests/BNCPreferenceHelperTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -414,4 +414,27 @@ - (void)testSaveContentAnalyticsManifest {
XCTAssertEqualObjects(retrievedManifest, dummyManifest);
}

- (void)testThirdPartyAPIsTimeoutDefaultValue {
XCTAssertEqual(self.prefHelper.thirdPartyAPIsTimeout, 0.5,
@"Default third party APIs timeout should be 0.5 seconds");
}

- (void)testThirdPartyAPIsTimeoutSetterGetter {
NSTimeInterval testTimeout1 = 1.0;
self.prefHelper.thirdPartyAPIsTimeout = testTimeout1;
XCTAssertEqual(self.prefHelper.thirdPartyAPIsTimeout, testTimeout1,
@"Third party APIs timeout should be settable and retrievable");

NSTimeInterval testTimeout2 = 2.5;
self.prefHelper.thirdPartyAPIsTimeout = testTimeout2;
XCTAssertEqual(self.prefHelper.thirdPartyAPIsTimeout, testTimeout2,
@"Third party APIs timeout should be updatable");

NSTimeInterval testTimeout3 = 0.1;
self.prefHelper.thirdPartyAPIsTimeout = testTimeout3;
XCTAssertEqual(self.prefHelper.thirdPartyAPIsTimeout, testTimeout3,
@"Third party APIs timeout should support small values");
}


@end
99 changes: 99 additions & 0 deletions Branch-TestBed/Branch-SDK-Tests/BranchClassTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@ - (void)writeObjectToDefaults:(NSString *)key value:(NSObject *)value;

@interface BranchClassTests : XCTestCase
@property (nonatomic, strong) Branch *branch;
@property (nonatomic, strong, readwrite) BNCPreferenceHelper *prefHelper;
@end

@implementation BranchClassTests

- (void)setUp {
[super setUp];
self.branch = [Branch getInstance];
self.prefHelper = [BNCPreferenceHelper sharedInstance];
}

- (void)tearDown {
Expand Down Expand Up @@ -261,5 +263,102 @@ - (void)testSetConsumerProtectionAttributionLevel {

}

- (void)testBranchSetThirdPartyAPIsTimeout {
// Test Branch instance method for setting timeout
NSTimeInterval testTimeout = 2.0;
[Branch setThirdPartyAPIsTimeout:testTimeout];

// Verify it was set in the preference helper
XCTAssertEqual(self.prefHelper.thirdPartyAPIsTimeout, testTimeout,
@"Branch setThirdPartyAPIsTimeout should update preference helper");
}

- (void)testBranchSetThirdPartyAPIsTimeoutMultipleValues {
// Test setting multiple different values
NSArray *testValues = @[@0.5, @1.0, @1.5, @3.0, @5.0];

for (NSNumber *timeoutValue in testValues) {
NSTimeInterval timeout = [timeoutValue doubleValue];
[Branch setThirdPartyAPIsTimeout:timeout];

XCTAssertEqual(self.prefHelper.thirdPartyAPIsTimeout, timeout,
@"Branch setThirdPartyAPIsTimeout should handle value %.1f", timeout);
}
}

- (void)testTimeoutIntegrationWithPreferenceHelper {
// Test that Branch and PreferenceHelper work together correctly
NSTimeInterval branchTimeout = 1.8;
NSTimeInterval directTimeout = 2.3;

// Set via Branch
[Branch setThirdPartyAPIsTimeout:branchTimeout];
XCTAssertEqual(self.prefHelper.thirdPartyAPIsTimeout, branchTimeout,
@"Timeout set via Branch should be readable from PreferenceHelper");

// Set directly on PreferenceHelper
self.prefHelper.thirdPartyAPIsTimeout = directTimeout;
XCTAssertEqual(self.prefHelper.thirdPartyAPIsTimeout, directTimeout,
@"Timeout set directly should be readable via Branch");
}

- (void)testTimeoutValueConsistency {
// Test that the same instance maintains consistent values
NSTimeInterval testTimeout = 1.25;

[Branch setThirdPartyAPIsTimeout:testTimeout];

// Read multiple times to ensure consistency
for (int i = 0; i < 5; i++) {
XCTAssertEqual(self.prefHelper.thirdPartyAPIsTimeout, testTimeout,
@"Timeout value should remain consistent across multiple reads");
}
}

- (void)testBranchSetThirdPartyAPIsTimeoutInvalidLowValues {

NSArray *invalidLowValues = @[@0.0, @-1.0, @-0.5];
NSTimeInterval originalTimeout = [BNCPreferenceHelper sharedInstance].thirdPartyAPIsTimeout;

for (NSNumber *timeoutValue in invalidLowValues) {
NSTimeInterval timeout = [timeoutValue doubleValue];
[Branch setThirdPartyAPIsTimeout:timeout];
XCTAssertEqual([BNCPreferenceHelper sharedInstance].thirdPartyAPIsTimeout, originalTimeout,
@"Branch setThirdPartyAPIsTimeout should reject invalid low value %.3f", timeout);
}
}

- (void)testBranchSetThirdPartyAPIsTimeoutInvalidHighValues {

NSArray *invalidHighValues = @[@10.1, @15.0, @30.0, @60.0];
NSTimeInterval originalTimeout = [BNCPreferenceHelper sharedInstance].thirdPartyAPIsTimeout;

for (NSNumber *timeoutValue in invalidHighValues) {
NSTimeInterval timeout = [timeoutValue doubleValue];
[Branch setThirdPartyAPIsTimeout:timeout];
XCTAssertEqual([BNCPreferenceHelper sharedInstance].thirdPartyAPIsTimeout, originalTimeout,
@"Branch setThirdPartyAPIsTimeout should reject invalid high value %.3f", timeout);
}
}

- (void)testBranchSetThirdPartyAPIsTimeoutBoundaryValues {
// Test exact boundary values
NSTimeInterval originalTimeout = [BNCPreferenceHelper sharedInstance].thirdPartyAPIsTimeout;

// Test exactly 10.0 (should be valid)
[Branch setThirdPartyAPIsTimeout:10.0];
XCTAssertEqual([BNCPreferenceHelper sharedInstance].thirdPartyAPIsTimeout, 10.0,
@"Timeout of exactly 10.0 seconds should be valid");

// Test just over 10.0 (should be invalid)
[Branch setThirdPartyAPIsTimeout:10.0001];
XCTAssertEqual([BNCPreferenceHelper sharedInstance].thirdPartyAPIsTimeout, 10.0,
@"Timeout of 10.0001 seconds should be rejected");

// Test very small positive value (should be valid)
[Branch setThirdPartyAPIsTimeout:0.0001];
XCTAssertEqual([BNCPreferenceHelper sharedInstance].thirdPartyAPIsTimeout, 0.0001,
@"Very small positive timeout should be valid");
}

@end
7 changes: 4 additions & 3 deletions Branch-TestBed/Reflection_ODM_Tests/Reflection_ODM_Tests.m
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,12 @@ - (void) testODMAPIsLoaded {

}


- (void) testODMAPICall {

XCTestExpectation *expectation = [self expectationWithDescription:@"Network call"];
[BNCPreferenceHelper sharedInstance].odmInfo = nil;
[[BNCODMInfoCollector instance ] loadODMInfoWithTimeOut:15 andCompletionHandler:^(NSString * _Nullable odmInfo, NSError * _Nullable error) {
[[BNCODMInfoCollector instance ] loadODMInfoWithCompletionHandler:^(NSString * _Nullable odmInfo, NSError * _Nullable error) {
if ((error.code != BNCClassNotFoundError) && (error.code != BNCMethodNotFoundError)){
if (odmInfo) {
XCTAssertTrue([odmInfo isEqualToString:[BNCPreferenceHelper sharedInstance].odmInfo]);
Expand All @@ -46,7 +47,7 @@ - (void) testODMAPICall {
[expectation fulfill];
}
}];
[self waitForExpectationsWithTimeout:30 handler:nil];
[self waitForExpectationsWithTimeout:10 handler:nil];
}

@end
59 changes: 15 additions & 44 deletions Sources/BranchSDK/BNCODMInfoCollector.m
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ @interface BNCODMInfoCollector()

@implementation BNCODMInfoCollector

@synthesize odmInfo = _odmInfo;

+ (BNCODMInfoCollector *)instance {
static BNCODMInfoCollector *collector = nil;
static dispatch_once_t onceToken = 0;
Expand All @@ -41,61 +39,37 @@ - (instancetype)init {
return self;
}

- (void) setOdmInfo:(NSString *)odmInfo {
_odmInfo = odmInfo;
}

- (NSString *) odmInfo {
@synchronized (self) {
// Load ODM info with a time-out of 500 ms. Its must for next call to v1/open.
if (!_odmInfo) {
[self loadODMInfoWithTimeOut:dispatch_time(DISPATCH_TIME_NOW, (int64_t)(500 * NSEC_PER_MSEC)) andCompletionHandler:nil]; // Timeout after 500 ms
}

if (_odmInfo) {
// Check if odmInfo is within validity window
NSDate *initTime = self.preferenceHelper.odmInfoInitDate;
NSTimeInterval validityWindow = self.preferenceHelper.odmInfoValidityWindow;
if ([self isWithinValidityWindow:initTime timeInterval:validityWindow]) {
// fetch ODM info from pref helper
_odmInfo = self.preferenceHelper.odmInfo;
} else {
_odmInfo = nil;
}
}
return _odmInfo;
}
}

- (void)loadODMInfo {
[self loadODMInfoWithTimeOut: DISPATCH_TIME_FOREVER andCompletionHandler:nil];
}

- (void)loadODMInfoWithTimeOut:(dispatch_time_t) timeOut andCompletionHandler:(void (^_Nullable)(NSString * _Nullable odmInfo, NSError * _Nullable error))completion {
- (void)loadODMInfoWithCompletionHandler:(void (^_Nullable)(NSString * _Nullable odmInfo, NSError * _Nullable error))completion {

if (self.preferenceHelper.odmInfo) {
self.odmInfo = self.preferenceHelper.odmInfo;
NSString *odmInfoValidated = self.preferenceHelper.odmInfo;
if (odmInfoValidated) {
// Check if odmInfo is within validity window
NSDate *initTime = self.preferenceHelper.odmInfoInitDate;
NSTimeInterval validityWindow = self.preferenceHelper.odmInfoValidityWindow;
if ([self isWithinValidityWindow:initTime timeInterval:validityWindow]) {
// fetch ODM info from pref helper
odmInfoValidated = self.preferenceHelper.odmInfo;
} else {
odmInfoValidated = nil;
}
if (completion) {
completion(_odmInfo, nil);
completion(odmInfoValidated, nil);
}
} else {
// Fetch ODM Info from device
NSDate * odmInfofetchingTime = [NSDate date];
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

[self fetchODMInfoFromDeviceWithInitDate:odmInfofetchingTime andCompletion:^(NSString *odmInfo, NSError *error) {
if (odmInfo) {
self.odmInfo = odmInfo;
// Cache ODM info in pref helper
self.preferenceHelper.odmInfo = odmInfo;
self.preferenceHelper.odmInfoInitDate = odmInfofetchingTime;
}
if (completion) {
completion(odmInfo, error);
}
dispatch_semaphore_signal(semaphore);

}];
dispatch_semaphore_wait(semaphore, timeOut);
}
}

Expand Down Expand Up @@ -155,12 +129,9 @@ typedef NS_ENUM(NSInteger, ODCInteractionType) {
}

__strong typeof(self) self = weakSelf;
if (info) {
self->_odmInfo = info; // Save new value even if its new.
}

if (completion) {
completion( self->_odmInfo, error);
completion( info, error);
}
[[BranchLogger shared] logVerbose:[NSString stringWithFormat:@"Received Info: %@", info] error:nil];
};
Expand Down
20 changes: 20 additions & 0 deletions Sources/BranchSDK/BNCPreferenceHelper.m
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#import "BNCSKAdNetwork.h"

static const NSTimeInterval DEFAULT_TIMEOUT = 5.5;
static const NSTimeInterval DEFAULT_THIRD_PARTY_APIS_TIMEOUT = 0.5; // 500ms default
static const NSTimeInterval DEFAULT_RETRY_INTERVAL = 0;
static const NSInteger DEFAULT_RETRY_COUNT = 3;
static const NSTimeInterval DEFAULT_REFERRER_GBRAID_WINDOW = 2592000; // 30 days = 2,592,000 seconds
Expand Down Expand Up @@ -57,6 +58,7 @@
static NSString * const BRANCH_PREFS_KEY_FIRST_APP_LAUNCH_TIME = @"bnc_first_app_launch_time";
static NSString * const BRANCH_PREFS_KEY_SKAN_HIGHEST_CONV_VALUE_SENT = @"bnc_skan_send_highest_conv_value";
static NSString * const BRANCH_PREFS_KEY_SKAN_INVOKE_REGISTER_APP = @"bnc_invoke_register_app";
static NSString * const BRANCH_PREFS_KEY_THIRD_PARTY_APIS_TIMEOUT = @"bnc_third_party_apis_timeout";

static NSString * const BRANCH_PREFS_KEY_USE_EU_SERVERS = @"bnc_use_EU_servers";

Expand Down Expand Up @@ -114,6 +116,7 @@ @implementation BNCPreferenceHelper
retryCount = _retryCount,
retryInterval = _retryInterval,
timeout = _timeout,
thirdPartyAPIsTimeout = _thirdPartyAPIsTimeout,
lastStrongMatchDate = _lastStrongMatchDate,
requestMetadataDictionary = _requestMetadataDictionary,
instrumentationDictionary = _instrumentationDictionary,
Expand Down Expand Up @@ -156,6 +159,7 @@ - (instancetype)init {
_retryCount = DEFAULT_RETRY_COUNT;
_retryInterval = DEFAULT_RETRY_INTERVAL;
_odmInfoValidityWindow = DEFAULT_ODM_INFO_VALIDITY_WINDOW;
_thirdPartyAPIsTimeout = DEFAULT_THIRD_PARTY_APIS_TIMEOUT;
_isDebug = NO;
_persistPrefsQueue = [[NSOperationQueue alloc] init];
_persistPrefsQueue.maxConcurrentOperationCount = 1;
Expand Down Expand Up @@ -759,6 +763,22 @@ - (void) setOdmInfoInitDate:(NSDate *)initDate {
}
}

- (NSTimeInterval) thirdPartyAPIsTimeout {
@synchronized (self) {
_thirdPartyAPIsTimeout = [self readDoubleFromDefaults:BRANCH_PREFS_KEY_THIRD_PARTY_APIS_TIMEOUT];
if (_thirdPartyAPIsTimeout == NSNotFound) {
_thirdPartyAPIsTimeout = DEFAULT_THIRD_PARTY_APIS_TIMEOUT;
}
return _thirdPartyAPIsTimeout;
}
}

- (void) setThirdPartyAPIsTimeout:(NSTimeInterval)timeOut {
@synchronized (self) {
[self writeObjectToDefaults:BRANCH_PREFS_KEY_THIRD_PARTY_APIS_TIMEOUT value:@(timeOut)];
}
}

- (NSInteger) skanCurrentWindow {
@synchronized (self) {
_skanCurrentWindow = [self readIntegerFromDefaults:BRANCH_PREFS_KEY_SKAN_CURRENT_WINDOW];
Expand Down
Loading
Loading