diff --git a/Branch-TestBed/Branch-SDK-Tests/BNCApplication+BNCTest.h b/Branch-TestBed/Branch-SDK-Tests/BNCApplication+BNCTest.h deleted file mode 100644 index 0c50af6d4..000000000 --- a/Branch-TestBed/Branch-SDK-Tests/BNCApplication+BNCTest.h +++ /dev/null @@ -1,20 +0,0 @@ -/** - @file BNCApplication+BNCTest.h - @package Branch-SDK-Tests - @brief Expose BNCApplication interfaces for testing. - - @author Edward Smith - @date May 4, 2018 - @copyright Copyright © 2018 Branch. All rights reserved. -*/ - -#import -#import "BNCApplication.h" - -@interface BNCApplication (BNCTest) - -- (void) setAppOriginalInstallDate:(NSDate*)originalInstallDate - firstInstallDate:(NSDate*)firstInstallDate - lastUpdateDate:(NSDate*)lastUpdateDate; - -@end diff --git a/Branch-TestBed/Branch-SDK-Tests/BNCApplication+BNCTest.m b/Branch-TestBed/Branch-SDK-Tests/BNCApplication+BNCTest.m deleted file mode 100644 index 72de10fde..000000000 --- a/Branch-TestBed/Branch-SDK-Tests/BNCApplication+BNCTest.m +++ /dev/null @@ -1,11 +0,0 @@ -/** - @file BNCApplication+BNCTest.m - @package Branch-SDK-Tests - @brief Expose BNCApplication interfaces for testing. - - @author Edward Smith - @date May 4, 2018 - @copyright Copyright © 2018 Branch. All rights reserved. -*/ - -#import "BNCApplication+BNCTest.h" diff --git a/Branch-TestBed/Branch-SDK-Tests/BNCServerInterface.Test.m b/Branch-TestBed/Branch-SDK-Tests/BNCServerInterface.Test.m deleted file mode 100644 index 944a792f1..000000000 --- a/Branch-TestBed/Branch-SDK-Tests/BNCServerInterface.Test.m +++ /dev/null @@ -1,380 +0,0 @@ -// -// BNCServerInterface.Test.m -// Branch -// -// Created by Graham Mueller on 3/31/15. -// Copyright (c) 2015 Branch Metrics. All rights reserved. -// - -#import -#import "BNCTestCase.h" -#import "BNCServerInterface.h" -#import "BNCPreferenceHelper.h" -#import "BranchConstants.h" -//#import -//#import -//#import - -//typedef void (^UrlConnectionCallback)(NSURLResponse *, NSData *, NSError *); -// -//@interface BNCServerInterface() -// -//// private BNCServerInterface method/properties to prepare dictionary for requests -//@property (copy, nonatomic) NSString *requestEndpoint; -//- (NSMutableDictionary *)prepareParamDict:(NSDictionary *)params -// key:(NSString *)key -// retryNumber:(NSInteger)retryNumber -// requestType:(NSString *)reqType; -//@end -// -// -// -//@interface BNCServerInterfaceTests : BNCTestCase -//@end -// -//@implementation BNCServerInterfaceTests -// -//#pragma mark - Tear Down -// -//- (void)tearDown { -// [HTTPStubs removeAllStubs]; -// [super tearDown]; -//} -// -// -//#pragma mark - Key tests -// -////================================================================================== -//// TEST 01 -//// This test checks to see that the branch key has been added to the GET request -// -//- (void)testParamAddForBranchKey { -// [HTTPStubs removeAllStubs]; -// BNCServerInterface *serverInterface = [[BNCServerInterface alloc] init]; -// XCTestExpectation* expectation = -// [self expectationWithDescription:@"NSURLSessionDataTask completed"]; -// -// __block int callCount = 0; -// [HTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest *request) { -// // We're not sending a request, just verifying a "branch_key=key_xxx" is present. -// callCount++; -// NSLog(@"\n\nCall count %d.\nRequest: %@\n", callCount, request); -// if (callCount == 1) { -// BOOL foundIt = ([request.URL.query rangeOfString:@"branch_key=key_"].location != NSNotFound); -// XCTAssertTrue(foundIt, @"Branch Key not added"); -// BNCAfterSecondsPerformBlockOnMainThread(0.01, ^{ [expectation fulfill]; }); -// return YES; -// } -// return NO; -// } -// withStubResponse:^HTTPStubsResponse *(NSURLRequest *request) { -// NSDictionary* dummyJSONResponse = @{@"key": @"value"}; -// return [HTTPStubsResponse responseWithJSONObject:dummyJSONResponse statusCode:200 headers:nil]; -// } -// ]; -// -// [serverInterface getRequest:nil url:@"http://foo" key:@"key_live_foo" callback:NULL]; -// [self waitForExpectationsWithTimeout:5.0 handler:nil]; -// [HTTPStubs removeAllStubs]; -//} -// -//#pragma mark - Retry tests -// -////================================================================================== -//// TEST 03 -//// This test simulates a poor network, with three failed GET attempts and one final success, -//// for 4 connections. -// -////- (void)testGetRequestAsyncRetriesWhenAppropriate { -//// [HTTPStubs removeAllStubs]; -//// -//// //Set up nsurlsession and data task, catching response -//// BNCServerInterface *serverInterface = [[BNCServerInterface alloc] init]; -//// serverInterface.preferenceHelper = [[BNCPreferenceHelper alloc] init]; -//// serverInterface.preferenceHelper.retryCount = 3; -//// -//// XCTestExpectation* successExpectation = [self expectationWithDescription:@"success"]; -//// -//// __block NSInteger connectionAttempts = 0; -//// __block NSInteger failedConnections = 0; -//// __block NSInteger successfulConnections = 0; -//// -//// [HTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest *request) { -//// BOOL foundBranchKey = [request.URL.query rangeOfString:@"branch_key=key_"].location != NSNotFound; -//// XCTAssertEqual(foundBranchKey, TRUE); -//// return foundBranchKey; -//// -//// } withStubResponse:^HTTPStubsResponse*(NSURLRequest *request) { -//// @synchronized (self) { -//// connectionAttempts++; -//// NSLog(@"Attempt # %lu", (unsigned long)connectionAttempts); -//// if (connectionAttempts < 3) { -//// -//// // Return an error the first three times -//// NSDictionary* dummyJSONResponse = @{@"bad": @"data"}; -//// -//// ++failedConnections; -//// return [HTTPStubsResponse responseWithJSONObject:dummyJSONResponse statusCode:504 headers:nil]; -//// -//// } else if (connectionAttempts == 3) { -//// -//// // Return actual data afterwards -//// ++successfulConnections; -//// XCTAssertEqual(connectionAttempts, failedConnections + successfulConnections); -//// BNCAfterSecondsPerformBlockOnMainThread(0.01, ^{ -//// NSLog(@"==> Fullfill."); -//// [successExpectation fulfill]; -//// }); -//// -//// NSDictionary* dummyJSONResponse = @{@"key": @"value"}; -//// return [HTTPStubsResponse responseWithJSONObject:dummyJSONResponse statusCode:200 headers:nil]; -//// -//// } else { -//// -//// XCTFail(@"Too many connection attempts: %ld.", (long) connectionAttempts); -//// return [HTTPStubsResponse responseWithJSONObject:[NSDictionary new] statusCode:200 headers:nil]; -//// -//// } -//// } -//// }]; -//// -//// [serverInterface getRequest:nil url:@"http://foo" key:@"key_live_foo" callback:NULL]; -//// [self waitForExpectationsWithTimeout:10.0 handler:nil]; -////} -// -////================================================================================== -//// TEST 04 -//// This test checks to make sure that GET retries are not attempted when they have a retry -//// count > 0, but retries aren't needed. Based on Test #3 above. -// -//- (void)testGetRequestAsyncRetriesWhenInappropriateResponse { -// [HTTPStubs removeAllStubs]; -// -// BNCServerInterface *serverInterface = [[BNCServerInterface alloc] init]; -// serverInterface.preferenceHelper = [[BNCPreferenceHelper alloc] init]; -// serverInterface.preferenceHelper.retryCount = 3; -// -// XCTestExpectation* successExpectation = [self expectationWithDescription:@"success"]; -// -// __block NSUInteger connectionAttempts = 0; -// -// [HTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest *request) { -// BOOL foundBranchKey = [request.URL.query rangeOfString:@"branch_key=key_"].location != NSNotFound; -// XCTAssertEqual(foundBranchKey, TRUE); -// return foundBranchKey; -// -// } withStubResponse:^HTTPStubsResponse*(NSURLRequest *request) { -// @synchronized (self) { -// // Return actual data on first attempt -// NSDictionary* dummyJSONResponse = @{@"key": @"value"}; -// connectionAttempts++; -// XCTAssertEqual(connectionAttempts, 1); -// BNCAfterSecondsPerformBlockOnMainThread(0.01, ^ { -// [successExpectation fulfill]; -// }); -// return [HTTPStubsResponse responseWithJSONObject:dummyJSONResponse statusCode:200 headers:nil]; -// } -// }]; -// -// [serverInterface getRequest:nil url:@"http://foo" key:@"key_live_foo" callback:NULL]; -// [self waitForExpectationsWithTimeout:2.0 handler:nil]; -//} -// -////================================================================================== -//// TEST 05 -//// This test checks to make sure that GET retries are not attempted when they have a retry -//// count == 0, but retries aren't needed. Based on Test #4 above -// -//- (void)testGetRequestAsyncRetriesWhenInappropriateRetryCount { -// [HTTPStubs removeAllStubs]; -// -// BNCServerInterface *serverInterface = [[BNCServerInterface alloc] init]; -// serverInterface.preferenceHelper = [[BNCPreferenceHelper alloc] init]; -// serverInterface.preferenceHelper.retryCount = 0; -// -// XCTestExpectation* successExpectation = [self expectationWithDescription:@"success"]; -// -// __block NSUInteger connectionAttempts = 0; -// -// [HTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest *request) { -// BOOL foundBranchKey = [request.URL.query rangeOfString:@"branch_key=key_"].location != NSNotFound; -// XCTAssertEqual(foundBranchKey, TRUE); -// return foundBranchKey; -// -// } withStubResponse:^HTTPStubsResponse*(NSURLRequest *request) { -// @synchronized (self) { -// // Return actual data on first attempt -// NSDictionary* dummyJSONResponse = @{@"key": @"value"}; -// connectionAttempts++; -// XCTAssertEqual(connectionAttempts, 1); -// BNCAfterSecondsPerformBlockOnMainThread(0.01, ^{ -// [successExpectation fulfill]; -// }); -// return [HTTPStubsResponse responseWithJSONObject:dummyJSONResponse statusCode:200 headers:nil]; -// } -// }]; -// -// [serverInterface getRequest:nil url:@"http://foo" key:@"key_live_foo" callback:NULL]; -// [self waitForExpectationsWithTimeout:2.0 handler:nil]; -//} -// -////================================================================================== -//// TEST 06 -//// This test simulates a poor network, with three failed GET attempts and one final success, -//// for 4 connections. Based on Test #3 above -// -//- (void)testPostRequestAsyncRetriesWhenAppropriate { -// [HTTPStubs removeAllStubs]; -// -// //Set up nsurlsession and data task, catching response -// BNCServerInterface *serverInterface = [[BNCServerInterface alloc] init]; -// serverInterface.preferenceHelper = [[BNCPreferenceHelper alloc] init]; -// serverInterface.preferenceHelper.retryCount = 3; -// [serverInterface.preferenceHelper synchronize]; -// -// XCTestExpectation* successExpectation = [self expectationWithDescription:@"success"]; -// -// __block NSUInteger connectionAttempts = 0; -// __block NSUInteger failedConnections = 0; -// __block NSUInteger successfulConnections = 0; -// -// [HTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest *request) { -// BOOL foundBranchKey = [request.URL.query rangeOfString:@"branch_key=key_"].location != NSNotFound; -// XCTAssertEqual(foundBranchKey, TRUE); -// return foundBranchKey; -// -// } withStubResponse:^HTTPStubsResponse*(NSURLRequest *request) { -// connectionAttempts++; -// NSLog(@"attempt # %lu", (unsigned long)connectionAttempts); -// if (connectionAttempts < 3) { -// // Return an error the first three times -// NSDictionary* dummyJSONResponse = @{@"bad": @"data"}; -// -// ++failedConnections; -// return [HTTPStubsResponse responseWithJSONObject:dummyJSONResponse statusCode:504 headers:nil]; -// -// } else if (connectionAttempts == 3) { -// -// // Return actual data afterwards -// ++successfulConnections; -// NSDictionary* dummyJSONResponse = @{@"key": @"value"}; -// XCTAssertEqual(connectionAttempts, failedConnections + successfulConnections); -// BNCAfterSecondsPerformBlockOnMainThread(0.01, ^ { -// NSLog(@"==>> Fullfill <<=="); -// [successExpectation fulfill]; -// }); -// return [HTTPStubsResponse responseWithJSONObject:dummyJSONResponse statusCode:200 headers:nil]; -// -// } else { -// -// XCTFail(@"Too many connection attempts: %ld.", (long) connectionAttempts); -// return [HTTPStubsResponse responseWithJSONObject:[NSDictionary new] statusCode:200 headers:nil]; -// -// } -// }]; -// -// [serverInterface postRequest:nil url:@"http://foo" key:@"key_live_foo" callback:NULL]; -// [self waitForExpectationsWithTimeout:5.0 handler:nil]; -//} -// -////================================================================================== -//// TEST 07 -//// This test checks to make sure that POST retries are not attempted when they have a retry -//// count == 0, and retries aren't needed. Based on Test #4 above -// -//- (void)testPostRequestAsyncRetriesWhenInappropriateResponse { -// [HTTPStubs removeAllStubs]; -// -// BNCServerInterface *serverInterface = [[BNCServerInterface alloc] init]; -// serverInterface.preferenceHelper = [[BNCPreferenceHelper alloc] init]; -// serverInterface.preferenceHelper.retryCount = 3; -// -// XCTestExpectation* successExpectation = [self expectationWithDescription:@"success"]; -// -// __block NSUInteger connectionAttempts = 0; -// -// [HTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest *request) { -// BOOL foundBranchKey = [request.URL.query rangeOfString:@"branch_key=key_"].location != NSNotFound; -// XCTAssertEqual(foundBranchKey, TRUE); -// return foundBranchKey; -// -// } withStubResponse:^HTTPStubsResponse*(NSURLRequest *request) { -// // Return actual data on first attempt -// NSDictionary* dummyJSONResponse = @{@"key": @"value"}; -// connectionAttempts++; -// XCTAssertEqual(connectionAttempts, 1); -// BNCAfterSecondsPerformBlockOnMainThread(0.01, ^{ [successExpectation fulfill]; }); -// return [HTTPStubsResponse responseWithJSONObject:dummyJSONResponse statusCode:200 headers:nil]; -// -// }]; -// -// [serverInterface postRequest:nil url:@"http://foo" key:@"key_live_foo" callback:NULL]; -// [self waitForExpectationsWithTimeout:1.0 handler:nil]; -// -//} -// -////================================================================================== -//// TEST 08 -//// This test checks to make sure that GET retries are not attempted when they have a retry -//// count == 0, and retries aren't needed. Based on Test #4 above -// -//- (void)testPostRequestAsyncRetriesWhenInappropriateRetryCount { -// [HTTPStubs removeAllStubs]; -// -// BNCServerInterface *serverInterface = [[BNCServerInterface alloc] init]; -// serverInterface.preferenceHelper = [[BNCPreferenceHelper alloc] init]; -// serverInterface.preferenceHelper.retryCount = 0; -// -// XCTestExpectation* successExpectation = [self expectationWithDescription:@"success"]; -// -// __block NSUInteger connectionAttempts = 0; -// -// [HTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest *request) { -// BOOL foundBranchKey = [request.URL.query rangeOfString:@"branch_key=key_"].location != NSNotFound; -// XCTAssertEqual(foundBranchKey, TRUE); -// return foundBranchKey; -// -// } withStubResponse:^HTTPStubsResponse*(NSURLRequest *request) { -// // Return actual data on first attempt -// NSDictionary* dummyJSONResponse = @{@"key": @"value"}; -// connectionAttempts++; -// XCTAssertEqual(connectionAttempts, 1); -// BNCAfterSecondsPerformBlockOnMainThread(0.01, ^{ [successExpectation fulfill]; }); -// return [HTTPStubsResponse responseWithJSONObject:dummyJSONResponse statusCode:200 headers:nil]; -// }]; -// -// [serverInterface getRequest:nil url:@"http://foo" key:@"key_live_foo" callback:NULL]; -// [self waitForExpectationsWithTimeout:1.0 handler:nil]; -//} -// -////================================================================================== -//// TEST 10 -//// Test mapping of X-Branch-Request-Id to [BNCServerResponse requestId] -// -//- (void)testRequestIdFromHeader { -// [HTTPStubs removeAllStubs]; -// -// BNCServerInterface *serverInterface = [[BNCServerInterface alloc] init]; -// NSString *requestId = @"1325e434fa294d3bb7d461349118602d-2020102721"; -// -// XCTestExpectation* successExpectation = [self expectationWithDescription:@"success"]; -// -// [HTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest *request) { -// // Return the following response for any request -// return YES; -// } withStubResponse:^HTTPStubsResponse *(NSURLRequest *request) { -// // Stub out a response with a X-Branch-Request-Id header -// return [HTTPStubsResponse responseWithJSONObject:@{} statusCode:200 headers:@{@"X-Branch-Request-Id": requestId}]; -// }]; -// -// // POST to trigger the stubbed response. -// [serverInterface postRequest:@{} url:@"https://api.branch.io/v1/open" key:@"key_live_xxxx" callback:^(BNCServerResponse *response, NSError *error) { -// // Verify the request ID value on the BNCServerResponse -// BNCAfterSecondsPerformBlockOnMainThread(0.01, ^{ [successExpectation fulfill]; }); -// XCTAssertEqualObjects(response.requestId, requestId); -// }]; -// -// [self waitForExpectationsWithTimeout:5.0 handler:nil]; -//} -// -//@end diff --git a/Branch-TestBed/Branch-SDK-Tests/BNCServerRequestQueueOldTests.m b/Branch-TestBed/Branch-SDK-Tests/BNCServerRequestQueueOldTests.m deleted file mode 100644 index 43343671d..000000000 --- a/Branch-TestBed/Branch-SDK-Tests/BNCServerRequestQueueOldTests.m +++ /dev/null @@ -1,124 +0,0 @@ -// -// BNCServerRequestQueueTests.m -// Branch-TestBed -// -// Created by Graham Mueller on 6/17/15. -// Copyright (c) 2015 Branch Metrics. All rights reserved. -// - -#import "BNCTestCase.h" -#import "BNCServerRequestQueue.h" -#import "BranchOpenRequest.h" -#import "Branch.h" - -//#import -// -//@interface BNCServerRequestQueue (BNCTests) -//- (void)retrieve; -//- (void)cancelTimer; -//@end -// -//@interface BNCServerRequestQueueOldTests : BNCTestCase -//@end -// -//@implementation BNCServerRequestQueueOldTests -// -//#pragma mark - MoveOpenOrInstallToFront tests -// -//+ (void) setUp { -// [self clearAllBranchSettings]; // Clear any saved data before our tests start. -//// Branch*branch = [Branch getInstance:@"key_live_foo"]; -//// [self clearAllBranchSettings]; -//} -// -//- (void)testMoveOpenOrInstallToFrontWhenEmpty { -// BNCServerRequestQueue *requestQueue = [[BNCServerRequestQueue alloc] init]; -// XCTAssertNoThrow([requestQueue moveInstallOrOpenToFront:0]); -//} -// -//- (void)testMoveOpenOrInstallToFrontWhenNotPresent { -// BNCServerRequestQueue *requestQueue = [[BNCServerRequestQueue alloc] init]; -// [requestQueue insert:[[BNCServerRequest alloc] init] at:0]; -// [requestQueue insert:[[BNCServerRequest alloc] init] at:0]; -// XCTAssertNoThrow([requestQueue moveInstallOrOpenToFront:0]); -//} -// -//- (void)testMoveOpenOrInstallToFrontWhenAlreadyInFrontAndNoRequestsInProgress { -// BNCServerRequestQueue *requestQueue = [[BNCServerRequestQueue alloc] init]; -// [requestQueue insert:[[BranchOpenRequest alloc] init] at:0]; -// -// id requestQueueMock = OCMPartialMock(requestQueue); -// [[requestQueueMock reject] removeAt:0]; -// -// [requestQueue moveInstallOrOpenToFront:0]; -//} -// -//- (void)testMoveOpenOrInstallToFrontWhenAlreadyInFrontWithRequestsInProgress { -// BNCServerRequestQueue *requestQueue = [[BNCServerRequestQueue alloc] init]; -// [requestQueue insert:[[BranchOpenRequest alloc] init] at:0]; -// -// id requestQueueMock = OCMPartialMock(requestQueue); -// [[requestQueueMock reject] removeAt:0]; -// -// [requestQueue moveInstallOrOpenToFront:1]; -//} -// -//- (void)testMoveOpenOrInstallToFrontWhenSecondInLineWithRequestsInProgress { -// BNCServerRequestQueue *requestQueue = [[BNCServerRequestQueue alloc] init]; -// [requestQueue insert:[[BNCServerRequest alloc] init] at:0]; -// [requestQueue insert:[[BranchOpenRequest alloc] init] at:1]; -// -// id requestQueueMock = OCMPartialMock(requestQueue); -// [[requestQueueMock reject] removeAt:1]; -// -// [requestQueue moveInstallOrOpenToFront:1]; -//} -// -//- (void)testMoveOpenOrInstallToFrontWhenSecondInLineWithNoRequestsInProgress { -// BNCServerRequestQueue *requestQueue = [[BNCServerRequestQueue alloc] init]; -// BranchOpenRequest *openRequest = [[BranchOpenRequest alloc] init]; -// [requestQueue insert:[[BNCServerRequest alloc] init] at:0]; -// [requestQueue insert:openRequest at:1]; -// -// id requestQueueMock = OCMPartialMock(requestQueue); -// [[[requestQueueMock expect] andForwardToRealObject] removeAt:1]; -// -// [requestQueue moveInstallOrOpenToFront:0]; -// XCTAssertEqual([requestQueue peek], openRequest); -// -// [requestQueueMock verify]; -//} -// -//- (void)testMoveOpenOrInstallToFrontWhenThirdInLineWithRequestsInProgress { -// BNCServerRequestQueue *requestQueue = [[BNCServerRequestQueue alloc] init]; -// BranchOpenRequest *openRequest = [[BranchOpenRequest alloc] init]; -// [requestQueue insert:[[BNCServerRequest alloc] init] at:0]; -// [requestQueue insert:[[BNCServerRequest alloc] init] at:1]; -// [requestQueue insert:openRequest at:2]; -// -// id requestQueueMock = OCMPartialMock(requestQueue); -// [[[requestQueueMock expect] andForwardToRealObject] removeAt:2]; -// -// [requestQueue moveInstallOrOpenToFront:1]; -// XCTAssertEqual([requestQueue peekAt:1], openRequest); -// -// [requestQueueMock verify]; -//} -// -//- (void)testMoveOpenOrInstallToFrontWhenThirdInLineWithNoRequestsInProgress { -// BNCServerRequestQueue *requestQueue = [[BNCServerRequestQueue alloc] init]; -// BranchOpenRequest *openRequest = [[BranchOpenRequest alloc] init]; -// [requestQueue insert:[[BNCServerRequest alloc] init] at:0]; -// [requestQueue insert:[[BNCServerRequest alloc] init] at:1]; -// [requestQueue insert:openRequest at:2]; -// -// id requestQueueMock = OCMPartialMock(requestQueue); -// [[[requestQueueMock expect] andForwardToRealObject] removeAt:2]; -// -// [requestQueue moveInstallOrOpenToFront:0]; -// XCTAssertEqual([requestQueue peek], openRequest); -// -// [requestQueueMock verify]; -//} -// -//@end diff --git a/Branch-TestBed/Branch-SDK-Tests/BNCTestCase.Test.m b/Branch-TestBed/Branch-SDK-Tests/BNCTestCase.Test.m deleted file mode 100644 index 2bf549088..000000000 --- a/Branch-TestBed/Branch-SDK-Tests/BNCTestCase.Test.m +++ /dev/null @@ -1,31 +0,0 @@ -/** - @file BNCTestCase.Test.m - @package Branch-SDK - @brief Test cases for the underlying Branch test class. - - @author Edward Smith - @date April 2018 - @copyright Copyright © 2018 Branch. All rights reserved. -*/ - -#import "BNCTestCase.h" - -@interface BNCTestCaseTest : BNCTestCase -@end - -@implementation BNCTestCaseTest - -- (void) testFailure { - // Un-comment the next line to test a failure case: - // XCTAssert(NO, @"Testing a test failure!"); - XCTAssertTrue(YES, @"Test passes!"); - NSString * bundleID = [NSBundle mainBundle].bundleIdentifier; - NSLog(@"The test bundleID is '%@'.", bundleID); -} - -- (void) testLoadString { - NSString *string = [self stringFromBundleWithKey:@"BNCTestCaseString"]; - XCTAssertEqualObjects(string, @"Test success!"); -} - -@end diff --git a/Branch-TestBed/Branch-SDK-Tests/BNCTestCase.h b/Branch-TestBed/Branch-SDK-Tests/BNCTestCase.h deleted file mode 100644 index de4afe482..000000000 --- a/Branch-TestBed/Branch-SDK-Tests/BNCTestCase.h +++ /dev/null @@ -1,40 +0,0 @@ -/** - @file BNCTestCase.h - @package Branch-SDK-Tests - @brief The Branch testing framework super class. - - @author Edward Smith - @date April 2017 - @copyright Copyright © 2017 Branch. All rights reserved. -*/ - -#import -#import "NSString+Branch.h" - -#define BNCTAssertEqualMaskedString(string, mask) { \ - if ((id)string != nil && (id)mask != nil && [string bnc_isEqualToMaskedString:mask]) { \ - } else { \ - XCTAssertEqualObjects(string, mask); \ - } \ -} - -extern BOOL BNCTestStringMatchesRegex(NSString *string, NSString *regex); - -#define XCTAssertStringMatchesRegex(string, regex) \ - XCTAssertTrue(BNCTestStringMatchesRegex(string, regex)) - -@interface BNCTestCase : XCTestCase - -- (void)safelyFulfillExpectation:(XCTestExpectation *)expectation; -- (void)awaitExpectations; -- (void)resetExpectations; -- (double) systemVersion; - -// Load Resources from the test bundle: - -- (NSString*)stringFromBundleWithKey:(NSString*)key; -- (NSMutableDictionary*) mutableDictionaryFromBundleJSONWithKey:(NSString*)key; - -+ (void) clearAllBranchSettings; -+ (BOOL) isApplication; -@end diff --git a/Branch-TestBed/Branch-SDK-Tests/BNCTestCase.m b/Branch-TestBed/Branch-SDK-Tests/BNCTestCase.m deleted file mode 100644 index 2afa92010..000000000 --- a/Branch-TestBed/Branch-SDK-Tests/BNCTestCase.m +++ /dev/null @@ -1,115 +0,0 @@ -/** - @file BNCTestCase.m - @package Branch-SDK-Tests - @brief The Branch testing framework super class. - - @author Edward Smith - @date April 2017 - @copyright Copyright © 2017 Branch. All rights reserved. -*/ - -#import "BNCTestCase.h" -#import "Branch.h" -#import "BNCApplication+BNCTest.h" - -#import "BNCUserAgentCollector.h" - -@interface Branch (BNCTest) -+ (void) clearAll; -@end - -NSString* kTestStringResourceName = @"BNCTestCase"; // File is 'BNCTestCase.strings'. Omit the '.string'. - -#pragma mark - BNCTestStringMatchesRegex - -BOOL BNCTestStringMatchesRegex(NSString *string, NSString *regex) { - NSError *error = nil; - NSRegularExpression* nsregex = - [NSRegularExpression regularExpressionWithPattern:regex options:0 error:&error]; - if (error) { - NSLog(@"Error in regex pattern: %@.", error); - return NO; - } - NSRange stringRange = NSMakeRange(0, string.length); - NSTextCheckingResult *match = [nsregex firstMatchInString:string options:0 range:stringRange]; - return NSEqualRanges(match.range, stringRange); -} - -#pragma mark - BNCTestCase - -@interface BNCTestCase () -@property (assign, nonatomic) BOOL hasExceededExpectations; -@end - -@implementation BNCTestCase - -- (void)setUp { - [super setUp]; - [self resetExpectations]; -} - -- (void)resetExpectations { - self.hasExceededExpectations = NO; -} - -- (void)safelyFulfillExpectation:(XCTestExpectation *)expectation { - if (!self.hasExceededExpectations) { - [expectation fulfill]; - } -} - -- (void)awaitExpectations { - [self waitForExpectationsWithTimeout:5 handler:^(NSError *error) { - self.hasExceededExpectations = YES; - }]; -} - -- (NSString*) stringFromBundleWithKey:(NSString*)key { - NSString *const kItemNotFound = @""; - NSString *resource = - [[NSBundle bundleForClass:self.class] - localizedStringForKey:key value:kItemNotFound table:kTestStringResourceName]; - if ([resource isEqualToString:kItemNotFound]) resource = nil; - return resource; -} - -- (NSMutableDictionary*) mutableDictionaryFromBundleJSONWithKey:(NSString*)key { - NSString *jsonString = [self stringFromBundleWithKey:key]; - XCTAssertTrue(jsonString, @"Can't load '%@' resource from bundle JSON!", key); - - NSError *error = nil; - NSDictionary *dictionary = - [NSJSONSerialization JSONObjectWithData:[jsonString dataUsingEncoding:NSUTF8StringEncoding] - options:0 error:&error]; - XCTAssertNil(error); - XCTAssert(dictionary); - NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionaryWithDictionary:dictionary]; - return mutableDictionary; -} - -- (double) systemVersion { - return [UIDevice currentDevice].systemVersion.floatValue; -} - -static NSString* savedRandomizedBundleToken = nil; - -+ (void) initialize { - if (self != [BNCTestCase self]) return; - - savedRandomizedBundleToken = [BNCPreferenceHelper sharedInstance].randomizedBundleToken; - [Branch clearAll]; -} - -+ (void)tearDown { - [BNCPreferenceHelper sharedInstance].randomizedBundleToken = savedRandomizedBundleToken; -} - -+ (void) clearAllBranchSettings { - [Branch clearAll]; -} - -+ (BOOL) isApplication { - return [BNCApplication currentApplication].bundleID.length > 0; -} - -@end diff --git a/Branch-TestBed/Branch-SDK-Tests/BNCTestCase.strings b/Branch-TestBed/Branch-SDK-Tests/BNCTestCase.strings deleted file mode 100644 index 43dc2f622..000000000 --- a/Branch-TestBed/Branch-SDK-Tests/BNCTestCase.strings +++ /dev/null @@ -1,255 +0,0 @@ -/** - @file BNCTestCase.strings - @package Branch-SDK-Tests - @brief String resources for Branch-SDK-Tests. - - @author Edward Smith - @date October 2016 - @copyright Copyright © 2016 Branch. All rights reserved. -*/ - -"BNCTestCaseString" = "Test success!"; - -"DumpClassTest" = -" -Class 0x11a380018 is class 'DumpClass' of class 'NSObject': - Ivar 'stringVar' type 'NSString'. - Ivar 'intVar' type 'int'. - Ivar 'charPtrVar' type 'char*'. - Ivar 'classVar' type 'class'. - Ivar 'floatVar' type 'float'. - Ivar 'doubleVar' type 'double'. - Ivar 'shortVar' type 'short'. - Ivar 'boolVar' type 'BOOL'. - Ivar 'ucharVar' type 'unsigned char'. - Ivar 'uintVar' type 'unsigned int'. - Ivar 'ushortVar' type 'unsigned short'. - Ivar 'ulongVar' type 'unsigned long'. - Ivar 'doubleTroubleVar' type 'long double'. - Ivar 'UnhandledType' type '{UnhandledStruct=\"int1\"i\"int2\"i}' (un-handled type). - Ivar '_intProp' type 'int'. - Ivar '_stringProp' type 'NSString'. - Property name: 'intProp'. - Property name: 'stringProp'. - Class method name: 'classMethod'. - Method name: '.cxx_destruct'. - Method name: 'dealloc'. - Method name: 'init'. - Method name: 'setIntProp:'. - Method name: 'setStringProp:'. - Method name: 'methodThatTakesAnNSString:'. - Method name: 'intProp'. - Method name: 'stringProp'. -"; - -"DumpInstanceTest" = -" -Instance 0x132585f70 is of class 'DumpClass' of class 'NSObject': - Ivar 'stringVar' type '__NSCFConstantString' value 'Yope!'. - Ivar 'intVar' type 'int' value '1'. - Ivar 'charPtrVar' type 'char*' value 'YopeCharString'. - Ivar 'classVar' type 'class' value 'NSNumber'. - Ivar 'floatVar' type 'float' value '2.000000'. - Ivar 'doubleVar' type 'double' value '3.000000'. - Ivar 'shortVar' type 'short' value '4'. - Ivar 'boolVar' type 'BOOL' value 'NO'. - Ivar 'ucharVar' type 'unsigned char' value ''. - Ivar 'uintVar' type 'unsigned int' value '0'. - Ivar 'ushortVar' type 'unsigned short' value '0'. - Ivar 'ulongVar' type 'unsigned long' value '0'. - Ivar 'doubleTroubleVar' type 'long double' value '0.000000'. - Ivar 'UnhandledType' type '{UnhandledStruct=\"int1\"i\"int2\"i}' (un-handled type). - Ivar '_intProp' type 'int' value '5'. - Ivar '_stringProp' type '__NSCFConstantString' value 'Props!'. - Property name: 'intProp'. - Property name: 'stringProp'. - Class method name: 'classMethod'. - Method name: '.cxx_destruct'. - Method name: 'dealloc'. - Method name: 'init'. - Method name: 'setIntProp:'. - Method name: 'setStringProp:'. - Method name: 'methodThatTakesAnNSString:'. - Method name: 'intProp'. - Method name: 'stringProp'. -"; - -"BranchUniversalObjectJSON" = -" -{ - \"$content_schema\": \"COMMERCE_PRODUCT\", - \"$quantity\": 2, - \"$price\": 23.2, - \"$currency\": \"USD\", - \"$sku\": \"1994320302\", - \"$product_name\": \"my_product_name1\", - \"$product_brand\": \"my_prod_Brand1\", - \"$product_category\": \"Baby & Toddler\", - \"$product_variant\": \"3T\", - \"$rating_average\": 5, - \"$rating_count\": 5, - \"$rating_max\": 7, - \"$rating\": 6, - \"$condition\": \"FAIR\", - \"$address_street\": \"Street_name1\", - \"$address_city\": \"city1\", - \"$address_region\": \"Region1\", - \"$address_country\": \"Country1\", - \"$address_postal_code\": \"postal_code\", - \"$latitude\": 12.07, - \"$longitude\": -97.5, - \"$image_captions\": [\"my_img_caption1\", \"my_img_caption_2\"], - \"$og_title\": \"My Content Title\", - \"$canonical_identifier\": \"item\/12345\", - \"$canonical_url\": \"https:\/\/branch.io\/deepviews\", - \"$keywords\": [\"My_Keyword1\", \"My_Keyword2\"], - \"$og_description\": \"my_product_description1\", - \"$og_image_url\": \"https:\/\/test_img_url\", - \"$exp_date\": 212123232544, - \"$publicly_indexable\": false, - \"$locally_indexable\": true, - \"$creation_timestamp\": 1501869445321, - \"Custom_Content_metadata_key1\": \"Custom_Content_metadata_val1\", - \"Custom_Content_metadata_key2\": \"Custom_Content_metadata_val2\" -} -"; -"V2EventProperties" = -" -{ - \"affiliation\": \"test_affiliation\", - \"coupon\": \"test_coupon\", - \"currency\": \"USD\", - \"description\": \"Event _description\", - \"shipping\": 10.2, - \"tax\": 12.3, - \"revenue\": 1.5, - \"search_query\": \"Query\", - \"transaction_id\": \"12344555\", - \"custom_data\": { - \"Custom_Event_Property_Key1\": \"Custom_Event_Property_val1\", - \"Custom_Event_Property_Key2\": \"Custom_Event_Property_val2\" - } -} -"; -"V2EventJSON" = -" -{ - \"name\": \"PURCHASE\", - \"metadata\" : { - \"skan_time_window\": \"5184000.000000\" - }, - \"custom_data\": { - \"Custom_Event_Property_Key1\": \"Custom_Event_Property_val1\", - \"Custom_Event_Property_Key2\": \"Custom_Event_Property_val2\" - }, - \"customer_event_alias\": \"event alias\", - \"event_data\": { - \"affiliation\": \"test_affiliation\", - \"coupon\": \"test_coupon\", - \"currency\": \"USD\", - \"description\": \"Event _description\", - \"shipping\": 10.2, - \"tax\": 12.3, - \"revenue\": 1.5, - \"transaction_id\": \"12344555\", - \"search_query\": \"Query\" - }, - \"content_items\": [{ - \"$content_schema\": \"COMMERCE_PRODUCT\", - \"$quantity\": 2, - \"$price\": 23.2, - \"$currency\": \"USD\", - \"$condition\": \"FAIR\", - \"$sku\": \"1994320302\", - \"$product_name\": \"my_product_name1\", - \"$product_brand\": \"my_prod_Brand1\", - \"$product_category\": \"Baby & Toddler\", - \"$product_variant\": \"3T\", - \"$rating_average\": 5, - \"$rating_count\": 5, - \"$rating_max\": 7, - \"$rating\": 6, - \"$address_street\": \"Street_name1\", - \"$address_city\": \"city1\", - \"$address_region\": \"Region1\", - \"$address_country\": \"Country1\", - \"$address_postal_code\": \"postal_code\", - \"$latitude\": 12.07, - \"$longitude\": -97.5, - \"$image_captions\": [\"my_img_caption1\", \"my_img_caption_2\"], - \"Custom_Content_metadata_key1\": \"Custom_Content_metadata_val1\", - \"Custom_Content_metadata_key2\": \"Custom_Content_metadata_val2\", - \"$og_title\": \"My Content Title\", - \"$canonical_identifier\": \"item\/12345\", - \"$canonical_url\": \"https:\/\/branch.io\/deepviews\", - \"$keywords\": [\"My_Keyword1\", \"My_Keyword2\"], - \"$og_description\": \"my_product_description1\", - \"$og_image_url\": \"https:\/\/test_img_url\", - \"$exp_date\": 212123232544, - \"$locally_indexable\": true, - \"$creation_timestamp\": 1501869445321 - }], - \"user_data\": { - \"os\": \"iOS\", - \"os_version\": 25, - \"environment\": \"FULL_APP\", - \"idfa\": \"\", - \"idfv\": \"\", - \"user_agent\": \"\", - \"developer_identity\": \"edsojan\", - \"country\": \"US\", - \"language\": \"en\", - \"brand\": \"Apple\", - \"randomized_device_token\": \"\", - \"sdk\": \"ios0.17.10\", - \"app_version\": \"whatever\", - \"model\": \"x86_64\", - \"screen_dpi\": 3, - \"screen_height\": 2208, - \"screen_width\": 1242 - }, - \"branch_key\": \"key_live_foo\", - \"retryNumber\": 0 -} -"; -"BUODescription" = -""; -"BNCDeviceDictionaryV2" = -"{ - \"os\": \"iOS\", - \"os_version\": 25, - \"environment\": \"FULL_APP\", - \"idfa\": \"\", - \"idfv\": \"\", - \"user_agent\": \"\", - \"developer_identity\": \"edsojan\", - \"country\": \"US\", - \"language\": \"en\", - \"brand\": \"Apple\", - \"randomized_device_token\": \"\", - \"sdk\": \"ios\", - \"sdk_version\": \"0.17.10\", - \"app_version\": \"whatever\", - \"model\": \"x86_64\", - \"screen_dpi\": 3, - \"screen_height\": 2208, - \"screen_width\": 1242 -}"; - diff --git a/Branch-TestBed/Branch-SDK-Tests/Branch-SDK-Tests-Bridging-Header.h b/Branch-TestBed/Branch-SDK-Tests/Branch-SDK-Tests-Bridging-Header.h index 1e7530a59..169bd50f3 100644 --- a/Branch-TestBed/Branch-SDK-Tests/Branch-SDK-Tests-Bridging-Header.h +++ b/Branch-TestBed/Branch-SDK-Tests/Branch-SDK-Tests-Bridging-Header.h @@ -2,5 +2,4 @@ // Module headers for Branch SDK unit testing. // -#import "BNCTestCase.h" #import "Branch.h" diff --git a/Branch-TestBed/Branch-SDK-Tests/BranchInstallRequestTests.m b/Branch-TestBed/Branch-SDK-Tests/BranchInstallRequestTests.m deleted file mode 100644 index b46ffefae..000000000 --- a/Branch-TestBed/Branch-SDK-Tests/BranchInstallRequestTests.m +++ /dev/null @@ -1,318 +0,0 @@ -// -// BranchInstallRequestTests.m -// Branch-TestBed -// -// Created by Graham Mueller on 6/24/15. -// Copyright (c) 2015 Branch Metrics. All rights reserved. -// - -#import "BNCTestCase.h" -#import "Branch.h" -#import "BNCApplication.h" -#import "BNCApplication+BNCTest.h" -#import "BranchInstallRequest.h" -#import "BNCPreferenceHelper.h" -#import "BNCSystemObserver.h" -#import "BranchConstants.h" -#import "BNCEncodingUtils.h" -//#import -// -//@interface BranchInstallRequestTests : BNCTestCase -//@end -// -//@implementation BranchInstallRequestTests -// -//- (void)setUp { -// [super setUp]; -// BNCPreferenceHelper *preferenceHelper = [BNCPreferenceHelper sharedInstance]; -// preferenceHelper.installParams = nil; -// preferenceHelper.randomizedBundleToken = nil; -// [preferenceHelper saveContentAnalyticsManifest:nil]; -// [preferenceHelper synchronize]; -//} -// -//- (void)testSuccessWithAllKeysAndIsReferrable { -// NSString * const DEVICE_TOKEN = @"foo-token"; -// NSString * const USER_URL = @"http://foo"; -// NSString * const DEVELOPER_ID = @"foo"; -// NSString * const SESSION_ID = @"foo-session"; -// NSString * const SESSION_PARAMS = @"{\"+clicked_branch_link\":1,\"foo\":\"bar\"}"; -// NSString * const RANDOMIZED_BUNDLE_TOKEN = @"randomized_bundle_token"; -// -// BNCServerResponse *response = [[BNCServerResponse alloc] init]; -// response.data = @{ -// BRANCH_RESPONSE_KEY_RANDOMIZED_DEVICE_TOKEN: DEVICE_TOKEN, -// BRANCH_RESPONSE_KEY_USER_URL: USER_URL, -// BRANCH_RESPONSE_KEY_DEVELOPER_IDENTITY: DEVELOPER_ID, -// BRANCH_RESPONSE_KEY_SESSION_ID: SESSION_ID, -// BRANCH_RESPONSE_KEY_SESSION_DATA: SESSION_PARAMS, -// BRANCH_RESPONSE_KEY_RANDOMIZED_BUNDLE_TOKEN: RANDOMIZED_BUNDLE_TOKEN -// }; -// -// XCTestExpectation *openExpectation = [self expectationWithDescription:@"OpenRequest Expectation"]; -// BranchInstallRequest *request = [[BranchInstallRequest alloc] initWithCallback:^(BOOL success, NSError *error) { -// XCTAssertNil(error); -// XCTAssertTrue(success); -// [self safelyFulfillExpectation:openExpectation]; -// }]; -// -// [Branch setBranchKey:@"key_live_foo"]; -// [request processResponse:response error:nil]; -// [self awaitExpectations]; -// -// BNCPreferenceHelper *preferenceHelper = [BNCPreferenceHelper sharedInstance]; -// XCTAssertEqualObjects(preferenceHelper.randomizedDeviceToken, DEVICE_TOKEN); -// XCTAssertEqualObjects(preferenceHelper.userUrl, USER_URL); -// XCTAssertEqualObjects(preferenceHelper.userIdentity, DEVELOPER_ID); -// XCTAssertEqualObjects(preferenceHelper.sessionID, SESSION_ID); -// XCTAssertEqualObjects(preferenceHelper.sessionParams, SESSION_PARAMS); -// XCTAssertEqualObjects(preferenceHelper.installParams, SESSION_PARAMS); -// XCTAssertEqualObjects(preferenceHelper.randomizedBundleToken, RANDOMIZED_BUNDLE_TOKEN); -// XCTAssertNil(preferenceHelper.linkClickIdentifier); -//} -// -//- (void)testSuccessWithAllKeysAndIsNotReferrable { -// NSString * const DEVICE_TOKEN = @"foo-token"; -// NSString * const USER_URL = @"http://foo"; -// NSString * const DEVELOPER_ID = @"foo"; -// NSString * const SESSION_ID = @"foo-session"; -// NSString * const SESSION_PARAMS = @"{\"foo\":\"bar\"}"; -// NSString * const INSTALL_PARAMS = @"{\"bar\":\"foo\"}"; -// NSString * const RANDOMIZED_BUNDLE_TOKEN = @"randomized_bundle_token"; -// -// BNCServerResponse *response = [[BNCServerResponse alloc] init]; -// response.data = @{ -// BRANCH_RESPONSE_KEY_RANDOMIZED_DEVICE_TOKEN: DEVICE_TOKEN, -// BRANCH_RESPONSE_KEY_USER_URL: USER_URL, -// BRANCH_RESPONSE_KEY_DEVELOPER_IDENTITY: DEVELOPER_ID, -// BRANCH_RESPONSE_KEY_SESSION_ID: SESSION_ID, -// BRANCH_RESPONSE_KEY_SESSION_DATA: SESSION_PARAMS, -// BRANCH_RESPONSE_KEY_RANDOMIZED_BUNDLE_TOKEN: RANDOMIZED_BUNDLE_TOKEN -// }; -// -// BNCPreferenceHelper *preferenceHelper = [BNCPreferenceHelper sharedInstance]; -// preferenceHelper.installParams = INSTALL_PARAMS; -// -// XCTestExpectation *openExpectation = [self expectationWithDescription:@"OpenRequest Expectation"]; -// BranchInstallRequest *request = [[BranchInstallRequest alloc] initWithCallback:^(BOOL success, NSError *error) { -// XCTAssertNil(error); -// XCTAssertTrue(success); -// [self safelyFulfillExpectation:openExpectation]; -// }]; -// -// [Branch setBranchKey:@"key_live_foo"]; -// [request processResponse:response error:nil]; -// -// [self awaitExpectations]; -// -// XCTAssertEqualObjects(preferenceHelper.randomizedDeviceToken, DEVICE_TOKEN); -// XCTAssertEqualObjects(preferenceHelper.userUrl, USER_URL); -// XCTAssertEqualObjects(preferenceHelper.userIdentity, DEVELOPER_ID); -// XCTAssertEqualObjects(preferenceHelper.sessionID, SESSION_ID); -// XCTAssertEqualObjects(preferenceHelper.sessionParams, SESSION_PARAMS); -// XCTAssertEqualObjects(preferenceHelper.installParams, INSTALL_PARAMS); -// XCTAssertEqualObjects(preferenceHelper.randomizedBundleToken, RANDOMIZED_BUNDLE_TOKEN); -// XCTAssertNil(preferenceHelper.linkClickIdentifier); -//} -// -//- (void)testSuccessWithNoSessionParamsAndIsNotReferrable { -// NSString * const DEVICE_TOKEN = @"foo-token"; -// NSString * const USER_URL = @"http://foo"; -// NSString * const DEVELOPER_ID = @"foo"; -// NSString * const SESSION_ID = @"foo-session"; -// NSString * const INSTALL_PARAMS = @"{\"bar\":\"foo\"}"; -// NSString * const RANDOMIZED_BUNDLE_TOKEN = @"randomized_bundle_token"; -// -// BNCServerResponse *response = [[BNCServerResponse alloc] init]; -// response.data = @{ -// BRANCH_RESPONSE_KEY_RANDOMIZED_DEVICE_TOKEN: DEVICE_TOKEN, -// BRANCH_RESPONSE_KEY_USER_URL: USER_URL, -// BRANCH_RESPONSE_KEY_DEVELOPER_IDENTITY: DEVELOPER_ID, -// BRANCH_RESPONSE_KEY_SESSION_ID: SESSION_ID, -// BRANCH_RESPONSE_KEY_RANDOMIZED_BUNDLE_TOKEN: RANDOMIZED_BUNDLE_TOKEN -// }; -// -// BNCPreferenceHelper *preferenceHelper = [BNCPreferenceHelper sharedInstance]; -// preferenceHelper.installParams = INSTALL_PARAMS; -// -// XCTestExpectation *openExpectation = [self expectationWithDescription:@"OpenRequest Expectation"]; -// BranchInstallRequest *request = [[BranchInstallRequest alloc] initWithCallback:^(BOOL success, NSError *error) { -// XCTAssertNil(error); -// XCTAssertTrue(success); -// [self safelyFulfillExpectation:openExpectation]; -// }]; -// -// [Branch setBranchKey:@"key_live_foo"]; -// [request processResponse:response error:nil]; -// [self awaitExpectations]; -// -// XCTAssertEqualObjects(preferenceHelper.randomizedDeviceToken, DEVICE_TOKEN); -// XCTAssertEqualObjects(preferenceHelper.userUrl, USER_URL); -// XCTAssertEqualObjects(preferenceHelper.userIdentity, DEVELOPER_ID); -// XCTAssertEqualObjects(preferenceHelper.sessionID, SESSION_ID); -// XCTAssertEqualObjects(preferenceHelper.installParams, INSTALL_PARAMS); -// XCTAssertEqualObjects(preferenceHelper.randomizedBundleToken, RANDOMIZED_BUNDLE_TOKEN); -// XCTAssertNil(preferenceHelper.sessionParams); -// XCTAssertNil(preferenceHelper.linkClickIdentifier); -//} -// -//- (void)testSuccessWithNoSessionParamsAndIsReferrableAndAllowToBeClearIsNotSet { -// NSString * const DEVICE_TOKEN = @"foo-token"; -// NSString * const USER_URL = @"http://foo"; -// NSString * const DEVELOPER_ID = @"foo"; -// NSString * const SESSION_ID = @"foo-session"; -// NSString * const INSTALL_PARAMS = @"{\"bar\":\"foo\"}"; -// NSString * const RANDOMIZED_BUNDLE_TOKEN = @"randomized_bundle_token"; -// -// BNCServerResponse *response = [[BNCServerResponse alloc] init]; -// response.data = @{ -// BRANCH_RESPONSE_KEY_RANDOMIZED_DEVICE_TOKEN: DEVICE_TOKEN, -// BRANCH_RESPONSE_KEY_USER_URL: USER_URL, -// BRANCH_RESPONSE_KEY_DEVELOPER_IDENTITY: DEVELOPER_ID, -// BRANCH_RESPONSE_KEY_SESSION_ID: SESSION_ID, -// BRANCH_RESPONSE_KEY_RANDOMIZED_BUNDLE_TOKEN: RANDOMIZED_BUNDLE_TOKEN -// }; -// -// BNCPreferenceHelper *preferenceHelper = [BNCPreferenceHelper sharedInstance]; -// preferenceHelper.installParams = INSTALL_PARAMS; -// -// XCTestExpectation *openExpectation = [self expectationWithDescription:@"OpenRequest Expectation"]; -// BranchOpenRequest *request = [[BranchOpenRequest alloc] initWithCallback:^(BOOL success, NSError *error) { -// XCTAssertNil(error); -// XCTAssertTrue(success); -// [self safelyFulfillExpectation:openExpectation]; -// }]; -// -// [Branch setBranchKey:@"key_live_foo"]; -// [request processResponse:response error:nil]; -// [self awaitExpectations]; -// -// XCTAssertEqualObjects(preferenceHelper.randomizedDeviceToken, DEVICE_TOKEN); -// XCTAssertEqualObjects(preferenceHelper.userUrl, USER_URL); -// XCTAssertEqualObjects(preferenceHelper.userIdentity, DEVELOPER_ID); -// XCTAssertEqualObjects(preferenceHelper.sessionID, SESSION_ID); -// XCTAssertEqualObjects(preferenceHelper.installParams, INSTALL_PARAMS); -// XCTAssertEqualObjects(preferenceHelper.randomizedBundleToken, RANDOMIZED_BUNDLE_TOKEN); -// XCTAssertNil(preferenceHelper.sessionParams); -// XCTAssertNil(preferenceHelper.linkClickIdentifier); -//} -// -//- (void)testSuccessWithNoSessionParamsAndIsReferrableAndAllowToBeClearIsSet { -// NSString * const DEVICE_TOKEN = @"foo-token"; -// NSString * const USER_URL = @"http://foo"; -// NSString * const DEVELOPER_ID = @"foo"; -// NSString * const SESSION_ID = @"foo-session"; -// NSString * const RANDOMIZED_BUNDLE_TOKEN = @"randomized_bundle_token"; -// -// BNCServerResponse *response = [[BNCServerResponse alloc] init]; -// response.data = @{ -// BRANCH_RESPONSE_KEY_RANDOMIZED_DEVICE_TOKEN: DEVICE_TOKEN, -// BRANCH_RESPONSE_KEY_USER_URL: USER_URL, -// BRANCH_RESPONSE_KEY_DEVELOPER_IDENTITY: DEVELOPER_ID, -// BRANCH_RESPONSE_KEY_SESSION_ID: SESSION_ID, -// BRANCH_RESPONSE_KEY_RANDOMIZED_BUNDLE_TOKEN: RANDOMIZED_BUNDLE_TOKEN -// }; -// -// XCTestExpectation *openExpectation = [self expectationWithDescription:@"OpenRequest Expectation"]; -// BranchInstallRequest *request = [[BranchInstallRequest alloc] initWithCallback:^(BOOL success, NSError *error) { -// XCTAssertNil(error); -// XCTAssertTrue(success); -// [self safelyFulfillExpectation:openExpectation]; -// } isInstall:YES]; -// -// [Branch setBranchKey:@"key_live_foo"]; -// [request processResponse:response error:nil]; -// [self awaitExpectations]; -// -// BNCPreferenceHelper *preferenceHelper = [BNCPreferenceHelper sharedInstance]; -// XCTAssertEqualObjects(preferenceHelper.randomizedDeviceToken, DEVICE_TOKEN); -// XCTAssertEqualObjects(preferenceHelper.userUrl, USER_URL); -// XCTAssertEqualObjects(preferenceHelper.userIdentity, DEVELOPER_ID); -// XCTAssertEqualObjects(preferenceHelper.sessionID, SESSION_ID); -// XCTAssertEqualObjects(preferenceHelper.randomizedBundleToken, RANDOMIZED_BUNDLE_TOKEN); -// XCTAssertNil(preferenceHelper.sessionParams); -// XCTAssertNil(preferenceHelper.linkClickIdentifier); -// XCTAssertNil(preferenceHelper.installParams); -//} -// -//- (void)testInstallWhenReferrableAndNullData { -// BNCPreferenceHelper *preferenceHelper = [BNCPreferenceHelper sharedInstance]; -// -// XCTestExpectation *expectation = [self expectationWithDescription:@"ReferrableInstall"]; -// BranchInstallRequest *request = [[BranchInstallRequest alloc] initWithCallback:^(BOOL changed, NSError *error) { -// XCTAssertNil(error); -// XCTAssertNil(preferenceHelper.installParams); -// [self safelyFulfillExpectation:expectation]; -// }]; -// -// [Branch setBranchKey:@"key_live_foo"]; -// BNCServerResponse *response = [[BNCServerResponse alloc] init]; -// response.data = @{}; -// [request processResponse:response error:nil]; -// [self awaitExpectations]; -//} -// -//- (void)testInstallWhenReferrableAndNonNullData { -// BNCPreferenceHelper *preferenceHelper = [BNCPreferenceHelper sharedInstance]; -// -// NSString * const INSTALL_PARAMS = @"{\"+clicked_branch_link\":1,\"foo\":\"bar\"}"; -// -// XCTestExpectation *expectation = [self expectationWithDescription:@"Request Expectation"]; -// BranchInstallRequest *request = [[BranchInstallRequest alloc] initWithCallback:^(BOOL changed, NSError *error) { -// XCTAssertNil(error); -// XCTAssertEqualObjects(preferenceHelper.installParams, INSTALL_PARAMS); -// -// [self safelyFulfillExpectation:expectation]; -// }]; -// -// [Branch setBranchKey:@"key_live_foo"]; -// BNCServerResponse *response = [[BNCServerResponse alloc] init]; -// response.data = @{ BRANCH_RESPONSE_KEY_SESSION_DATA: INSTALL_PARAMS }; -// [request processResponse:response error:nil]; -// [self awaitExpectations]; -//} -// -//- (void)testInstallWhenReferrableAndNoInstallParamsAndNonLinkClickData { -// BNCPreferenceHelper *preferenceHelper = [BNCPreferenceHelper sharedInstance]; -// -// NSString * const OPEN_PARAMS = @"{\"+clicked_branch_link\":0}"; -// -// XCTestExpectation *expectation = [self expectationWithDescription:@"Request Expectation"]; -// BranchInstallRequest *request = [[BranchInstallRequest alloc] initWithCallback:^(BOOL changed, NSError *error) { -// XCTAssertNil(error); -// XCTAssertNil(preferenceHelper.installParams); -// -// [self safelyFulfillExpectation:expectation]; -// }]; -// -// [Branch setBranchKey:@"key_live_foo"]; -// BNCServerResponse *response = [[BNCServerResponse alloc] init]; -// response.data = @{ BRANCH_RESPONSE_KEY_SESSION_DATA: OPEN_PARAMS }; -// [request processResponse:response error:nil]; -// [self awaitExpectations]; -//} -// -//- (void)testInstallWhenNotReferrable { -// // 'isReferrable' seems to be an empty concept in iOS. -// // It is in the code but not used. -- Edward. -// -// BNCPreferenceHelper *preferenceHelper = [BNCPreferenceHelper sharedInstance]; -// NSString * const INSTALL_PARAMS = @"{\"+clicked_branch_link\":1,\"foo\":\"bar\"}"; -// -// XCTestExpectation *expectation = [self expectationWithDescription:@"Request Expectation"]; -// BranchInstallRequest *request = -// [[BranchInstallRequest alloc] initWithCallback:^(BOOL changed, NSError *error) { -// XCTAssertNil(error); -// XCTAssert([preferenceHelper.installParams isEqualToString:INSTALL_PARAMS]); -// [self safelyFulfillExpectation:expectation]; -// }]; -// -// [Branch setBranchKey:@"key_live_foo"]; -// BNCServerResponse *response = [[BNCServerResponse alloc] init]; -// response.data = @{ BRANCH_RESPONSE_KEY_SESSION_DATA: INSTALL_PARAMS }; -// [request processResponse:response error:nil]; -// -// [self awaitExpectations]; -//} -// -//@end diff --git a/Branch-TestBed/Branch-SDK-Tests/BranchLoggerTests.m b/Branch-TestBed/Branch-SDK-Tests/BranchLoggerTests.m index 0a9539f61..1a4be3490 100644 --- a/Branch-TestBed/Branch-SDK-Tests/BranchLoggerTests.m +++ b/Branch-TestBed/Branch-SDK-Tests/BranchLoggerTests.m @@ -11,99 +11,251 @@ #import "Branch.h" @interface BranchLoggerTests : XCTestCase + @end @implementation BranchLoggerTests +// public API test - (void)testEnableLoggingSetsCorrectDefaultLevel { [[Branch getInstance] enableLogging]; XCTAssertEqual([BranchLogger shared].logLevelThreshold, BranchLogLevelDebug, "Default log level should be Debug."); } -- (void)testLogLevelThresholdBlocksLowerLevels { +- (void)testLoggingEnabled_NOByDefault { BranchLogger *logger = [BranchLogger new]; - logger.loggingEnabled = true; - logger.logLevelThreshold = BranchLogLevelDebug; - XCTestExpectation *expectation = [self expectationWithDescription:@"Log callback expectation for message that should pass the threshold"]; - + __block int count = 0; logger.logCallback = ^(NSString * _Nonnull message, BranchLogLevel logLevel, NSError * _Nullable error) { - if ([message isEqualToString:@"[BranchSDK][Debug][BranchLoggerTests testLogLevelThresholdBlocksLowerLevels] This message should trigger the log callback."] && logLevel >= BranchLogLevelDebug) { - [expectation fulfill]; - } else if (logLevel == BranchLogLevelVerbose) { - XCTFail(); - } + count = count + 1; }; + [logger logError:@"msg" error:nil]; - [logger logVerbose:@"This verbose message should not trigger the log callback."]; - [logger logDebug:@"This message should trigger the log callback."]; + XCTAssertTrue(count == 0); +} - [self waitForExpectationsWithTimeout:1 handler:nil]; +- (void)testLoggingEnabled_Yes { + BranchLogger *logger = [BranchLogger new]; + logger.loggingEnabled = YES; + + __block int count = 0; + logger.logCallback = ^(NSString * _Nonnull message, BranchLogLevel logLevel, NSError * _Nullable error) { + count = count + 1; + }; + + [logger logError:@"msg" error:nil]; + XCTAssertTrue(count == 1); + + [logger logError:@"msg" error:nil]; + XCTAssertTrue(count == 2); } -- (void)testLogCallbackExecutesWithCorrectParameters { - XCTestExpectation *expectation = [self expectationWithDescription:@"Log callback expectation"]; - NSString *expectedMessage = @"[BranchSDK][Info][BranchLoggerTests testLogCallbackExecutesWithCorrectParameters] Test message"; - BranchLogLevel expectedLevel = BranchLogLevelInfo; +- (void)testLoggingIgnoresNil { + BranchLogger *logger = [BranchLogger new]; + logger.loggingEnabled = YES; + + __block int count = 0; + logger.logCallback = ^(NSString * _Nonnull message, BranchLogLevel logLevel, NSError * _Nullable error) { + count = count + 1; + }; + + [logger logError:nil error:nil]; + XCTAssertTrue(count == 0); +} +- (void)testLoggingIgnoresEmptyString { BranchLogger *logger = [BranchLogger new]; + logger.loggingEnabled = YES; + + __block int count = 0; + logger.logCallback = ^(NSString * _Nonnull message, BranchLogLevel logLevel, NSError * _Nullable error) { + count = count + 1; + }; + + [logger logError:@"" error:nil]; + XCTAssertTrue(count == 0); +} +- (void)testLoggingEnabled_YesThenNo { + BranchLogger *logger = [BranchLogger new]; + logger.loggingEnabled = YES; + + __block int count = 0; logger.logCallback = ^(NSString * _Nonnull message, BranchLogLevel logLevel, NSError * _Nullable error) { - XCTAssertEqualObjects(message, expectedMessage, "Logged message does not match expected message."); - XCTAssertEqual(logLevel, expectedLevel, "Logged level does not match expected level."); - XCTAssertNil(error, "Error should be nil."); - [expectation fulfill]; + count = count + 1; }; + // one call + [logger logError:@"msg" error:nil]; + XCTAssertTrue(count == 1); + + // disable, second call is ignored + logger.loggingEnabled = NO; + [logger logError:@"msg" error:nil]; + XCTAssertTrue(count == 1); +} + +- (void)testLogLevel_DebugByDefault { + BranchLogger *logger = [BranchLogger new]; logger.loggingEnabled = YES; - logger.logLevelThreshold = BranchLogLevelInfo; - [logger logInfo:@"Test message"]; + + __block int count = 0; + logger.logCallback = ^(NSString * _Nonnull message, BranchLogLevel logLevel, NSError * _Nullable error) { + count = count + 1; + }; + + [logger logError:@"msg" error:nil]; + XCTAssertTrue(count == 1); + [logger logWarning:@"msg" error:nil]; + XCTAssertTrue(count == 2); + [logger logDebug:@"msg" error:nil]; + XCTAssertTrue(count == 3); + + // this should be ignored and the counter not incremented + [logger logVerbose:@"msg" error:nil]; + XCTAssertTrue(count == 3); +} - [self waitForExpectationsWithTimeout:1 handler:nil]; +- (void)testLogLevel_Error { + BranchLogger *logger = [BranchLogger new]; + logger.loggingEnabled = YES; + logger.logLevelThreshold = BranchLogLevelError; + + + __block int count = 0; + logger.logCallback = ^(NSString * _Nonnull message, BranchLogLevel logLevel, NSError * _Nullable error) { + count = count + 1; + }; + + [logger logError:@"msg" error:nil]; + XCTAssertTrue(count == 1); + + // these should be ignored and the counter not incremented + [logger logWarning:@"msg" error:nil]; + XCTAssertTrue(count == 1); + [logger logDebug:@"msg" error:nil]; + XCTAssertTrue(count == 1); + [logger logVerbose:@"msg" error:nil]; + XCTAssertTrue(count == 1); } -- (void)testLogLevelSpecificityFiltersLowerLevels { +- (void)testLogLevel_Warning { BranchLogger *logger = [BranchLogger new]; logger.loggingEnabled = YES; logger.logLevelThreshold = BranchLogLevelWarning; - XCTestExpectation *verboseExpectation = [self expectationWithDescription:@"Verbose log callback"]; - verboseExpectation.inverted = YES; - XCTestExpectation *errorExpectation = [self expectationWithDescription:@"Error log callback"]; - __block NSUInteger callbackCount = 0; + __block int count = 0; + logger.logCallback = ^(NSString * _Nonnull message, BranchLogLevel logLevel, NSError * _Nullable error) { + count = count + 1; + }; + + [logger logError:@"msg" error:nil]; + XCTAssertTrue(count == 1); + [logger logWarning:@"msg" error:nil]; + XCTAssertTrue(count == 2); + + // this should be ignored and the counter not incremented + [logger logDebug:@"msg" error:nil]; + XCTAssertTrue(count == 2); + [logger logVerbose:@"msg" error:nil]; + XCTAssertTrue(count == 2); +} + +- (void)testLogLevel_Verbose { + BranchLogger *logger = [BranchLogger new]; + logger.loggingEnabled = YES; + logger.logLevelThreshold = BranchLogLevelVerbose; + + + __block int count = 0; + logger.logCallback = ^(NSString * _Nonnull message, BranchLogLevel logLevel, NSError * _Nullable error) { + count = count + 1; + }; + + [logger logError:@"msg" error:nil]; + XCTAssertTrue(count == 1); + [logger logWarning:@"msg" error:nil]; + XCTAssertTrue(count == 2); + [logger logDebug:@"msg" error:nil]; + XCTAssertTrue(count == 3); + [logger logVerbose:@"msg" error:nil]; + XCTAssertTrue(count == 4); +} + +- (void)testLogFormat_Default { + BranchLogger *logger = [BranchLogger new]; + logger.loggingEnabled = YES; + logger.logCallback = ^(NSString * _Nonnull message, BranchLogLevel logLevel, NSError * _Nullable error) { - if (logLevel == BranchLogLevelVerbose) { - [verboseExpectation fulfill]; - } else if (logLevel == BranchLogLevelError) { - [errorExpectation fulfill]; - } - callbackCount++; + NSString *expectedMessage = @"[BranchLoggerTests testLogFormat_Default] msg"; + + XCTAssertTrue([expectedMessage isEqualToString:message]); + XCTAssertTrue(logLevel == BranchLogLevelError); + XCTAssertNil(error); }; - [logger logVerbose:@"This should not be logged due to log level threshold."]; - [logger logError:@"This should be logged" error:nil]; + [logger logError:@"msg" error:nil]; +} + +- (void)testLogFormat_NSError { + __block NSError *originalError = [NSError errorWithDomain:@"com.domain.test" code:200 userInfo:@{@"Error Message": @"Test Error"}]; + + BranchLogger *logger = [BranchLogger new]; + logger.loggingEnabled = YES; + + logger.logCallback = ^(NSString * _Nonnull message, BranchLogLevel logLevel, NSError * _Nullable error) { + NSString *expectedMessage = @"[BranchLoggerTests testLogFormat_NSError] msg"; + + XCTAssertTrue([expectedMessage isEqualToString:message]); + XCTAssertTrue(logLevel == BranchLogLevelError); + XCTAssertTrue(originalError == error); + }; - [self waitForExpectations:@[verboseExpectation, errorExpectation] timeout:2]; - XCTAssertEqual(callbackCount, 1, "Only one log callback should have been invoked."); + [logger logError:@"msg" error:originalError]; } -- (void)testErrorLoggingIncludesErrorDetails { +- (void)testLogFormat_includeCallerDetailsNO { BranchLogger *logger = [BranchLogger new]; logger.loggingEnabled = YES; + logger.includeCallerDetails = NO; + + logger.logCallback = ^(NSString * _Nonnull message, BranchLogLevel logLevel, NSError * _Nullable error) { + NSString *expectedMessage = @"msg"; + + XCTAssertTrue([expectedMessage isEqualToString:message]); + XCTAssertTrue(logLevel == BranchLogLevelError); + XCTAssertNil(error); + }; - XCTestExpectation *expectation = [self expectationWithDescription:@"Error log includes error details"]; + [logger logError:@"msg" error:nil]; +} + +- (void)testLogFormat_includeCallerDetailsNO_NSError { + __block NSError *originalError = [NSError errorWithDomain:@"com.domain.test" code:200 userInfo:@{@"Error Message": @"Test Error"}]; - NSError *testError = [NSError errorWithDomain:@"TestDomain" code:42 userInfo:@{NSLocalizedDescriptionKey: @"Test error description"}]; + BranchLogger *logger = [BranchLogger new]; + logger.loggingEnabled = YES; + logger.includeCallerDetails = NO; + logger.logCallback = ^(NSString * _Nonnull message, BranchLogLevel logLevel, NSError * _Nullable error) { - if ([message containsString:@"Test error description"] && error == testError) { - [expectation fulfill]; - } + NSString *expectedMessage = @"msg"; + + XCTAssertTrue([expectedMessage isEqualToString:message]); + XCTAssertTrue(logLevel == BranchLogLevelError); + XCTAssertTrue(originalError == error); }; - [logger logError:@"Testing error logging" error:testError]; + [logger logError:@"msg" error:originalError]; +} - [self waitForExpectationsWithTimeout:1 handler:nil]; +- (void)testDefaultBranchLogFormat { + NSError *error = [NSError errorWithDomain:@"com.domain.test" code:200 userInfo:@{@"Error Message": @"Test Error"}]; + + NSString *expectedMessage = @"[BranchSDK][Error]msg NSError: Error Domain=com.domain.test Code=200 \"(null)\" UserInfo={Error Message=Test Error}"; + NSString *formattedMessage = [BranchLogger formatMessage:@"msg" logLevel:BranchLogLevelError error:error]; + + XCTAssertTrue([expectedMessage isEqualToString:formattedMessage]); } @end diff --git a/Branch-TestBed/Branch-SDK-Tests/BranchOpenRequestTests.m b/Branch-TestBed/Branch-SDK-Tests/BranchOpenRequestTests.m deleted file mode 100644 index 234084b81..000000000 --- a/Branch-TestBed/Branch-SDK-Tests/BranchOpenRequestTests.m +++ /dev/null @@ -1,390 +0,0 @@ -// -// BranchOpenRequestTests.m -// Branch-TestBed -// -// Created by Graham Mueller on 6/19/15. -// Copyright (c) 2015 Branch Metrics. All rights reserved. -// - -#import "BNCTestCase.h" -#import "Branch.h" -#import "BNCApplication+BNCTest.h" -#import "BranchOpenRequest.h" -#import "BranchConstants.h" -#import "BNCPreferenceHelper.h" -#import "BNCPreferenceHelper.h" -#import "BNCEncodingUtils.h" -#import "BNCSystemObserver.h" -//#import -// -//@interface BranchOpenRequestTests : BNCTestCase -//@end -// -//@implementation BranchOpenRequestTests -// -//- (void)setUp { -// [super setUp]; -// BNCPreferenceHelper *preferenceHelper = [BNCPreferenceHelper sharedInstance]; -// preferenceHelper.installParams = nil; -// preferenceHelper.randomizedBundleToken = nil; -// [preferenceHelper saveContentAnalyticsManifest:nil]; -// [preferenceHelper synchronize]; -//} -// -//- (void)testSuccessWithAllKeysAndIsReferrable { -// NSString * const DEVICE_TOKEN = @"foo-token"; -// NSString * const USER_URL = @"http://foo"; -// NSString * const DEVELOPER_ID = @"foo"; -// NSString * const SESSION_ID = @"foo-session"; -// NSString * const SESSION_PARAMS = @"{\"+clicked_branch_link\":1,\"foo\":\"bar\"}"; -// NSString * const RANDOMIZED_BUNDLE_TOKEN = @"branch-id"; -// -// BNCServerResponse *response = [[BNCServerResponse alloc] init]; -// response.data = @{ -// BRANCH_RESPONSE_KEY_RANDOMIZED_DEVICE_TOKEN: DEVICE_TOKEN, -// BRANCH_RESPONSE_KEY_USER_URL: USER_URL, -// BRANCH_RESPONSE_KEY_DEVELOPER_IDENTITY: DEVELOPER_ID, -// BRANCH_RESPONSE_KEY_SESSION_ID: SESSION_ID, -// BRANCH_RESPONSE_KEY_SESSION_DATA: SESSION_PARAMS, -// BRANCH_RESPONSE_KEY_RANDOMIZED_BUNDLE_TOKEN: RANDOMIZED_BUNDLE_TOKEN -// }; -// -// BNCPreferenceHelper *preferenceHelper = [BNCPreferenceHelper sharedInstance]; -// -// XCTestExpectation *openExpectation = [self expectationWithDescription:@"OpenRequest Expectation"]; -// BranchOpenRequest *request = [[BranchOpenRequest alloc] initWithCallback:^(BOOL success, NSError *error) { -// XCTAssertNil(error); -// XCTAssertTrue(success); -// [self safelyFulfillExpectation:openExpectation]; -// } isInstall:TRUE]; -// -// [request processResponse:response error:nil]; -// -// [self awaitExpectations]; -// -// XCTAssertEqualObjects(preferenceHelper.randomizedDeviceToken, DEVICE_TOKEN); -// XCTAssertEqualObjects(preferenceHelper.userUrl, USER_URL); -// XCTAssertEqualObjects(preferenceHelper.userIdentity, DEVELOPER_ID); -// XCTAssertEqualObjects(preferenceHelper.sessionID, SESSION_ID); -// XCTAssertEqualObjects(preferenceHelper.sessionParams, SESSION_PARAMS); -// XCTAssertEqualObjects(preferenceHelper.installParams, SESSION_PARAMS); -// XCTAssertEqualObjects(preferenceHelper.randomizedBundleToken, RANDOMIZED_BUNDLE_TOKEN); -// XCTAssertNil(preferenceHelper.linkClickIdentifier); -//} -// -//- (void)testSuccessWithAllKeysAndIsNotReferrable { -// NSString * const DEVICE_TOKEN = @"foo-token"; -// NSString * const USER_URL = @"http://foo"; -// NSString * const DEVELOPER_ID = @"foo"; -// NSString * const SESSION_ID = @"foo-session"; -// NSString * const SESSION_PARAMS = @"{\"foo\":\"bar\"}"; -// NSString * const INSTALL_PARAMS = @"{\"bar\":\"foo\"}"; -// NSString * const IDENTITY = @"branch-id"; -// -// BNCServerResponse *response = [[BNCServerResponse alloc] init]; -// response.data = @{ -// BRANCH_RESPONSE_KEY_RANDOMIZED_DEVICE_TOKEN: DEVICE_TOKEN, -// BRANCH_RESPONSE_KEY_USER_URL: USER_URL, -// BRANCH_RESPONSE_KEY_DEVELOPER_IDENTITY: DEVELOPER_ID, -// BRANCH_RESPONSE_KEY_SESSION_ID: SESSION_ID, -// BRANCH_RESPONSE_KEY_SESSION_DATA: SESSION_PARAMS, -// BRANCH_RESPONSE_KEY_RANDOMIZED_BUNDLE_TOKEN: IDENTITY -// }; -// -// BNCPreferenceHelper *preferenceHelper = [BNCPreferenceHelper sharedInstance]; -// preferenceHelper.installParams = INSTALL_PARAMS; -// -// XCTestExpectation *openExpectation = [self expectationWithDescription:@"OpenRequest Expectation"]; -// BranchOpenRequest *request = [[BranchOpenRequest alloc] initWithCallback:^(BOOL success, NSError *error) { -// XCTAssertNil(error); -// XCTAssertTrue(success); -// [self safelyFulfillExpectation:openExpectation]; -// }]; -// -// [request processResponse:response error:nil]; -// -// [self awaitExpectations]; -// -// XCTAssertEqualObjects(preferenceHelper.randomizedDeviceToken, DEVICE_TOKEN); -// XCTAssertEqualObjects(preferenceHelper.userUrl, USER_URL); -// XCTAssertEqualObjects(preferenceHelper.userIdentity, DEVELOPER_ID); -// XCTAssertEqualObjects(preferenceHelper.sessionID, SESSION_ID); -// XCTAssertEqualObjects(preferenceHelper.sessionParams, SESSION_PARAMS); -// XCTAssertEqualObjects(preferenceHelper.installParams, INSTALL_PARAMS); -// XCTAssertEqualObjects(preferenceHelper.randomizedBundleToken, IDENTITY); -// XCTAssertNil(preferenceHelper.linkClickIdentifier); -//} -// -//- (void)testSuccessWithNoSessionParamsAndIsNotReferrable { -// NSString * const DEVICE_TOKEN = @"foo-token"; -// NSString * const USER_URL = @"http://foo"; -// NSString * const DEVELOPER_ID = @"foo"; -// NSString * const SESSION_ID = @"foo-session"; -// NSString * const INSTALL_PARAMS = @"{\"bar\":\"foo\"}"; -// NSString * const IDENTITY = @"branch-id"; -// -// BNCServerResponse *response = [[BNCServerResponse alloc] init]; -// response.data = @{ -// BRANCH_RESPONSE_KEY_RANDOMIZED_DEVICE_TOKEN: DEVICE_TOKEN, -// BRANCH_RESPONSE_KEY_USER_URL: USER_URL, -// BRANCH_RESPONSE_KEY_DEVELOPER_IDENTITY: DEVELOPER_ID, -// BRANCH_RESPONSE_KEY_SESSION_ID: SESSION_ID, -// BRANCH_RESPONSE_KEY_RANDOMIZED_BUNDLE_TOKEN: IDENTITY -// }; -// -// BNCPreferenceHelper *preferenceHelper = [BNCPreferenceHelper sharedInstance]; -// preferenceHelper.installParams = INSTALL_PARAMS; -// -// XCTestExpectation *openExpectation = [self expectationWithDescription:@"OpenRequest Expectation"]; -// BranchOpenRequest *request = [[BranchOpenRequest alloc] initWithCallback:^(BOOL success, NSError *error) { -// XCTAssertNil(error); -// XCTAssertTrue(success); -// [self safelyFulfillExpectation:openExpectation]; -// }]; -// -// [request processResponse:response error:nil]; -// -// [self awaitExpectations]; -// -// XCTAssertEqualObjects(preferenceHelper.randomizedDeviceToken, DEVICE_TOKEN); -// XCTAssertEqualObjects(preferenceHelper.userUrl, USER_URL); -// XCTAssertEqualObjects(preferenceHelper.userIdentity, DEVELOPER_ID); -// XCTAssertEqualObjects(preferenceHelper.sessionID, SESSION_ID); -// XCTAssertEqualObjects(preferenceHelper.installParams, INSTALL_PARAMS); -// XCTAssertEqualObjects(preferenceHelper.randomizedBundleToken, IDENTITY); -// XCTAssertNil(preferenceHelper.sessionParams); -// XCTAssertNil(preferenceHelper.linkClickIdentifier); -//} -// -//- (void)testSuccessWithNoSessionParamsAndIsReferrableAndAllowToBeClearIsNotSet { -// NSString * const DEVICE_TOKEN = @"foo-token"; -// NSString * const USER_URL = @"http://foo"; -// NSString * const DEVELOPER_ID = @"foo"; -// NSString * const SESSION_ID = @"foo-session"; -// NSString * const INSTALL_PARAMS = @"{\"bar\":\"foo\"}"; -// NSString * const IDENTITY = @"branch-id"; -// -// BNCServerResponse *response = [[BNCServerResponse alloc] init]; -// response.data = @{ -// BRANCH_RESPONSE_KEY_RANDOMIZED_DEVICE_TOKEN: DEVICE_TOKEN, -// BRANCH_RESPONSE_KEY_USER_URL: USER_URL, -// BRANCH_RESPONSE_KEY_DEVELOPER_IDENTITY: DEVELOPER_ID, -// BRANCH_RESPONSE_KEY_SESSION_ID: SESSION_ID, -// BRANCH_RESPONSE_KEY_RANDOMIZED_BUNDLE_TOKEN: IDENTITY -// }; -// -// BNCPreferenceHelper *preferenceHelper = [BNCPreferenceHelper sharedInstance]; -// preferenceHelper.installParams = INSTALL_PARAMS; -// -// XCTestExpectation *openExpectation = [self expectationWithDescription:@"OpenRequest Expectation"]; -// BranchOpenRequest *request = [[BranchOpenRequest alloc] initWithCallback:^(BOOL success, NSError *error) { -// XCTAssertNil(error); -// XCTAssertTrue(success); -// [self safelyFulfillExpectation:openExpectation]; -// }]; -// -// [request processResponse:response error:nil]; -// -// [self awaitExpectations]; -// -// XCTAssertEqualObjects(preferenceHelper.randomizedDeviceToken, DEVICE_TOKEN); -// XCTAssertEqualObjects(preferenceHelper.userUrl, USER_URL); -// XCTAssertEqualObjects(preferenceHelper.userIdentity, DEVELOPER_ID); -// XCTAssertEqualObjects(preferenceHelper.sessionID, SESSION_ID); -// XCTAssertEqualObjects(preferenceHelper.installParams, INSTALL_PARAMS); -// XCTAssertEqualObjects(preferenceHelper.randomizedBundleToken, IDENTITY); -// XCTAssertNil(preferenceHelper.sessionParams); -// XCTAssertNil(preferenceHelper.linkClickIdentifier); -//} -// -//- (void)testSuccessWithNoSessionParamsAndIsReferrableAndAllowToBeClearIsSet { -// NSString * const DEVICE_TOKEN = @"foo-token"; -// NSString * const USER_URL = @"http://foo"; -// NSString * const DEVELOPER_ID = @"foo"; -// NSString * const SESSION_ID = @"foo-session"; -// NSString * const IDENTITY = @"branch-id"; -// -// BNCServerResponse *response = [[BNCServerResponse alloc] init]; -// response.data = @{ -// BRANCH_RESPONSE_KEY_RANDOMIZED_DEVICE_TOKEN: DEVICE_TOKEN, -// BRANCH_RESPONSE_KEY_USER_URL: USER_URL, -// BRANCH_RESPONSE_KEY_DEVELOPER_IDENTITY: DEVELOPER_ID, -// BRANCH_RESPONSE_KEY_SESSION_ID: SESSION_ID, -// BRANCH_RESPONSE_KEY_RANDOMIZED_BUNDLE_TOKEN: IDENTITY -// }; -// -// BNCPreferenceHelper *preferenceHelper = [BNCPreferenceHelper sharedInstance]; -// -// XCTestExpectation *openExpectation = [self expectationWithDescription:@"OpenRequest Expectation"]; -// BranchOpenRequest *request = [[BranchOpenRequest alloc] initWithCallback:^(BOOL success, NSError *error) { -// XCTAssertNil(error); -// XCTAssertTrue(success); -// [self safelyFulfillExpectation:openExpectation]; -// } isInstall:NO]; -// -// [request processResponse:response error:nil]; -// -// [self awaitExpectations]; -// -// XCTAssertEqualObjects(preferenceHelper.randomizedDeviceToken, DEVICE_TOKEN); -// XCTAssertEqualObjects(preferenceHelper.userUrl, USER_URL); -// XCTAssertEqualObjects(preferenceHelper.userIdentity, DEVELOPER_ID); -// XCTAssertEqualObjects(preferenceHelper.sessionID, SESSION_ID); -// XCTAssertEqualObjects(preferenceHelper.randomizedBundleToken, IDENTITY); -// XCTAssertNil(preferenceHelper.sessionParams); -// XCTAssertNil(preferenceHelper.linkClickIdentifier); -// XCTAssertNil(preferenceHelper.installParams); -//} -// -//- (void)testOpenWhenReferrableAndNoInstallParamsAndNonNullData { -// BNCPreferenceHelper *preferenceHelper = [BNCPreferenceHelper sharedInstance]; -// -// NSString * const OPEN_PARAMS = @"{\"+clicked_branch_link\":1,\"foo\":\"bar\"}"; -// -// XCTestExpectation *expectation = [self expectationWithDescription:@"Request Expectation"]; -// BranchOpenRequest *request = [[BranchOpenRequest alloc] initWithCallback:^(BOOL changed, NSError *error) { -// XCTAssertNil(error); -// XCTAssertEqualObjects(preferenceHelper.installParams, OPEN_PARAMS); -// -// [self safelyFulfillExpectation:expectation]; -// } isInstall:TRUE]; -// -// BNCServerResponse *response = [[BNCServerResponse alloc] init]; -// response.data = @{ BRANCH_RESPONSE_KEY_SESSION_DATA: OPEN_PARAMS }; -// [request processResponse:response error:nil]; -// -// [self awaitExpectations]; -//} -// -//- (void)testOpenWhenReferrableAndNoInstallParamsAndNullData { -// BNCPreferenceHelper *preferenceHelper = [BNCPreferenceHelper sharedInstance]; -// -// XCTestExpectation *expectation = [self expectationWithDescription:@"Request Expectation"]; -// BranchOpenRequest *request = [[BranchOpenRequest alloc] initWithCallback:^(BOOL changed, NSError *error) { -// XCTAssertNil(error); -// XCTAssertNil(preferenceHelper.installParams); -// -// [self safelyFulfillExpectation:expectation]; -// }]; -// -// BNCServerResponse *response = [[BNCServerResponse alloc] init]; -// response.data = @{ }; -// [request processResponse:response error:nil]; -// -// [self awaitExpectations]; -//} -// -//- (void)testOpenWhenReferrableAndNoInstallParamsAndNonLinkClickData { -// BNCPreferenceHelper *preferenceHelper = [BNCPreferenceHelper sharedInstance]; -// -// NSString * const OPEN_PARAMS = @"{\"+clicked_branch_link\":0}"; -// -// XCTestExpectation *expectation = [self expectationWithDescription:@"Request Expectation"]; -// BranchOpenRequest *request = [[BranchOpenRequest alloc] initWithCallback:^(BOOL changed, NSError *error) { -// XCTAssertNil(error); -// XCTAssertNil(preferenceHelper.installParams); -// -// [self safelyFulfillExpectation:expectation]; -// }]; -// -// BNCServerResponse *response = [[BNCServerResponse alloc] init]; -// response.data = @{ BRANCH_RESPONSE_KEY_SESSION_DATA: OPEN_PARAMS }; -// [request processResponse:response error:nil]; -// -// [self awaitExpectations]; -//} -// -//- (void)testOpenWhenReferrableAndInstallParams { -// BNCPreferenceHelper *preferenceHelper = [BNCPreferenceHelper sharedInstance]; -// -// NSString * const INSTALL_PARAMS = @"{\"+clicked_branch_link\":1,\"foo\":\"bar\"}"; -// NSString * const OPEN_PARAMS = @"{\"+clicked_branch_link\":1,\"bar\":\"foo\"}"; -// -// preferenceHelper.installParams = INSTALL_PARAMS; -// -// XCTestExpectation *expectation = [self expectationWithDescription:@"Request Expectation"]; -// BranchOpenRequest *request = [[BranchOpenRequest alloc] initWithCallback:^(BOOL changed, NSError *error) { -// XCTAssertNil(error); -// XCTAssertEqualObjects(preferenceHelper.installParams, INSTALL_PARAMS); -// -// [self safelyFulfillExpectation:expectation]; -// }]; -// -// BNCServerResponse *response = [[BNCServerResponse alloc] init]; -// response.data = @{ BRANCH_RESPONSE_KEY_SESSION_DATA: OPEN_PARAMS }; -// [request processResponse:response error:nil]; -// -// [self awaitExpectations]; -//} -// -//- (void)testOpenWhenNotReferrable { -// // 'isReferrable' seems to be an empty concept in iOS. -// // It is in the code but not used. -- Edward. -// -// BNCPreferenceHelper *preferenceHelper = [BNCPreferenceHelper sharedInstance]; -// -// NSString * const OPEN_PARAMS = @"{\"+clicked_branch_link\":1,\"foo\":\"bar\"}"; -// -// XCTestExpectation *expectation = [self expectationWithDescription:@"Request Expectation"]; -// BranchOpenRequest *request = [[BranchOpenRequest alloc] initWithCallback:^(BOOL changed, NSError *error) { -// XCTAssertNil(error); -// XCTAssert([preferenceHelper.installParams isEqualToString:OPEN_PARAMS]); -// [self safelyFulfillExpectation:expectation]; -// } isInstall:TRUE]; -// -// BNCServerResponse *response = [[BNCServerResponse alloc] init]; -// response.data = @{ BRANCH_RESPONSE_KEY_SESSION_DATA: OPEN_PARAMS }; -// [request processResponse:response error:nil]; -// -// [self awaitExpectations]; -//} -// -//- (void)testEmptyResponseFields { -// NSString * DEVICE_TOKEN = @"foo-token"; -// NSString * USER_URL = @"http://foo"; -// NSString * DEVELOPER_ID = @"foo"; -// NSString * SESSION_ID = @"foo-session"; -// NSString * IDENTITY = @"branch-id"; -// -// BNCServerResponse *response = [[BNCServerResponse alloc] init]; -// response.data = @{ -// BRANCH_RESPONSE_KEY_RANDOMIZED_DEVICE_TOKEN: DEVICE_TOKEN, -// BRANCH_RESPONSE_KEY_USER_URL: USER_URL, -// BRANCH_RESPONSE_KEY_DEVELOPER_IDENTITY: DEVELOPER_ID, -// BRANCH_RESPONSE_KEY_SESSION_ID: SESSION_ID, -// BRANCH_RESPONSE_KEY_RANDOMIZED_BUNDLE_TOKEN: IDENTITY -// }; -// -// BNCPreferenceHelper *preferenceHelper = [BNCPreferenceHelper sharedInstance]; -// -// XCTestExpectation *openExpectation = [self expectationWithDescription:@"OpenRequest Expectation"]; -// BranchOpenRequest *request = [[BranchOpenRequest alloc] initWithCallback:^(BOOL success, NSError *error) { -// XCTAssertNil(error); -// XCTAssertTrue(success); -// [self safelyFulfillExpectation:openExpectation]; -// } isInstall:NO]; -// -// [request processResponse:response error:nil]; -// -// [self awaitExpectations]; -// -// XCTAssertEqualObjects(preferenceHelper.randomizedDeviceToken, DEVICE_TOKEN); -// XCTAssertEqualObjects(preferenceHelper.userUrl, USER_URL); -// XCTAssertEqualObjects(preferenceHelper.userIdentity, DEVELOPER_ID); -// XCTAssertEqualObjects(preferenceHelper.sessionID, SESSION_ID); -// XCTAssertEqualObjects(preferenceHelper.randomizedBundleToken, IDENTITY); -// XCTAssertNil(preferenceHelper.sessionParams); -// XCTAssertNil(preferenceHelper.linkClickIdentifier); -// XCTAssertNil(preferenceHelper.installParams); -// -// // Now call processResponse with empty fields again. -// response.data = @{}; -// [request processResponse:response error:nil]; -// -// XCTAssertNotNil(preferenceHelper.randomizedDeviceToken); -// XCTAssertNotNil(preferenceHelper.userUrl); -// XCTAssertNotNil(preferenceHelper.sessionID); -// XCTAssertNotNil(preferenceHelper.randomizedBundleToken); -//} -// -//@end diff --git a/Branch-TestBed/Branch-SDK-Tests/BranchSDKFunctionalityTests.m b/Branch-TestBed/Branch-SDK-Tests/BranchSDKFunctionalityTests.m deleted file mode 100644 index 889ee54a3..000000000 --- a/Branch-TestBed/Branch-SDK-Tests/BranchSDKFunctionalityTests.m +++ /dev/null @@ -1,121 +0,0 @@ -// -// Branch_SDK_test.m -// Branch-SDK test -// -// Created by Qinwei Gong on 2/19/15. -// Copyright (c) 2015 Branch Metrics. All rights reserved. -// - -#import "BNCTestCase.h" -#import "Branch.h" - -NSString * const TEST_RANDOMIZED_DEVICE_TOKEN = @"94938498586381084"; -NSString * const TEST_RANDOMIZED_BUNDLE_TOKEN = @"95765863201768032"; -NSString * const TEST_SESSION_ID = @"97141055400444225"; -NSString * const TEST_IDENTITY_LINK = @"https://bnc.lt/i/3N-xr0E-_M"; -NSString * const TEST_NEW_USER_LINK = @"https://bnc.lt/i/2kkbX6k-As"; - -@interface BranchSDKFunctionalityTests : BNCTestCase -@property (assign, nonatomic) BOOL hasExceededExpectations; -@end - -@implementation BranchSDKFunctionalityTests - -//- (void)test00OpenOrInstall { -// id serverInterfaceMock = OCMClassMock([BNCServerInterface class]); -// -// BNCPreferenceHelper *preferenceHelper = [BNCPreferenceHelper sharedInstance]; -// Branch.branchKey = @"key_live_foo"; -// -// Branch *branch = -// [[Branch alloc] -// initWithInterface:serverInterfaceMock -// queue:[[BNCServerRequestQueue alloc] init] -// cache:[[BNCLinkCache alloc] init] -// preferenceHelper:preferenceHelper -// key:@"key_live_foo"]; -// -// BNCServerResponse *openInstallResponse = [[BNCServerResponse alloc] init]; -// openInstallResponse.data = @{ -// @"randomized_device_token": TEST_RANDOMIZED_DEVICE_TOKEN, -// @"randomized_bundle_token": TEST_RANDOMIZED_BUNDLE_TOKEN, -// @"link": TEST_IDENTITY_LINK, -// @"session_id": TEST_SESSION_ID -// }; -// -// __block BNCServerCallback openOrInstallCallback; -// id openOrInstallCallbackCheckBlock = [OCMArg checkWithBlock:^BOOL(BNCServerCallback callback) { -// openOrInstallCallback = callback; -// return YES; -// }]; -// -// id openOrInstallInvocation = ^(NSInvocation *invocation) { -// openOrInstallCallback(openInstallResponse, nil); -// }; -// -// id openOrInstallUrlCheckBlock = [OCMArg checkWithBlock:^BOOL(NSString *url) { -// return [url rangeOfString:@"open"].location != NSNotFound || [url rangeOfString:@"install"].location != NSNotFound; -// }]; -// [[[serverInterfaceMock expect] -// andDo:openOrInstallInvocation] -// postRequest:[OCMArg any] -// url:openOrInstallUrlCheckBlock -// key:[OCMArg any] -// callback:openOrInstallCallbackCheckBlock]; -// -// XCTestExpectation *openExpectation = [self expectationWithDescription:@"Test open"]; -// [branch initSessionWithLaunchOptions:@{} andRegisterDeepLinkHandler:^(NSDictionary *params, NSError *error) { -// XCTAssertNil(error); -// XCTAssertEqualObjects(preferenceHelper.sessionID, TEST_SESSION_ID); -// [openExpectation fulfill]; -// }]; -// -// [self waitForExpectationsWithTimeout:2 handler:NULL]; -//} -// -//#pragma mark - Test Utility -// -//- (void)safelyFulfillExpectation:(XCTestExpectation *)expectation { -// if (!self.hasExceededExpectations) { -// [expectation fulfill]; -// } -//} -// -//- (void)awaitExpectations { -// [self waitForExpectationsWithTimeout:6.0 handler:^(NSError *error) { -// self.hasExceededExpectations = YES; -// }]; -//} -// -//- (void)setupDefaultStubsForServerInterfaceMock:(id)serverInterfaceMock { -// BNCServerResponse *openInstallResponse = [[BNCServerResponse alloc] init]; -// openInstallResponse.data = @{ -// @"session_id": TEST_SESSION_ID, -// @"randomized_bundle_token": TEST_RANDOMIZED_BUNDLE_TOKEN, -// @"randomized_device_token": TEST_RANDOMIZED_DEVICE_TOKEN, -// }; -// -// // Stub open / install -// __block BNCServerCallback openOrInstallCallback; -// id openOrInstallCallbackCheckBlock = [OCMArg checkWithBlock:^BOOL(BNCServerCallback callback) { -// openOrInstallCallback = callback; -// return YES; -// }]; -// -// id openOrInstallInvocation = ^(NSInvocation *invocation) { -// openOrInstallCallback(openInstallResponse, nil); -// }; -// -// id openOrInstallUrlCheckBlock = [OCMArg checkWithBlock:^BOOL(NSString *url) { -// return [url rangeOfString:@"open"].location != NSNotFound || -// [url rangeOfString:@"install"].location != NSNotFound; -// }]; -// [[[serverInterfaceMock expect] -// andDo:openOrInstallInvocation] -// postRequest:[OCMArg any] -// url:openOrInstallUrlCheckBlock -// key:[OCMArg any] -// callback:openOrInstallCallbackCheckBlock]; -//} - -@end diff --git a/Branch-TestBed/Branch-TestBed.xcodeproj/project.pbxproj b/Branch-TestBed/Branch-TestBed.xcodeproj/project.pbxproj index 3dfa83dfa..23e32a6c7 100644 --- a/Branch-TestBed/Branch-TestBed.xcodeproj/project.pbxproj +++ b/Branch-TestBed/Branch-TestBed.xcodeproj/project.pbxproj @@ -22,13 +22,8 @@ 4683F0761B20A73F00A432E7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 670016731940F51400A9E103 /* AppDelegate.m */; }; 46DC406E1B2A328900D2D203 /* AdSupport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 67BBCF271A69E49A009C7DAE /* AdSupport.framework */; }; 4AB16368239E3A2700D42931 /* DispatchToIsolationQueueTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4AB16367239E3A2700D42931 /* DispatchToIsolationQueueTests.m */; }; - 4D1683A82098C902008819E3 /* BNCServerRequestQueueOldTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D16837D2098C901008819E3 /* BNCServerRequestQueueOldTests.m */; }; - 4D1683AA2098C902008819E3 /* BranchOpenRequestTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D16837F2098C901008819E3 /* BranchOpenRequestTests.m */; }; - 4D1683AC2098C902008819E3 /* BranchInstallRequestTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D1683822098C901008819E3 /* BranchInstallRequestTests.m */; }; 4D1683AE2098C902008819E3 /* BNCLinkDataTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D1683842098C901008819E3 /* BNCLinkDataTests.m */; }; - 4D1683B02098C902008819E3 /* BranchSDKFunctionalityTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D1683862098C901008819E3 /* BranchSDKFunctionalityTests.m */; }; 4D1683B62098C902008819E3 /* BNCURLFilterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D16838C2098C901008819E3 /* BNCURLFilterTests.m */; }; - 4D1683B72098C902008819E3 /* BNCTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D16838D2098C901008819E3 /* BNCTestCase.m */; }; 4D1683B82098C902008819E3 /* BNCEncodingUtilsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D16838E2098C901008819E3 /* BNCEncodingUtilsTests.m */; }; 4D1683B92098C902008819E3 /* BNCSystemObserverTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D16838F2098C901008819E3 /* BNCSystemObserverTests.m */; }; 4D1683C02098C902008819E3 /* BranchUniversalObjectTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D1683962098C901008819E3 /* BranchUniversalObjectTests.m */; }; @@ -38,9 +33,6 @@ 4D1683C82098C902008819E3 /* NSStringBranchTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D16839E2098C901008819E3 /* NSStringBranchTests.m */; }; 4D1683CA2098C902008819E3 /* BNCPreferenceHelperTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D1683A02098C901008819E3 /* BNCPreferenceHelperTests.m */; }; 4D1851C120180F3300E48994 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4D1851BF20180F0600E48994 /* Security.framework */; }; - 4D7881FD209CF2D4002B750F /* BNCTestCase.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4D7881F9209CF2D4002B750F /* BNCTestCase.strings */; }; - 4D7881FE209CF2D4002B750F /* BNCTestCase.Test.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D7881FA209CF2D4002B750F /* BNCTestCase.Test.m */; }; - 4D7881FF209CF2D4002B750F /* BNCApplication+BNCTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D7881FC209CF2D4002B750F /* BNCApplication+BNCTest.m */; }; 4D93D8622098D43C00CFABA6 /* UITestSafari.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D93D8602098D43C00CFABA6 /* UITestSafari.m */; }; 4DBEFFF61FB114F900F7C41B /* ArrayPickerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4DBEFFF51FB114F900F7C41B /* ArrayPickerView.m */; }; 4DE235641FB12C2700D4E5A9 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4DBEFFFB1FB12A1000F7C41B /* Main.storyboard */; }; @@ -50,7 +42,6 @@ 5F3D671B233062FD00454FF1 /* BNCJsonLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 5F3D671A233062FD00454FF1 /* BNCJsonLoader.m */; }; 5F3D671C233062FD00454FF1 /* BNCJsonLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 5F3D671A233062FD00454FF1 /* BNCJsonLoader.m */; }; 5F42763325DB3694005B9BBC /* AdServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F42763225DB3694005B9BBC /* AdServices.framework */; }; - 5F437E38237DE1320052064B /* CoreTelephony.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F437E37237DE1320052064B /* CoreTelephony.framework */; settings = {ATTRIBUTES = (Required, ); }; }; 5F437E40237E1A560052064B /* BNCDeviceSystemTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5F437E3F237E1A560052064B /* BNCDeviceSystemTests.m */; }; 5F5FDA102B7DE20800F14A43 /* BranchLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 5F5FDA0F2B7DE20800F14A43 /* BranchLogger.m */; }; 5F5FDA122B7DE22A00F14A43 /* BranchLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 5F5FDA112B7DE22A00F14A43 /* BranchLogger.h */; }; @@ -311,15 +302,9 @@ 03B49EEA25F9F315000BF105 /* UITestCase0OpenNInstall.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UITestCase0OpenNInstall.m; sourceTree = ""; }; 466B58381B17773000A69EDE /* libBranch.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libBranch.a; sourceTree = BUILT_PRODUCTS_DIR; }; 4AB16367239E3A2700D42931 /* DispatchToIsolationQueueTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DispatchToIsolationQueueTests.m; sourceTree = ""; }; - 4D16837D2098C901008819E3 /* BNCServerRequestQueueOldTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BNCServerRequestQueueOldTests.m; sourceTree = ""; }; - 4D16837E2098C901008819E3 /* BNCServerInterface.Test.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BNCServerInterface.Test.m; sourceTree = ""; }; - 4D16837F2098C901008819E3 /* BranchOpenRequestTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BranchOpenRequestTests.m; sourceTree = ""; }; 4D1683812098C901008819E3 /* Branch-SDK-Tests-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Branch-SDK-Tests-Bridging-Header.h"; sourceTree = ""; }; - 4D1683822098C901008819E3 /* BranchInstallRequestTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BranchInstallRequestTests.m; sourceTree = ""; }; 4D1683842098C901008819E3 /* BNCLinkDataTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BNCLinkDataTests.m; sourceTree = ""; }; - 4D1683862098C901008819E3 /* BranchSDKFunctionalityTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BranchSDKFunctionalityTests.m; sourceTree = ""; }; 4D16838C2098C901008819E3 /* BNCURLFilterTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BNCURLFilterTests.m; sourceTree = ""; }; - 4D16838D2098C901008819E3 /* BNCTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BNCTestCase.m; sourceTree = ""; }; 4D16838E2098C901008819E3 /* BNCEncodingUtilsTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BNCEncodingUtilsTests.m; sourceTree = ""; }; 4D16838F2098C901008819E3 /* BNCSystemObserverTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BNCSystemObserverTests.m; sourceTree = ""; }; 4D1683952098C901008819E3 /* BranchEvent.Test.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BranchEvent.Test.swift; sourceTree = ""; }; @@ -330,12 +315,7 @@ 4D16839E2098C901008819E3 /* NSStringBranchTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSStringBranchTests.m; sourceTree = ""; }; 4D16839F2098C901008819E3 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 4D1683A02098C901008819E3 /* BNCPreferenceHelperTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BNCPreferenceHelperTests.m; sourceTree = ""; }; - 4D1683A12098C901008819E3 /* BNCTestCase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BNCTestCase.h; sourceTree = ""; }; 4D1851BF20180F0600E48994 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; - 4D7881F9209CF2D4002B750F /* BNCTestCase.strings */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; path = BNCTestCase.strings; sourceTree = ""; }; - 4D7881FA209CF2D4002B750F /* BNCTestCase.Test.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BNCTestCase.Test.m; sourceTree = ""; }; - 4D7881FB209CF2D4002B750F /* BNCApplication+BNCTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "BNCApplication+BNCTest.h"; sourceTree = ""; }; - 4D7881FC209CF2D4002B750F /* BNCApplication+BNCTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "BNCApplication+BNCTest.m"; sourceTree = ""; }; 4D93D8592098CC4400CFABA6 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 4D93D85F2098D43C00CFABA6 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 4D93D8602098D43C00CFABA6 /* UITestSafari.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UITestSafari.m; sourceTree = ""; }; @@ -571,7 +551,6 @@ buildActionMask = 2147483647; files = ( 5F92B2362383644C00CA909B /* SystemConfiguration.framework in Frameworks */, - 5F437E38237DE1320052064B /* CoreTelephony.framework in Frameworks */, 5F205D05231864E800C776D1 /* WebKit.framework in Frameworks */, 5FF7D2862A9549B40049158D /* AdServices.framework in Frameworks */, 466B584F1B17775900A69EDE /* AdSupport.framework in Frameworks */, @@ -630,8 +609,6 @@ children = ( E7A728BC2AA9A112009343B7 /* BNCAPIServerTest.m */, 5FC7326F22DD1F93006E6FBC /* BNCAppleReceiptTests.m */, - 4D7881FB209CF2D4002B750F /* BNCApplication+BNCTest.h */, - 4D7881FC209CF2D4002B750F /* BNCApplication+BNCTest.m */, 4D1683972098C901008819E3 /* BNCApplicationTests.m */, 5FE694372405FA2700E3AEE2 /* BNCCallbackMapTests.m */, 4D16839D2098C901008819E3 /* BNCCrashlyticsWrapperTests.m */, @@ -652,15 +629,9 @@ 5F92B23323835FEB00CA909B /* BNCReachabilityTests.m */, C1CC888129BAAFC000BDD2B5 /* BNCReferringURLUtilityTests.m */, 5FC20E722A93D85F00D9E1C8 /* BNCRequestFactoryTests.m */, - 4D16837E2098C901008819E3 /* BNCServerInterface.Test.m */, - 4D16837D2098C901008819E3 /* BNCServerRequestQueueOldTests.m */, 5FB6CC12264F0C7C0020E478 /* BNCServerRequestQueueTests.m */, 5FDB04F324E6156800F2F267 /* BNCSKAdNetworkTests.m */, 4D16838F2098C901008819E3 /* BNCSystemObserverTests.m */, - 4D1683A12098C901008819E3 /* BNCTestCase.h */, - 4D16838D2098C901008819E3 /* BNCTestCase.m */, - 4D7881F9209CF2D4002B750F /* BNCTestCase.strings */, - 4D7881FA209CF2D4002B750F /* BNCTestCase.Test.m */, 5FCF7EAC29DC96A7008D629E /* BNCURLFilterSkiplistUpgradeTests.m */, 4D16838C2098C901008819E3 /* BNCURLFilterTests.m */, 5F205D022318641700C776D1 /* BNCUserAgentCollectorTests.m */, @@ -669,13 +640,10 @@ C17DAF7A2AC20C2000B16B1A /* BranchClassTests.m */, 4D16839C2098C901008819E3 /* BranchEvent.Test.m */, 4D1683952098C901008819E3 /* BranchEvent.Test.swift */, - 4D1683822098C901008819E3 /* BranchInstallRequestTests.m */, 5F909B712332BEF600A774D2 /* BranchLastAttributedTouchDataTests.m */, 5F5FDA132B7DE27D00F14A43 /* BranchLoggerTests.m */, - 4D16837F2098C901008819E3 /* BranchOpenRequestTests.m */, C10F393927A0872800BF5D36 /* BranchPluginSupportTests.m */, C12320B42808DB90007771C0 /* BranchQRCodeTests.m */, - 4D1683862098C901008819E3 /* BranchSDKFunctionalityTests.m */, C10C61A9282481FB00761D7E /* BranchShareLinkTests.m */, 4D1683962098C901008819E3 /* BranchUniversalObjectTests.m */, 4AB16367239E3A2700D42931 /* DispatchToIsolationQueueTests.m */, @@ -1256,7 +1224,6 @@ 5FC4CF8C24860C440001E701 /* latd.json in Resources */, 5FC4CF9024860C440001E701 /* example.json in Resources */, 5FC4CF9224860C440001E701 /* latd_missing_data.json in Resources */, - 4D7881FD209CF2D4002B750F /* BNCTestCase.strings in Resources */, 5FC4CF8D24860C440001E701 /* latd_missing_window.json in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1395,13 +1362,10 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 4D1683B72098C902008819E3 /* BNCTestCase.m in Sources */, 4D1683B82098C902008819E3 /* BNCEncodingUtilsTests.m in Sources */, 5F909B5E23314CE900A774D2 /* BNCJSONUtilityTests.m in Sources */, 5F909B722332BEF600A774D2 /* BranchLastAttributedTouchDataTests.m in Sources */, - 4D7881FE209CF2D4002B750F /* BNCTestCase.Test.m in Sources */, 5FC20E732A93D85F00D9E1C8 /* BNCRequestFactoryTests.m in Sources */, - 4D1683B02098C902008819E3 /* BranchSDKFunctionalityTests.m in Sources */, 5FA9112F29BC662000F3D35C /* BNCNetworkInterfaceTests.m in Sources */, 5FD1786E26DEE49D009696E3 /* BNCPasteboardTests.m in Sources */, 5F86501A2B76DA3200364BDE /* NSMutableDictionaryBranchTests.m in Sources */, @@ -1409,7 +1373,6 @@ 5F92B242238752A500CA909B /* BNCDeviceInfoTests.m in Sources */, 4D1683C62098C902008819E3 /* BranchEvent.Test.m in Sources */, C15CC9DE2ABCB549003CC339 /* BNCCurrencyTests.m in Sources */, - 5F83B9ED2433BAAA0054A022 /* BNCServerInterface.Test.m in Sources */, 5F205D0823186AF700C776D1 /* BNCUserAgentCollectorTests.m in Sources */, 5FCF7EAD29DC96A7008D629E /* BNCURLFilterSkiplistUpgradeTests.m in Sources */, 5F6D86D92BB5E9650068B536 /* BNCClassSerializationTests.m in Sources */, @@ -1425,7 +1388,6 @@ 5FDB04F424E6156800F2F267 /* BNCSKAdNetworkTests.m in Sources */, 5FB6CC13264F0C7C0020E478 /* BNCServerRequestQueueTests.m in Sources */, 4D1683AE2098C902008819E3 /* BNCLinkDataTests.m in Sources */, - 4D7881FF209CF2D4002B750F /* BNCApplication+BNCTest.m in Sources */, C15CC9E02ABCF8C8003CC339 /* BranchActivityItemTests.m in Sources */, 5F92B23423835FEB00CA909B /* BNCReachabilityTests.m in Sources */, C17DAF7B2AC20C2000B16B1A /* BranchClassTests.m in Sources */, @@ -1435,12 +1397,9 @@ 5FC7327022DD1F93006E6FBC /* BNCAppleReceiptTests.m in Sources */, 4D1683C82098C902008819E3 /* NSStringBranchTests.m in Sources */, 5F892EC5236116CD0023AEC1 /* NSErrorBranchTests.m in Sources */, - 4D1683AA2098C902008819E3 /* BranchOpenRequestTests.m in Sources */, - 4D1683A82098C902008819E3 /* BNCServerRequestQueueOldTests.m in Sources */, 4D1683B62098C902008819E3 /* BNCURLFilterTests.m in Sources */, C10C61AA282481FB00761D7E /* BranchShareLinkTests.m in Sources */, 5F437E40237E1A560052064B /* BNCDeviceSystemTests.m in Sources */, - 4D1683AC2098C902008819E3 /* BranchInstallRequestTests.m in Sources */, 4D1683C72098C902008819E3 /* BNCCrashlyticsWrapperTests.m in Sources */, 5FDF91592581CDF4009BE5A3 /* BNCPartnerParametersTests.m in Sources */, ); diff --git a/BranchSDK.podspec b/BranchSDK.podspec index cf52b72d9..b7d65623c 100644 --- a/BranchSDK.podspec +++ b/BranchSDK.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "BranchSDK" - s.version = "3.3.0" + s.version = "3.4.0" s.summary = "Create an HTTP URL for any piece of content in your app" s.description = <<-DESC - Want the highest possible conversions on your sharing feature? diff --git a/BranchSDK.xcodeproj/project.pbxproj b/BranchSDK.xcodeproj/project.pbxproj index 3c67048f8..de8d1fda2 100644 --- a/BranchSDK.xcodeproj/project.pbxproj +++ b/BranchSDK.xcodeproj/project.pbxproj @@ -1974,7 +1974,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MARKETING_VERSION = 3.3.0; + MARKETING_VERSION = 3.4.0; OTHER_LDFLAGS = ( "-weak_framework", LinkPresentation, @@ -2009,7 +2009,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MARKETING_VERSION = 3.3.0; + MARKETING_VERSION = 3.4.0; OTHER_LDFLAGS = ( "-weak_framework", LinkPresentation, @@ -2215,7 +2215,7 @@ "@loader_path/Frameworks", ); MACH_O_TYPE = staticlib; - MARKETING_VERSION = 3.3.0; + MARKETING_VERSION = 3.4.0; OTHER_LDFLAGS = ( "-weak_framework", LinkPresentation, @@ -2254,7 +2254,7 @@ "@loader_path/Frameworks", ); MACH_O_TYPE = staticlib; - MARKETING_VERSION = 3.3.0; + MARKETING_VERSION = 3.4.0; OTHER_LDFLAGS = ( "-weak_framework", LinkPresentation, @@ -2291,7 +2291,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MARKETING_VERSION = 3.3.0; + MARKETING_VERSION = 3.4.0; OTHER_LDFLAGS = ( "-weak_framework", LinkPresentation, @@ -2326,7 +2326,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MARKETING_VERSION = 3.3.0; + MARKETING_VERSION = 3.4.0; OTHER_LDFLAGS = ( "-weak_framework", LinkPresentation, diff --git a/ChangeLog.md b/ChangeLog.md index 52323086a..8f88503ce 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,5 +1,8 @@ Branch iOS SDK Change Log +v.3.4.0 +- Added support for setting the Branch API base URL through the `branch.json` file. + v.3.3.0 - SDK behavior change to fix a race condition when opening a closed app with a link. In some apps, this race condition could cause the occasional loss of link data. diff --git a/Sources/BranchSDK/BNCApplication.m b/Sources/BranchSDK/BNCApplication.m index 2bbecb03a..a3cce47c5 100644 --- a/Sources/BranchSDK/BNCApplication.m +++ b/Sources/BranchSDK/BNCApplication.m @@ -21,7 +21,7 @@ @implementation BNCApplication // BNCApplication checks a few values in keychain -// Checking keychain from main thread early in the app lifecycle can deadlock. INTENG-7291 +// Checking keychain from main thread early in the app lifecycle can deadlock. INTENG-7291 + (void)loadCurrentApplicationWithCompletion:(void (^)(BNCApplication *application))completion { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ BNCApplication *tmp = [BNCApplication currentApplication]; @@ -69,64 +69,71 @@ + (BNCApplication*) createCurrentApplication { return application; } -+ (NSDate*) currentBuildDate { ++ (NSDate *)currentBuildDate { NSURL *appURL = nil; NSURL *bundleURL = [NSBundle mainBundle].bundleURL; NSDictionary *info = [NSBundle mainBundle].infoDictionary; - NSString *appName = info[(__bridge NSString*)kCFBundleExecutableKey]; + NSString *appName = info[(__bridge NSString *)kCFBundleExecutableKey]; if (appName.length > 0 && bundleURL) { + // path to the app on device. file:///private/var/containers/Bundle/Application/GUID appURL = [bundleURL URLByAppendingPathComponent:appName]; } else { + // TODO: Why is this fallback necessary? The NSBundle approach has been available since iOS 2.0 + // path to old app location, this symlinks to the new location. file:///var/containers/Bundle/Application/GUID NSString *path = [[NSProcessInfo processInfo].arguments firstObject]; - if (path) appURL = [NSURL fileURLWithPath:path]; + if (path) { + appURL = [NSURL fileURLWithPath:path]; + } } - if (appURL == nil) + if (appURL == nil) { + [[BranchLogger shared] logError:@"Failed to get build date, app path is nil" error:nil]; return nil; + } NSError *error = nil; NSFileManager *fileManager = [NSFileManager defaultManager]; NSDictionary *attributes = [fileManager attributesOfItemAtPath:appURL.path error:&error]; if (error) { - [[BranchLogger shared] logError:[NSString stringWithFormat:@"Can't get build date: %@.", error] error:error]; + [[BranchLogger shared] logError:@"Failed to get build date" error:error]; return nil; } - NSDate * buildDate = [attributes fileCreationDate]; + NSDate *buildDate = [attributes fileCreationDate]; if (buildDate == nil || [buildDate timeIntervalSince1970] <= 0.0) { - [[BranchLogger shared] logError:[NSString stringWithFormat:@"Invalid build date: %@.", buildDate] error:nil]; + [[BranchLogger shared] logError:[NSString stringWithFormat:@"Invalid build date: %@", buildDate] error:nil]; } return buildDate; } -+ (NSDate*) firstInstallBuildDate { ++ (NSDate *)firstInstallBuildDate { + // check for stored build date NSError *error = nil; - NSDate *firstBuildDate = - [BNCKeyChain retrieveDateForService:kBranchKeychainService - key:kBranchKeychainFirstBuildKey - error:&error]; - if (firstBuildDate) + NSDate *firstBuildDate = [BNCKeyChain retrieveDateForService:kBranchKeychainService key:kBranchKeychainFirstBuildKey error:&error]; + if (firstBuildDate) { return firstBuildDate; - + } + + // get current build date and store it firstBuildDate = [self currentBuildDate]; - error = [BNCKeyChain storeDate:firstBuildDate - forService:kBranchKeychainService - key:kBranchKeychainFirstBuildKey - cloudAccessGroup:nil]; - if (error) [[BranchLogger shared] logError:[NSString stringWithFormat:@"Keychain store: %@.", error] error:error]; - + error = [BNCKeyChain storeDate:firstBuildDate forService:kBranchKeychainService key:kBranchKeychainFirstBuildKey cloudAccessGroup:nil]; + if (error) { + [[BranchLogger shared] logError:@"Error saving build date" error:error]; + } return firstBuildDate; } -+ (NSDate *) currentInstallDate { ++ (NSDate *)currentInstallDate { NSDate *installDate = [NSDate date]; #if !TARGET_OS_TV // tvOS always returns a creation date of Unix epoch 0 on device installDate = [self creationDateForLibraryDirectory]; - #endif - if (installDate == nil || [installDate timeIntervalSince1970] <= 0.0) { - [[BranchLogger shared] logWarning:[NSString stringWithFormat:@"Invalid install date, using [NSDate date]."]]; + [[BranchLogger shared] logError:@"Invalid install date, using [NSDate date]" error:nil]; } + #else + [[BranchLogger shared] logWarning:@"File system creation date not supported on tvOS, using [NSDate date]" error:nil]; + #endif + return installDate; } @@ -136,13 +143,13 @@ + (NSDate *)creationDateForLibraryDirectory { NSURL *directoryURL = [[fileManager URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask] firstObject]; NSDictionary *attributes = [fileManager attributesOfItemAtPath:directoryURL.path error:&error]; if (error) { - [[BranchLogger shared] logError:[NSString stringWithFormat:@"Can't get creation date for Library directory: %@", error] error:error]; - return nil; + [[BranchLogger shared] logWarning:@"Failed to get creation date for NSLibraryDirectory" error:error]; + return nil; } return [attributes fileCreationDate]; } -+ (NSDate*) firstInstallDate { ++ (NSDate *)firstInstallDate { // check keychain for stored install date, on iOS this is lost on app deletion. NSError *error = nil; NSDate* firstInstallDate = [BNCKeyChain retrieveDateForService:kBranchKeychainService key:kBranchKeychainFirstInstalldKey error:&error]; @@ -156,22 +163,9 @@ + (NSDate*) firstInstallDate { // save filesystem time to keychain error = [BNCKeyChain storeDate:firstInstallDate forService:kBranchKeychainService key:kBranchKeychainFirstInstalldKey cloudAccessGroup:nil]; if (error) { - [[BranchLogger shared] logError:[NSString stringWithFormat:@"Keychain store: %@.", error] error:error]; + [[BranchLogger shared] logWarning:@"Error while saving install date" error:error]; } return firstInstallDate; } @end - -@implementation BNCApplication (BNCTest) - -- (void) setAppOriginalInstallDate:(NSDate*)originalInstallDate - firstInstallDate:(NSDate*)firstInstallDate - lastUpdateDate:(NSDate*)lastUpdateDate { - self->_currentInstallDate = firstInstallDate; // latest_install_time - self->_firstInstallDate = originalInstallDate; // first_install_time - self->_currentBuildDate = lastUpdateDate; // lastest_update_time -} - -@end - diff --git a/Sources/BranchSDK/BNCConfig.m b/Sources/BranchSDK/BNCConfig.m index 2e16a9c7d..7335edabc 100644 --- a/Sources/BranchSDK/BNCConfig.m +++ b/Sources/BranchSDK/BNCConfig.m @@ -8,7 +8,7 @@ #include "BNCConfig.h" -NSString * const BNC_SDK_VERSION = @"3.3.0"; +NSString * const BNC_SDK_VERSION = @"3.4.0"; NSString * const BNC_LINK_URL = @"https://bnc.lt"; NSString * const BNC_CDN_URL = @"https://cdn.branch.io"; diff --git a/Sources/BranchSDK/BNCEncodingUtils.m b/Sources/BranchSDK/BNCEncodingUtils.m index 57cf9e16c..2ed69555c 100644 --- a/Sources/BranchSDK/BNCEncodingUtils.m +++ b/Sources/BranchSDK/BNCEncodingUtils.m @@ -165,9 +165,8 @@ + (NSString *)encodeDictionaryToJsonString:(NSDictionary *)dictionary { NSMutableString *encodedDictionary = [[NSMutableString alloc] initWithString:@"{"]; for (NSString *key in dictionary) { - // protect against non-string keys if (![key isKindOfClass:[NSString class]]) { - [[BranchLogger shared] logError:[NSString stringWithFormat:@"Unexpected key type %@. Skipping key.", [key class]] error:nil]; + [[BranchLogger shared] logWarning:[NSString stringWithFormat:@"Ignoring unexpected key type %@", [key class]] error:nil]; continue; } @@ -177,38 +176,30 @@ + (NSString *)encodeDictionaryToJsonString:(NSDictionary *)dictionary { id obj = dictionary[key]; if ([obj isKindOfClass:[NSString class]]) { value = [BNCEncodingUtils sanitizedStringFromString:obj]; - } - else if ([obj isKindOfClass:[NSURL class]]) { + } else if ([obj isKindOfClass:[NSURL class]]) { value = [obj absoluteString]; - } - else if ([obj isKindOfClass:[NSDate class]]) { + } else if ([obj isKindOfClass:[NSDate class]]) { value = [BNCEncodingUtils iso8601StringFromDate:obj]; - } - else if ([obj isKindOfClass:[NSArray class]]) { + } else if ([obj isKindOfClass:[NSArray class]]) { value = [BNCEncodingUtils encodeArrayToJsonString:obj]; string = NO; - } - else if ([obj isKindOfClass:[NSDictionary class]] || [obj isKindOfClass:[NSMutableDictionary class]]) { + } else if ([obj isKindOfClass:[NSDictionary class]] || [obj isKindOfClass:[NSMutableDictionary class]]) { value = [BNCEncodingUtils encodeDictionaryToJsonString:obj]; string = NO; - } - else if ([obj isKindOfClass:[NSNumber class]]) { + } else if ([obj isKindOfClass:[NSNumber class]]) { string = NO; - if (obj == (id)kCFBooleanFalse) + if (obj == (id)kCFBooleanFalse) { value = @"false"; - else - if (obj == (id)kCFBooleanTrue) + } else if (obj == (id)kCFBooleanTrue) { value = @"true"; - else + } else { value = [obj stringValue]; - } - else if ([obj isKindOfClass:[NSNull class]]) { + } + } else if ([obj isKindOfClass:[NSNull class]]) { value = @"null"; string = NO; - } - else { - // If this type is not a known type, don't attempt to encode it. - [[BranchLogger shared] logError:[NSString stringWithFormat:@"Cannot encode value for key %@. The value is not an accepted type.", key] error:nil]; + } else { + [[BranchLogger shared] logWarning:[NSString stringWithFormat:@"Ignoring unexpected value type %@", [obj class]] error:nil]; continue; } @@ -230,12 +221,11 @@ + (NSString *)encodeDictionaryToJsonString:(NSDictionary *)dictionary { [encodedDictionary appendString:@"}"]; - [[BranchLogger shared] logDebug:[NSString stringWithFormat:@"Encoded dictionary: %@.", encodedDictionary]]; + [[BranchLogger shared] logVerbose:[NSString stringWithFormat:@"Encoded dictionary: %@.", encodedDictionary] error:nil]; return encodedDictionary; } + (NSString *)encodeArrayToJsonString:(NSArray *)array { - // Empty array if (![array count]) { return @"[]"; } @@ -247,41 +237,31 @@ + (NSString *)encodeArrayToJsonString:(NSArray *)array { if ([obj isKindOfClass:[NSString class]]) { value = [BNCEncodingUtils sanitizedStringFromString:obj]; - } - else if ([obj isKindOfClass:[NSURL class]]) { + } else if ([obj isKindOfClass:[NSURL class]]) { value = [obj absoluteString]; - } - else if ([obj isKindOfClass:[NSDate class]]) { + } else if ([obj isKindOfClass:[NSDate class]]) { value = [BNCEncodingUtils iso8601StringFromDate:obj]; - } - else if ([obj isKindOfClass:[NSArray class]]) { + } else if ([obj isKindOfClass:[NSArray class]]) { value = [BNCEncodingUtils encodeArrayToJsonString:obj]; string = NO; - } - else if ([obj isKindOfClass:[NSDictionary class]] || [obj isKindOfClass:[NSMutableDictionary class]]) { + } else if ([obj isKindOfClass:[NSDictionary class]] || [obj isKindOfClass:[NSMutableDictionary class]]) { value = [BNCEncodingUtils encodeDictionaryToJsonString:obj]; string = NO; - } - else if ([obj isKindOfClass:[NSNumber class]]) { + } else if ([obj isKindOfClass:[NSNumber class]]) { value = [obj stringValue]; string = NO; - } - else if ([obj isKindOfClass:[NSNull class]]) { + } else if ([obj isKindOfClass:[NSNull class]]) { value = @"null"; string = NO; - } - else { - // If this type is not a known type, don't attempt to encode it. - [[BranchLogger shared] logError:[NSString stringWithFormat:@"Cannot encode value %@. The value is not an accepted type.", obj] error:nil]; + } else { + [[BranchLogger shared] logWarning:[NSString stringWithFormat:@"Ignoring unexpected value type %@", [obj class]] error:nil]; continue; } - // If this is a "string" object, wrap it in quotes if (string) { + // quote strings [encodedArray appendFormat:@"\"%@\",", value]; - } - // Otherwise, just add the raw value after the colon - else { + } else { [encodedArray appendFormat:@"%@,", value]; } } @@ -290,8 +270,7 @@ + (NSString *)encodeArrayToJsonString:(NSArray *)array { [encodedArray deleteCharactersInRange:NSMakeRange([encodedArray length] - 1, 1)]; [encodedArray appendString:@"]"]; - [[BranchLogger shared] logDebug:[NSString stringWithFormat:@"Encoded array: %@.", encodedArray]]; - + [[BranchLogger shared] logVerbose:[NSString stringWithFormat:@"Encoded array: %@.", encodedArray] error:nil]; return encodedArray; } @@ -305,26 +284,20 @@ + (NSString *)encodeDictionaryToQueryString:(NSDictionary *)dictionary { NSMutableString *queryString = [[NSMutableString alloc] initWithString:@"?"]; for (NSString *key in [dictionary allKeys]) { - // No empty keys, please. if (key.length) { id obj = dictionary[key]; NSString *value; if ([obj isKindOfClass:[NSString class]]) { value = [BNCEncodingUtils urlEncodedString:obj]; - } - else if ([obj isKindOfClass:[NSURL class]]) { + } else if ([obj isKindOfClass:[NSURL class]]) { value = [BNCEncodingUtils urlEncodedString:[obj absoluteString]]; - } - else if ([obj isKindOfClass:[NSDate class]]) { + } else if ([obj isKindOfClass:[NSDate class]]) { value = [BNCEncodingUtils iso8601StringFromDate:obj]; - } - else if ([obj isKindOfClass:[NSNumber class]]) { + } else if ([obj isKindOfClass:[NSNumber class]]) { value = [obj stringValue]; - } - else { - // If this type is not a known type, don't attempt to encode it. - [[BranchLogger shared] logError:[NSString stringWithFormat:@"Cannot encode value %@. The value is not an accepted type.", obj] error:nil]; + } else { + [[BranchLogger shared] logWarning:[NSString stringWithFormat:@"Ignoring unexpected value type %@", [obj class]] error:nil]; continue; } @@ -334,29 +307,41 @@ + (NSString *)encodeDictionaryToQueryString:(NSDictionary *)dictionary { // Delete last character (either trailing & or ? if no params present) [queryString deleteCharactersInRange:NSMakeRange(queryString.length - 1, 1)]; - return queryString; } -+ (NSString*) stringByPercentDecodingString:(NSString *)string { ++ (NSString *)stringByPercentDecodingString:(NSString *)string { return [string stringByRemovingPercentEncoding]; } -+ (NSString*) stringByPercentEncodingStringForQuery:(NSString *)string { - return [string stringByAddingPercentEncodingWithAllowedCharacters: - [NSCharacterSet URLQueryAllowedCharacterSet]]; ++ (NSString *)stringByPercentEncodingStringForQuery:(NSString *)string { + return [string stringByAddingPercentEncodingWithAllowedCharacters: [NSCharacterSet URLQueryAllowedCharacterSet]]; +} + ++ (NSString *)prettyPrintJSON:(NSDictionary *)json { + if (![NSJSONSerialization isValidJSONObject:json]) { + [[BranchLogger shared] logWarning:@"Dictionary is not a valid JSON" error:nil]; + return nil; + } + + NSError *error; + NSData *data = [NSJSONSerialization dataWithJSONObject:json options:NSJSONWritingSortedKeys | NSJSONWritingPrettyPrinted error:&error]; + + if (!data || error) { + [[BranchLogger shared] logWarning:@"Failed to pretty print JSON" error:error]; + return nil; + } + return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; } #pragma mark - Param Decoding Methods + (NSDictionary *)decodeJsonDataToDictionary:(NSData *)jsonData { NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; - return [BNCEncodingUtils decodeJsonStringToDictionary:jsonString]; } + (NSDictionary *)decodeJsonStringToDictionary:(NSString *)jsonString { - // Just a basic decode, easy enough NSData *tempData = [jsonString dataUsingEncoding:NSUTF8StringEncoding]; if (!tempData) { return @{}; @@ -379,7 +364,6 @@ + (NSDictionary *)decodeJsonStringToDictionary:(NSString *)jsonString { return base64DecodedDictionary; } - // Apparently this data was not parsible into a dictionary, so we'll just return an empty one return @{}; } @@ -393,27 +377,29 @@ + (NSDictionary *)decodeQueryStringToDictionary:(NSString *)queryString { NSString *key = kv[0]; NSString *val = [kv[1] stringByRemovingPercentEncoding]; - // Don't add empty items if (val.length) { params[key] = val; } } } - return params; } #pragma mark - Hex Strings -+ (NSString *) hexStringFromData:(NSData*)data { - ++ (NSString *)hexStringFromData:(NSData*)data { NSUInteger bytesCount = data.length; - if (bytesCount <= 0) return @""; - + if (bytesCount <= 0) { + return @""; + } + const char *hexChars = "0123456789ABCDEF"; const char *dataBuffer = data.bytes; char *chars = malloc(sizeof(char) * (bytesCount * 2 + 1)); - if (!chars) return @""; + if (!chars) { + return @""; + } + char *s = chars; for (unsigned i = 0; i < bytesCount; ++i) { *s++ = hexChars[((*dataBuffer & 0xF0) >> 4)]; @@ -423,35 +409,39 @@ + (NSString *) hexStringFromData:(NSData*)data { *s = '\0'; NSString *hexString = [NSString stringWithUTF8String:chars]; - if (chars) free(chars); + if (chars) { + free(chars); + } + return hexString; } -+ (NSData *) dataFromHexString:(NSString*)string { - if (!string) return nil; - ++ (NSData *)dataFromHexString:(NSString*)string { + if (!string) { + return nil; + } + NSData *data = nil; NSData *inputData = [string dataUsingEncoding:NSUTF8StringEncoding]; size_t length = (inputData.length+1)/2; uint8_t *bytes = malloc(length); uint8_t *b = bytes; - if (!bytes) goto exit; - + if (!bytes) { + goto exit; + } + int highValue = -1; const uint8_t *p = (const uint8_t*) [inputData bytes]; for (NSUInteger i = 0; i < inputData.length; ++i) { int value; - if (*p >= '0' && *p <= '9') + if (*p >= '0' && *p <= '9') { value = *p - '0'; - else - if (*p >= 'A' && *p <= 'F') + } else if (*p >= 'A' && *p <= 'F') { value = *p - 'A' + 10; - else - if (*p >= 'a' && *p <= 'f') + } else if (*p >= 'a' && *p <= 'f') { value = *p - 'a' + 10; - else - if (isspace(*p)) { + } else if (isspace(*p)) { p++; continue; } else { @@ -468,9 +458,12 @@ + (NSData *) dataFromHexString:(NSString*)string { } // If highValue != -1 then we got an odd number of hex values, which is an error. - if (highValue == -1) + if (highValue == -1) { data = [NSData dataWithBytes:bytes length:b-bytes]; + } + // Error handling in C code is one case where goto can improve readability. + // https://www.kernel.org/doc/html/v4.19/process/coding-style.html exit: if (bytes) { free(bytes); @@ -480,23 +473,27 @@ + (NSData *) dataFromHexString:(NSString*)string { #pragma mark - URL QueryItems -+ (NSArray*) queryItems:(NSURL*)URL { - NSMutableArray* keyValues = [NSMutableArray new]; - if (!URL) return keyValues; - ++ (NSArray *)queryItems:(NSURL *)URL { + NSMutableArray *keyValues = [NSMutableArray new]; + if (!URL) { + return keyValues; + } + NSArray *queryItems = [[URL query] componentsSeparatedByString:@"&"]; - for (NSString* itemPair in queryItems) { + for (NSString *itemPair in queryItems) { BNCKeyValue *keyValue = [BNCKeyValue new]; NSRange range = [itemPair rangeOfString:@"="]; if (range.location == NSNotFound) { - if (itemPair.length) + if (itemPair.length) { keyValue.key = itemPair; + } } else { keyValue.key = [itemPair substringWithRange:NSMakeRange(0, range.location)]; NSRange r = NSMakeRange(range.location+1, itemPair.length-range.location-1); - if (r.length > 0) + if (r.length > 0) { keyValue.value = [itemPair substringWithRange:r]; + } } keyValue.key = [BNCEncodingUtils stringByPercentDecodingString:keyValue.key]; @@ -506,8 +503,13 @@ + (NSData *) dataFromHexString:(NSString*)string { keyValue.value = [keyValue.value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; if (keyValue.key.length || keyValue.value.length) { - if (keyValue.key == nil) keyValue.key = @""; - if (keyValue.value == nil) keyValue.value = @""; + if (keyValue.key == nil) { + keyValue.key = @""; + } + + if (keyValue.value == nil) { + keyValue.value = @""; + } [keyValues addObject:keyValue]; } } diff --git a/Sources/BranchSDK/BNCKeyChain.m b/Sources/BranchSDK/BNCKeyChain.m index c2e1da340..12dfaa640 100644 --- a/Sources/BranchSDK/BNCKeyChain.m +++ b/Sources/BranchSDK/BNCKeyChain.m @@ -20,11 +20,12 @@ @implementation BNCKeyChain +// Wraps OSStatus in an NSError +// Security errors are defined in Security/SecBase.h + (NSError *) errorWithKey:(NSString *)key OSStatus:(OSStatus)status { - // Security errors are defined in Security/SecBase.h if (status == errSecSuccess) return nil; NSString *reason = (__bridge_transfer NSString*) SecCopyErrorMessageString(status, NULL); - NSString *description = [NSString stringWithFormat:@"Security error with key '%@': code %ld.", key, (long) status]; + NSString *description = [NSString stringWithFormat:@"Branch Keychain error for key '%@': OSStatus %ld.", key, (long) status]; if (!reason) { reason = @"Sec OSStatus error."; @@ -37,7 +38,7 @@ + (NSError *) errorWithKey:(NSString *)key OSStatus:(OSStatus)status { return error; } -+ (NSDate *) retrieveDateForService:(NSString *)service key:(NSString *)key error:(NSError **)error { ++ (NSDate *)retrieveDateForService:(NSString *)service key:(NSString *)key error:(NSError **)error { if (error) *error = nil; if (service == nil || key == nil) { NSError *localError = [self errorWithKey:key OSStatus:errSecParam]; @@ -57,7 +58,8 @@ + (NSDate *) retrieveDateForService:(NSString *)service key:(NSString *)key erro OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)dictionary, (CFTypeRef *)&valueData); if (status != errSecSuccess) { NSError *localError = [self errorWithKey:key OSStatus:status]; - [[BranchLogger shared] logDebug:[NSString stringWithFormat:@"Can't retrieve key: %@.", localError]]; + [[BranchLogger shared] logVerbose:@"Key not found" error:localError]; + if (error) *error = localError; if (valueData) CFRelease(valueData); return nil; @@ -66,8 +68,7 @@ + (NSDate *) retrieveDateForService:(NSString *)service key:(NSString *)key erro if (valueData) { @try { value = [NSKeyedUnarchiver unarchivedObjectOfClass:[NSDate class] fromData:(__bridge NSData*)valueData error:NULL]; - } - @catch (id) { + } @catch (NSException *exception) { value = nil; NSError *localError = [self errorWithKey:key OSStatus:errSecDecode]; if (error) *error = localError; @@ -82,14 +83,14 @@ + (NSError *) storeDate:(NSDate *)date key:(NSString *)key cloudAccessGroup:(NSString *)accessGroup { - if (date == nil || service == nil || key == nil) + if (date == nil || service == nil || key == nil) { return [self errorWithKey:key OSStatus:errSecParam]; - + } + NSData* valueData = nil; @try { valueData = [NSKeyedArchiver archivedDataWithRootObject:date requiringSecureCoding:YES error:NULL]; - } - @catch(id) { + } @catch (NSException *exception) { valueData = nil; } if (!valueData) { @@ -106,7 +107,7 @@ + (NSError *) storeDate:(NSDate *)date OSStatus status = SecItemDelete((__bridge CFDictionaryRef)dictionary); if (status != errSecSuccess && status != errSecItemNotFound) { NSError *error = [self errorWithKey:key OSStatus:status]; - [[BranchLogger shared] logDebug:[NSString stringWithFormat:@"Can't clear to store key: %@.", error]]; + [[BranchLogger shared] logDebug:@"Failed to save key" error:error]; } dictionary[(__bridge id)kSecValueData] = valueData; @@ -122,7 +123,7 @@ + (NSError *) storeDate:(NSDate *)date status = SecItemAdd((__bridge CFDictionaryRef)dictionary, NULL); if (status) { NSError *error = [self errorWithKey:key OSStatus:status]; - [[BranchLogger shared] logDebug:[NSString stringWithFormat:@"Can't store key: %@.", error]]; + [[BranchLogger shared] logDebug:@"Failed to save key" error:error]; return error; } return nil; @@ -140,22 +141,24 @@ + (NSError*) removeValuesForService:(NSString *)service key:(NSString *)key { if (status == errSecItemNotFound) status = errSecSuccess; if (status) { NSError *error = [self errorWithKey:key OSStatus:status]; - [[BranchLogger shared] logDebug:[NSString stringWithFormat:@"Can't remove key: %@.", error]]; + [[BranchLogger shared] logDebug:@"Failed to remove key" error:[self errorWithKey:key OSStatus:status]]; return error; } return nil; } -+ (NSString * _Nullable) securityAccessGroup { - // https://stackoverflow.com/questions/11726672/access-app-identifier-prefix-programmatically +// The security access group string is prefixed with the Apple Developer Team ID ++ (NSString * _Nullable)securityAccessGroup { @synchronized(self) { - static NSString*_securityAccessGroup = nil; + static NSString *_securityAccessGroup = nil; if (_securityAccessGroup) return _securityAccessGroup; - - // First store a value: + + // The keychain cannot be empty prior to requesting the security access group string. Add a tmp variable. NSError *error = [self storeDate:[NSDate date] forService:@"BranchKeychainService" key:@"Temp" cloudAccessGroup:nil]; - if (error) [[BranchLogger shared] logDebug:[NSString stringWithFormat:@"Error storing temp value: %@.", error]]; - + if (error) { + [[BranchLogger shared] logWarning:@"Failed to store temp value" error:error]; + } + NSDictionary* dictionary = @{ (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword, (__bridge id)kSecAttrService: @"BranchKeychainService", @@ -167,13 +170,13 @@ + (NSString * _Nullable) securityAccessGroup { OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)dictionary, (CFTypeRef*)&resultDictionary); if (status == errSecItemNotFound) return nil; if (status != errSecSuccess) { - [[BranchLogger shared] logDebug:[NSString stringWithFormat:@"Get securityAccessGroup returned(%ld): %@.", - (long) status, [self errorWithKey:nil OSStatus:status]]]; + [[BranchLogger shared] logWarning:[NSString stringWithFormat:@"Failed to retrieve security access group"] error:[self errorWithKey:nil OSStatus:status]]; return nil; } - NSString*group = - [(__bridge NSDictionary *)resultDictionary objectForKey:(__bridge NSString *)kSecAttrAccessGroup]; - if (group.length > 0) _securityAccessGroup = [group copy]; + NSString *group = [(__bridge NSDictionary *)resultDictionary objectForKey:(__bridge NSString *)kSecAttrAccessGroup]; + if (group.length > 0) { + _securityAccessGroup = [group copy]; + } CFRelease(resultDictionary); return _securityAccessGroup; } diff --git a/Sources/BranchSDK/BNCNetworkInterface.m b/Sources/BranchSDK/BNCNetworkInterface.m index 87dffc8b2..2bc9a19c4 100644 --- a/Sources/BranchSDK/BNCNetworkInterface.m +++ b/Sources/BranchSDK/BNCNetworkInterface.m @@ -41,6 +41,7 @@ - (NSString*) description { ]; } +// Reads network interface information to the device IP address + (NSArray *)currentInterfaces { struct ifaddrs *interfaces = NULL; @@ -49,7 +50,8 @@ - (NSString*) description { // Retrieve the current interfaces - returns 0 on success if (getifaddrs(&interfaces) != 0) { int e = errno; - [[BranchLogger shared] logError:[NSString stringWithFormat:@"Can't read ip address: (%d): %s.", e, strerror(e)] error:nil]; + [[BranchLogger shared] logWarning:[NSString stringWithFormat:@"Failed to read IP Address: (%d): %s", e, strerror(e)] error:nil]; + goto exit; } @@ -92,6 +94,8 @@ - (NSString*) description { } } + // Error handling in C code is one case where goto can improve readability. + // https://www.kernel.org/doc/html/v4.19/process/coding-style.html exit: if (interfaces) freeifaddrs(interfaces); return currentInterfaces; diff --git a/Sources/BranchSDK/BNCNetworkService.m b/Sources/BranchSDK/BNCNetworkService.m index ea3ee4d16..01c517835 100644 --- a/Sources/BranchSDK/BNCNetworkService.m +++ b/Sources/BranchSDK/BNCNetworkService.m @@ -52,7 +52,8 @@ - (void) cancel { [self.sessionTask cancel]; } -- (NSString*) stringFromResponseData { +// only used in logging? Consider removing +- (NSString *)stringFromResponseData { NSString *string = nil; if ([self.responseData isKindOfClass:[NSData class]]) { string = [[NSString alloc] initWithData:(NSData*)self.responseData encoding:NSUTF8StringEncoding]; @@ -148,12 +149,12 @@ - (BOOL) operationsAreSuspended { #pragma mark - Operations -- (BNCNetworkOperation*) networkOperationWithURLRequest:(NSMutableURLRequest*)request +- (BNCNetworkOperation *) networkOperationWithURLRequest:(NSMutableURLRequest*)request completion:(void (^)(idoperation))completion { BNCNetworkOperation *operation = [BNCNetworkOperation new]; if (![request isKindOfClass:[NSMutableURLRequest class]]) { - [[BranchLogger shared] logError:@"A `NSMutableURLRequest` request parameter was expected." error:nil]; + [[BranchLogger shared] logError:[NSString stringWithFormat:@"Expected NSMutableURLRequest, got %@", [request class]] error:nil]; return nil; } operation.request = request; @@ -162,7 +163,7 @@ - (BNCNetworkOperation*) networkOperationWithURLRequest:(NSMutableURLRequest*)re return operation; } -- (void) startOperation:(BNCNetworkOperation*)operation { +- (void)startOperation:(BNCNetworkOperation *)operation { operation.networkService = self; if (!operation.startDate) { operation.startDate = [NSDate date]; @@ -170,41 +171,29 @@ - (void) startOperation:(BNCNetworkOperation*)operation { if (!operation.timeoutDate) { NSTimeInterval timeoutInterval = operation.request.timeoutInterval; - if (timeoutInterval < 0.0) + if (timeoutInterval < 0.0) { timeoutInterval = self.defaultTimeoutInterval; - operation.timeoutDate = - [[operation startDate] dateByAddingTimeInterval:timeoutInterval]; + } + operation.timeoutDate = [[operation startDate] dateByAddingTimeInterval:timeoutInterval]; } if ([operation.request isKindOfClass:[NSMutableURLRequest class]]) { ((NSMutableURLRequest*)operation.request).timeoutInterval = [operation.timeoutDate timeIntervalSinceDate:[NSDate date]]; } else { - [[BranchLogger shared] logError:@"SDK logic error. Expected mutable request in `start` method." error:nil]; + [[BranchLogger shared] logError:[NSString stringWithFormat:@"Expected NSMutableURLRequest, got %@", [operation.request class]] error:nil]; } - operation.sessionTask = - [self.session dataTaskWithRequest:operation.request - completionHandler: - ^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { + operation.sessionTask = [self.session dataTaskWithRequest:operation.request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { operation.responseData = data; operation.response = (NSHTTPURLResponse*) response; operation.error = error; - if (operation.response.statusCode != 404) { - [[BranchLogger shared] logDebug:[NSString stringWithFormat:@"Network finish operation %@ %1.3fs. Status %ld error %@.\n%@.", - operation.request.URL.absoluteString, - [[NSDate date] timeIntervalSinceDate:operation.startDate], - (long)operation.response.statusCode, - operation.error, - operation.stringFromResponseData]]; - } - if (operation.completionBlock) + if (operation.completionBlock) { operation.completionBlock(operation); + } }]; - [[BranchLogger shared] logDebug:[NSString stringWithFormat:@"Network start operation %@.", operation.request.URL]]; - [operation.sessionTask resume]; } diff --git a/Sources/BranchSDK/BNCPartnerParameters.m b/Sources/BranchSDK/BNCPartnerParameters.m index 828edc1dc..c8642e488 100644 --- a/Sources/BranchSDK/BNCPartnerParameters.m +++ b/Sources/BranchSDK/BNCPartnerParameters.m @@ -54,7 +54,7 @@ - (void)addFacebookParameterWithName:(NSString *)name value:(NSString *)value { if ([self sha256HashSanityCheckValue:value]) { [self addParameterWithName:name value:value partnerName:@"fb"]; } else { - [[BranchLogger shared] logWarning:@"Partner parameter does not appear to be SHA256 hashed. Dropping the parameter."]; + [[BranchLogger shared] logWarning:@"Partner parameter does not appear to be SHA256 hashed. Dropping the parameter." error:nil]; } } @@ -62,7 +62,7 @@ - (void)addSnapParameterWithName:(NSString *)name value:(NSString *)value { if ([self sha256HashSanityCheckValue:value]) { [self addParameterWithName:name value:value partnerName:@"snap"]; } else { - [[BranchLogger shared] logWarning:@"Partner parameter does not appear to be SHA256 hashed. Dropping the parameter."]; + [[BranchLogger shared] logWarning:@"Partner parameter does not appear to be SHA256 hashed. Dropping the parameter." error:nil]; } } diff --git a/Sources/BranchSDK/BNCPreferenceHelper.m b/Sources/BranchSDK/BNCPreferenceHelper.m index cee6cbbb4..730fcbe1a 100644 --- a/Sources/BranchSDK/BNCPreferenceHelper.m +++ b/Sources/BranchSDK/BNCPreferenceHelper.m @@ -168,7 +168,7 @@ - (void)setPatternListURL:(NSString *)url { [self writeObjectToDefaults:BRANCH_PREFS_KEY_PATTERN_LIST_URL value:url]; } } else { - [[BranchLogger shared] logWarning:@"Ignoring invalid custom CDN URL"]; + [[BranchLogger shared] logWarning:@"Ignoring invalid custom CDN URL" error:nil]; } } @@ -923,7 +923,7 @@ - (void)persistPrefsToDisk { NSError *error = nil; [data writeToURL:prefsURL options:NSDataWritingAtomic error:&error]; if (error) { - [[BranchLogger shared] logWarning:[NSString stringWithFormat:@"Failed to persist preferences: %@.", error]]; + [[BranchLogger shared] logWarning:@"Failed to persist preferences" error:error]; } }]; [_persistPrefsQueue addOperation:newPersistOp]; @@ -937,8 +937,8 @@ - (NSData *)serializePrefDict:(NSMutableDictionary *)dict { NSData *data = nil; @try { data = [NSKeyedArchiver archivedDataWithRootObject:dict requiringSecureCoding:YES error:NULL]; - } @catch (id exception) { - [[BranchLogger shared] logWarning:[NSString stringWithFormat:@"Exception serializing preferences dict: %@.", exception]]; + } @catch (NSException *exception) { + [[BranchLogger shared] logError:[NSString stringWithFormat:@"Exception serializing preferences dict: %@.", exception] error:nil]; } return data; } @@ -969,10 +969,10 @@ - (NSData *)loadPrefData { NSError *error = nil; data = [NSData dataWithContentsOfURL:self.class.URLForPrefsFile options:0 error:&error]; if (error || !data) { - [[BranchLogger shared] logWarning:@"Failed to load preferences from storage."]; + [[BranchLogger shared] logWarning:@"Failed to load preferences from storage. This is expected on first run." error:error]; } - } @catch (NSException *) { - [[BranchLogger shared] logWarning:@"Failed to load preferences from storage."]; + } @catch (NSException *exception) { + [[BranchLogger shared] logError:[NSString stringWithFormat:@"Exception loading preferences dict: %@.", exception] error:nil]; } return data; } @@ -985,7 +985,7 @@ - (NSMutableDictionary *)deserializePrefDictFromData:(NSData *)data { dict = [NSKeyedUnarchiver unarchivedObjectOfClasses:classes fromData:data error:&error]; if (error) { - [[BranchLogger shared] logWarning:@"Failed to load preferences from storage."]; + [[BranchLogger shared] logWarning:@"Failed to load preferences from storage." error:error]; } } @@ -1083,9 +1083,10 @@ + (NSURL* _Nonnull) URLForPrefsFile { attributes:nil error:&error]; if (success) { + [[BranchLogger shared] logVerbose:[NSString stringWithFormat:@"Using storage URL %@", branchURL] error:error]; return branchURL; } else { - [[BranchLogger shared] logError:[NSString stringWithFormat:@"CreateBranchURL failed: %@ URL: %@.", error, branchURL] error:error]; + [[BranchLogger shared] logWarning:[NSString stringWithFormat:@"Failed to create URL %@", branchURL] error:error]; } } return nil; @@ -1123,8 +1124,11 @@ + (NSURL* _Nonnull) URLForPrefsFile { withIntermediateDirectories:YES attributes:nil error:&error]; - if (!success) { - [[BranchLogger shared] logError:[NSString stringWithFormat:@"Worst case CreateBranchURL error was: %@ URL: %@.", error, branchURL] error:error]; + if (success) { + [[BranchLogger shared] logVerbose:[NSString stringWithFormat:@"Using storage URL %@", branchURL] error:error]; + } else { + [[BranchLogger shared] logWarning:[NSString stringWithFormat:@"Failed to create URL %@", branchURL] error:error]; + [[BranchLogger shared] logError:@"Failed all attempts to create URLs to BNCPreferenceHelper storage." error:nil]; } return branchURL; } diff --git a/Sources/BranchSDK/BNCReferringURLUtility.m b/Sources/BranchSDK/BNCReferringURLUtility.m index c4a9c965a..3d7b63aac 100644 --- a/Sources/BranchSDK/BNCReferringURLUtility.m +++ b/Sources/BranchSDK/BNCReferringURLUtility.m @@ -79,6 +79,7 @@ - (void)processQueryParameter:(NSURLQueryItem *)item { param.validityWindow = [self defaultValidityWindowForParam:name]; } + [[BranchLogger shared] logDebug:[NSString stringWithFormat:@"Parsed Referring URL: %@", param] error:nil]; [self.urlQueryParameters setValue:param forKey:name]; } @@ -90,6 +91,8 @@ - (void)processMetaQueryParameter:(NSURLQueryItem *)item { param.timestamp = [NSDate date]; param.isDeepLink = YES; param.validityWindow = [self defaultValidityWindowForParam:BRANCH_REQUEST_KEY_META_CAMPAIGN_IDS]; + + [[BranchLogger shared] logDebug:[NSString stringWithFormat:@"Parsed Referring URL: %@", param] error:nil]; [self.urlQueryParameters setValue:param forKey:BRANCH_REQUEST_KEY_META_CAMPAIGN_IDS]; } } @@ -112,6 +115,8 @@ - (NSDictionary *)dictionaryFromEncodedJsonString:(NSString *)encodedJsonString NSDictionary *json = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error]; if (!error) { return json; + } else { + [[BranchLogger shared] logError:@"Failed to parse Meta AEM JSON" error:error]; } } return nil; @@ -263,7 +268,6 @@ - (NSMutableDictionary *)serializeToJson:(NSMutableDictionaryoperation) = ^void (idoperation) { - BNCServerResponse *serverResponse = - [self processServerResponse:operation.response data:operation.responseData error:operation.error]; + BNCServerResponse *serverResponse = [self processServerResponse:operation.response data:operation.responseData error:operation.error]; [self collectInstrumentationMetricsWithOperation:operation]; - NSError *underlyingError = operation.error; - NSInteger status = [serverResponse.statusCode integerValue]; - // If the phone is in a poor network condition, // iOS will return statuses such as -1001, -1003, -1200, -9806 // indicating various parts of the HTTP post failed. @@ -109,68 +104,46 @@ - (void)genericHTTPRequest:(NSURLRequest *)request retryNumber:(NSInteger)retryN // Status 53 means the request was killed by the OS because we're still in the background. // This started happening in iOS 12 / Xcode 10 production when we're called from continueUserActivity: // but we're not fully out of the background yet. + + NSInteger status = [serverResponse.statusCode integerValue]; + NSError *underlyingError = operation.error; + // Retry request if appropriate BOOL isRetryableStatusCode = status >= 500 || status < 0 || status == 53; - - // Retry the request if appropriate if (retryNumber < self.preferenceHelper.retryCount && isRetryableStatusCode) { - dispatch_time_t dispatchTime = - dispatch_time(DISPATCH_TIME_NOW, self.preferenceHelper.retryInterval * NSEC_PER_SEC); + dispatch_time_t dispatchTime = dispatch_time(DISPATCH_TIME_NOW, self.preferenceHelper.retryInterval * NSEC_PER_SEC); dispatch_after(dispatchTime, dispatch_get_main_queue(), ^{ if (retryHandler) { - [[BranchLogger shared] logDebug: [NSString stringWithFormat:@"Retrying request with url %@", request.URL.relativePath]]; - // Create the next request + [[BranchLogger shared] logDebug: [NSString stringWithFormat:@"Retrying request with HTTP status code %ld", (long)status] error:underlyingError]; NSURLRequest *retryRequest = retryHandler(retryNumber); - [self genericHTTPRequest:retryRequest - retryNumber:(retryNumber + 1) - callback:callback retryHandler:retryHandler]; + [self genericHTTPRequest:retryRequest retryNumber:(retryNumber + 1) callback:callback retryHandler:retryHandler]; } }); - // Do not continue on if retrying, else the callback will be called incorrectly - return; - } - - NSError *branchError = nil; - - // Wrap up bad statuses w/ specific error messages - if (status >= 500) { - branchError = [NSError branchErrorWithCode:BNCServerProblemError error:underlyingError]; - } - else if (status == 409) { - branchError = [NSError branchErrorWithCode:BNCDuplicateResourceError error:underlyingError]; - } - else if (status >= 400) { - NSString *errorString = [serverResponse.data objectForKey:@"error"]; - if (![errorString isKindOfClass:[NSString class]]) - errorString = nil; - if (!errorString) - errorString = underlyingError.localizedDescription; - if (!errorString) - errorString = @"The request was invalid."; - branchError = [NSError branchErrorWithCode:BNCBadRequestError localizedMessage:errorString]; - } - else if (underlyingError) { - branchError = [NSError branchErrorWithCode:BNCServerProblemError error:underlyingError]; - } + } else { + if (status != 200) { + if ([NSError branchDNSBlockingError:underlyingError]) { + [[BranchLogger shared] logWarning:[NSString stringWithFormat:@"Possible DNS Ad Blocker. Giving up on request with HTTP status code %ld", (long)status] error:underlyingError]; + } else { + [[BranchLogger shared] logWarning: [NSString stringWithFormat:@"Giving up on request with HTTP status code %ld", (long)status] error:underlyingError]; + } + } - if (branchError) { - [[BranchLogger shared] logError:[NSString stringWithFormat:@"An error prevented request to %@ from completing: %@", request.URL.absoluteString, branchError] error:branchError]; + // Don't call on the main queue since it might be blocked. + if (callback) { + callback(serverResponse, underlyingError); + } } - - // Don't call on the main queue since it might be blocked. - if (callback) - callback(serverResponse, branchError); }; + // Drops non-linking requests when tracking is disabled if (Branch.trackingDisabled) { NSString *endpoint = request.URL.absoluteString; - - // if endpoint is not linking related, fail it. + if (![self isLinkingRelatedRequest:endpoint]) { [[BNCPreferenceHelper sharedInstance] clearTrackingInformation]; NSError *error = [NSError branchErrorWithCode:BNCTrackingDisabledError]; - [[BranchLogger shared] logWarning:[NSString stringWithFormat:@"Dropping Request %@: - %@", endpoint, error]]; + [[BranchLogger shared] logWarning:[NSString stringWithFormat:@"Dropping non-linking request"] error:error]; if (callback) { callback(nil, error); } @@ -178,12 +151,13 @@ - (void)genericHTTPRequest:(NSURLRequest *)request retryNumber:(NSInteger)retryN } } - id operation = - [self.networkService networkOperationWithURLRequest:request.copy completion:completionHandler]; + id operation = [self.networkService networkOperationWithURLRequest:request.copy completion:completionHandler]; [operation start]; + + // In the past we allowed clients to provide their own networking classes. NSError *error = [self verifyNetworkOperation:operation]; if (error) { - [[BranchLogger shared] logError:[NSString stringWithFormat:@"Network service error: %@.", error] error:error]; + [[BranchLogger shared] logError:@"NetworkService returned an operation that failed validation" error:error]; if (callback) { callback(nil, error); } @@ -214,7 +188,6 @@ - (BOOL)isLinkingRelatedRequest:(NSString *)endpoint { } - (NSError *)verifyNetworkOperation:(id)operation { - if (!operation) { NSString *message = @"A network operation instance is expected to be returned by the" " networkOperationWithURLRequest:completion: method."; @@ -278,27 +251,23 @@ - (NSURLRequest *)prepareGetRequest:(NSDictionary *)params url:(NSString *)url k NSDictionary *tmp = [self addRetryCount:retryNumber toJSON:params]; NSString *requestUrlString = [NSString stringWithFormat:@"%@%@", url, [BNCEncodingUtils encodeDictionaryToQueryString:tmp]]; - [[BranchLogger shared] logDebug:[NSString stringWithFormat:@"URL: %@", requestUrlString]]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:requestUrlString] cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:self.preferenceHelper.timeout]; [request setHTTPMethod:@"GET"]; [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; + [[BranchLogger shared] logDebug:[NSString stringWithFormat:@"%@\nHeaders %@", request, [request allHTTPHeaderFields]] error:nil]; + return request; } - (NSURLRequest *)preparePostRequest:(NSDictionary *)params url:(NSString *)url key:(NSString *)key retryNumber:(NSInteger)retryNumber { - NSDictionary *tmp = [self addRetryCount:retryNumber toJSON:params]; + NSDictionary *updatedParams = [self addRetryCount:retryNumber toJSON:params]; - NSData *postData = [BNCEncodingUtils encodeDictionaryToJsonData:tmp]; + NSData *postData = [BNCEncodingUtils encodeDictionaryToJsonData:updatedParams]; NSString *postLength = [NSString stringWithFormat:@"%lu", (unsigned long)[postData length]]; - - [[BranchLogger shared] logDebug:[NSString stringWithFormat:@"URL: %@.\n", url]]; - [[BranchLogger shared] logDebug:[NSString stringWithFormat:@"Body: %@\nJSON: %@.", - params, - [[NSString alloc] initWithData:postData encoding:NSUTF8StringEncoding]]]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url] @@ -309,6 +278,10 @@ - (NSURLRequest *)preparePostRequest:(NSDictionary *)params url:(NSString *)url [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; [request setHTTPBody:postData]; + if ([[BranchLogger shared] shouldLog:BranchLogLevelDebug]) { + [[BranchLogger shared] logDebug:[NSString stringWithFormat:@"%@\nHeaders %@\nBody %@", request, [request allHTTPHeaderFields], [BNCEncodingUtils prettyPrintJSON:updatedParams]] error:nil]; + } + return request; } @@ -321,15 +294,21 @@ - (BNCServerResponse *)processServerResponse:(NSURLResponse *)response data:(NSD serverResponse.statusCode = @([httpResponse statusCode]); serverResponse.data = [BNCEncodingUtils decodeJsonDataToDictionary:data]; serverResponse.requestId = requestId; - } - else { + + if ([[BranchLogger shared] shouldLog:BranchLogLevelDebug]) { + [[BranchLogger shared] logDebug:[NSString stringWithFormat:@"%@\nBody %@", response, [BNCEncodingUtils prettyPrintJSON:serverResponse.data]] error:nil]; + } + + } else { serverResponse.statusCode = @(error.code); serverResponse.data = error.userInfo; serverResponse.requestId = requestId; + + if ([[BranchLogger shared] shouldLog:BranchLogLevelDebug]) { + [[BranchLogger shared] logDebug:@"Request failed with NSError" error:error]; + } } - [[BranchLogger shared] logDebug:[NSString stringWithFormat:@"Server returned: %@.", serverResponse]]; - return serverResponse; } diff --git a/Sources/BranchSDK/BNCServerRequestQueue.m b/Sources/BranchSDK/BNCServerRequestQueue.m index dcc8ad8e0..3beb7136e 100755 --- a/Sources/BranchSDK/BNCServerRequestQueue.m +++ b/Sources/BranchSDK/BNCServerRequestQueue.m @@ -267,7 +267,7 @@ - (NSData *)archiveObject:(NSObject *)object { data = [NSKeyedArchiver archivedDataWithRootObject:object requiringSecureCoding:YES error:&error]; if (!data && error) { - [[BranchLogger shared] logWarning:[NSString stringWithFormat:@"Failed to archive: %@", error]]; + [[BranchLogger shared] logWarning:@"Failed to archive: %@" error:error]; } return data; } @@ -387,7 +387,7 @@ + (instancetype)getInstance { dispatch_once(&onceToken, ^ { sharedQueue = [[BNCServerRequestQueue alloc] init]; [sharedQueue retrieve]; - [[BranchLogger shared] logDebug:[NSString stringWithFormat:@"Retrieved from storage: %@.", sharedQueue]]; + [[BranchLogger shared] logVerbose:[NSString stringWithFormat:@"Retrieved from storage: %@.", sharedQueue] error:nil]; }); return sharedQueue; } diff --git a/Sources/BranchSDK/BNCSystemObserver.m b/Sources/BranchSDK/BNCSystemObserver.m index 9944bb409..1864caf95 100644 --- a/Sources/BranchSDK/BNCSystemObserver.m +++ b/Sources/BranchSDK/BNCSystemObserver.m @@ -31,6 +31,7 @@ @implementation BNCSystemObserver + (NSString *)appleAttributionToken { // token is not available on simulator if ([self isSimulator]) { + [[BranchLogger shared] logVerbose:[NSString stringWithFormat:@"AppleAttributionToken not available on simulator"] error:nil]; return nil; } @@ -54,7 +55,7 @@ + (NSString *)appleAttributionToken { // Apple said this API should respond within 50ms, lets give up after 500 ms dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(500 * NSEC_PER_MSEC))); if (token == nil) { - [[BranchLogger shared] logDebug:[NSString stringWithFormat:@"AppleAttributionToken request timed out"]]; + [[BranchLogger shared] logError:[NSString stringWithFormat:@"AppleAttributionToken request timed out"] error:nil]; } } #endif @@ -64,6 +65,7 @@ + (NSString *)appleAttributionToken { + (NSString *)advertiserIdentifier { #ifdef BRANCH_EXCLUDE_IDFA_CODE + [[BranchLogger shared] logDebug:[NSString stringWithFormat:@"BRANCH_EXCLUDE_IDFA_CODE flag enabled. IDFA is not available"] error:nil]; return nil; #else @@ -80,6 +82,7 @@ + (NSString *)advertiserIdentifier { (sharedManager, advertisingIdentifierSelector); uid = [uuid UUIDString]; if ([uid isEqualToString:@"00000000-0000-0000-0000-000000000000"]) { + [[BranchLogger shared] logVerbose:[NSString stringWithFormat:@"IDFA is all 0's. Probably running on a simulator or an App Clip."] error:nil]; uid = nil; } } @@ -92,6 +95,7 @@ + (NSString *)attOptedInStatus { NSString *statusString = @"unavailable"; #ifdef BRANCH_EXCLUDE_ATT_STATUS_CODE + [[BranchLogger shared] logDebug:[NSString stringWithFormat:@"BRANCH_EXCLUDE_IDFA_CODE flag enabled. ATT opt in status unavailable"] error:nil]; #else Class ATTrackingManagerClass = NSClassFromString(@"ATTrackingManager"); @@ -128,6 +132,8 @@ + (NSString *)defaultURIScheme { for (NSDictionary *urlType in urlTypes) { NSArray *urlSchemes = [urlType objectForKey:@"CFBundleURLSchemes"]; for (NSString *uriScheme in urlSchemes) { + + // TODO: Add a log to indicate that a URI was ignored due to a match with a known URI format if ([uriScheme hasPrefix:@"fb"]) continue; // Facebook if ([uriScheme hasPrefix:@"db"]) continue; // DB? if ([uriScheme hasPrefix:@"twitterkit-"]) continue; // Twitter @@ -151,6 +157,8 @@ + (NSString *)teamIdentifier { if (teamWithDot.length) { return [teamWithDot substringToIndex:([teamWithDot length] - 1)]; } + + [[BranchLogger shared] logVerbose:@"AppIdentifierPrefix not found in mainBundle" error:nil]; return nil; } diff --git a/Sources/BranchSDK/BNCURLFilter.m b/Sources/BranchSDK/BNCURLFilter.m index 367ba2ae3..65cf25ff5 100644 --- a/Sources/BranchSDK/BNCURLFilter.m +++ b/Sources/BranchSDK/BNCURLFilter.m @@ -11,6 +11,7 @@ #import "BNCURLFilter.h" #import "Branch.h" #import "BranchLogger.h" +#import "NSError+Branch.h" @interface BNCURLFilter () @@ -58,7 +59,7 @@ - (void)useDefaultPatternList { if (regex && !regexError) { [array addObject:regex]; } else { - [[BranchLogger shared] logError:[NSString stringWithFormat:@"Invalid regular expression '%@': %@.", pattern, regexError] error:regexError]; + [[BranchLogger shared] logError:[NSString stringWithFormat:@"Invalid regular expression '%@'", pattern] error:regexError]; } } return array; @@ -127,15 +128,15 @@ - (BOOL)foundUpdatedURLList:(id)operation { } if (statusCode == 404) { - [[BranchLogger shared] logDebug: [NSString stringWithFormat:@"No update for URL ignore list found."]]; + [[BranchLogger shared] logDebug:@"No update for URL ignore list found." error:nil]; return NO; - } else if (statusCode != 200 || error != nil || jsonString == nil) { - [[BranchLogger shared] logError:[NSString stringWithFormat:@"Failed to update URL ignore list. error: %@ status: %ld", operation.error, (long)operation.response.statusCode] error:operation.error]; - [[BranchLogger shared] logDebug: [NSString stringWithFormat:@"URL ignore JSON: %@", jsonString]]; - + if ([NSError branchDNSBlockingError:error]) { + [[BranchLogger shared] logWarning:@"Possible DNS Ad Blocker" error:error]; + } else { + [[BranchLogger shared] logWarning:@"Failed to update URL ignore list" error:operation.error]; + } return NO; - } else { return YES; } @@ -146,19 +147,21 @@ - (nullable NSDictionary *)parseJSONFromData:(NSData *)data { NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error]; if (error) { - [[BranchLogger shared] logError:[NSString stringWithFormat:@"Can't parse URL ignore JSON: %@.", error] error:error]; + [[BranchLogger shared] logWarning:@"Failed to parse uri_skip_list" error:error]; return nil; } + // Given the way this is currently designed, the server will return formats that will fail this check. + // Making this a verbose log until we have a chance to refactor this design. NSArray *urls = dictionary[@"uri_skip_list"]; if (![urls isKindOfClass:NSArray.class]) { - [[BranchLogger shared] logError:[NSString stringWithFormat:@"Can't parse URL ignore JSON, uri_skip_list is not a NSArray."] error:nil]; + [[BranchLogger shared] logVerbose:@"Failed to parse uri_skip_list is not a NSArray" error:nil]; return nil; } NSNumber *version = dictionary[@"version"]; if (![version isKindOfClass:NSNumber.class]) { - [[BranchLogger shared] logError:[NSString stringWithFormat:@"Can't parse URL ignore JSON, version is not a NSNumber."] error:nil]; + [[BranchLogger shared] logWarning:@"Failed to parse uri_skip_list, version is not a NSNumber." error:nil]; return nil; } diff --git a/Sources/BranchSDK/Branch.m b/Sources/BranchSDK/Branch.m index 984fbb40d..3ed78a771 100644 --- a/Sources/BranchSDK/Branch.m +++ b/Sources/BranchSDK/Branch.m @@ -90,6 +90,8 @@ #pragma mark - Load Categories +// Depending on linker settings, static compilation can omit ObjC categories leading to a runtime error. +// These no-op static initializers force the category to load. void ForceCategoriesToLoad(void); void ForceCategoriesToLoad(void) { BNCForceNSErrorCategoryToLoad(); @@ -235,8 +237,12 @@ - (id)initWithInterface:(BNCServerInterface *)interface BranchJsonConfig *config = BranchJsonConfig.instance; self.deferInitForPluginRuntime = config.deferInitForPluginRuntime; + if (config.apiUrl) { + [Branch setAPIUrl:config.apiUrl]; + } + if (config.enableLogging) { - [self enableLogging]; + [Branch enableLogging]; } if (config.checkPasteboardOnInstall) { @@ -251,7 +257,7 @@ - (id)initWithInterface:(BNCServerInterface *)interface + (void)setNetworkServiceClass:(Class)networkServiceClass { @synchronized ([Branch class]) { if (bnc_networkServiceClass) { - [[BranchLogger shared] logError:@"The Branch network service class is already set. It can be set only once." error:nil]; + [[BranchLogger shared] logError:@"The Branch network service class is already set. Ignoring attempt to set it again." error:nil]; return; } if (![networkServiceClass conformsToProtocol:@protocol(BNCNetworkServiceProtocol)]) { @@ -335,7 +341,7 @@ + (void)setBranchKey:(NSString *)branchKey { [self setBranchKey:branchKey error:&error]; if (error) { - [[BranchLogger shared] logError:[NSString stringWithFormat:@"Branch init error: %@", error.localizedDescription] error:error]; + [[BranchLogger shared] logError:@"Failed to set Branch Key" error:error]; } } @@ -366,7 +372,7 @@ + (void)setBranchKey:(NSString*)branchKey error:(NSError **)error { if ([branchKey hasPrefix:@"key_test"]) { bnc_useTestBranchKey = YES; - [[BranchLogger shared] logWarning: @"You are using your test app's Branch Key. Remember to change it to live Branch Key for production deployment."]; + [[BranchLogger shared] logWarning: @"You are using your test app's Branch Key. Remember to change it to live Branch Key for production deployment." error:nil]; } else if ([branchKey hasPrefix:@"key_live"]) { bnc_useTestBranchKey = NO; @@ -419,16 +425,26 @@ + (BOOL)branchKeyIsSet { } - (void)enableLogging { + [Branch enableLogging]; +} + +- (void)enableLoggingAtLevel:(BranchLogLevel)logLevel withCallback:(nullable BranchLogCallback)callback { + [Branch enableLoggingAtLevel:logLevel withCallback:callback]; +} + ++ (void)enableLogging { BranchLogger *logger = [BranchLogger shared]; logger.loggingEnabled = YES; logger.logLevelThreshold = BranchLogLevelDebug; } -- (void)enableLoggingAtLevel:(BranchLogLevel)logLevel withCallback:(nullable BranchLogCallback)callback { ++ (void)enableLoggingAtLevel:(BranchLogLevel)logLevel withCallback:(nullable BranchLogCallback)callback { BranchLogger *logger = [BranchLogger shared]; logger.loggingEnabled = YES; logger.logLevelThreshold = logLevel; - logger.logCallback = callback; + if (callback) { + logger.logCallback = callback; + } } - (void)useEUEndpoints { @@ -439,7 +455,7 @@ + (void)setAPIUrl:(NSString *)url { if ([url hasPrefix:@"http://"] || [url hasPrefix:@"https://"] ){ [BNCServerAPI sharedInstance].customAPIURL = url; } else { - [[BranchLogger shared] logWarning:(@"Ignoring invalid custom API URL")]; + [[BranchLogger shared] logWarning:@"Ignoring invalid custom API URL" error:nil]; } } @@ -566,8 +582,7 @@ - (void)initSessionWithLaunchOptions:(NSDictionary *)options automaticallyDispla #pragma mark - Actual Init Session -- (void)initSessionWithLaunchOptions:(NSDictionary *)options isReferrable:(BOOL)isReferrable explicitlyRequestedReferrable:(BOOL)explicitlyRequestedReferrable automaticallyDisplayController:(BOOL)automaticallyDisplayController registerDeepLinkHandlerUsingBranchUniversalObject:(callbackWithBranchUniversalObject)callback { - +- (void)initSessionWithLaunchOptions:(NSDictionary *)options isReferrable:(BOOL)isReferrable explicitlyRequestedReferrable:(BOOL)explicitlyRequestedReferrable automaticallyDisplayController:(BOOL)automaticallyDisplayController registerDeepLinkHandlerUsingBranchUniversalObject:(callbackWithBranchUniversalObject)callback { [self initSceneSessionWithLaunchOptions:options isReferrable:isReferrable explicitlyRequestedReferrable:explicitlyRequestedReferrable automaticallyDisplayController:automaticallyDisplayController registerDeepLinkHandler:^(BNCInitSessionResponse * _Nullable initResponse, NSError * _Nullable error) { if (callback) { @@ -581,7 +596,6 @@ - (void)initSessionWithLaunchOptions:(NSDictionary *)options isReferrable:(BOOL) } - (void)initSessionWithLaunchOptions:(NSDictionary *)options isReferrable:(BOOL)isReferrable explicitlyRequestedReferrable:(BOOL)explicitlyRequestedReferrable automaticallyDisplayController:(BOOL)automaticallyDisplayController registerDeepLinkHandler:(callbackWithParams)callback { - [self initSceneSessionWithLaunchOptions:options isReferrable:isReferrable explicitlyRequestedReferrable:explicitlyRequestedReferrable automaticallyDisplayController:automaticallyDisplayController registerDeepLinkHandler:^(BNCInitSessionResponse * _Nullable initResponse, NSError * _Nullable error) { if (callback) { @@ -633,7 +647,6 @@ - (void)initSessionWithLaunchOptions:(NSDictionary *)options } } -//these params will be added - (void)setDeepLinkDebugMode:(NSDictionary *)debugParams { self.deepLinkDebugParams = debugParams; } @@ -746,7 +759,6 @@ - (BOOL)sceneIdentifier:(NSString *)sceneIdentifier - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary *)options { - NSString *source = options[UIApplicationOpenURLOptionsSourceApplicationKey]; NSString *annotation = options[UIApplicationOpenURLOptionsAnnotationKey]; return [self application:application openURL:url sourceApplication:source annotation:annotation]; @@ -768,7 +780,6 @@ - (BOOL)continueUserActivity:(NSUserActivity *)userActivity { } - (BOOL)continueUserActivity:(NSUserActivity *)userActivity sceneIdentifier:(NSString *)sceneIdentifier { - if (userActivity.referrerURL) { self.preferenceHelper.initialReferrer = userActivity.referrerURL.absoluteString; } @@ -917,7 +928,7 @@ - (void)handleATTAuthorizationStatus:(NSUInteger)status { - (void)setSKAdNetworkCalloutMaxTimeSinceInstall:(NSTimeInterval)maxTimeInterval { if (@available(iOS 16.1, macCatalyst 16.1, *)) { - [[BranchLogger shared] logDebug:@"This is no longer supported for iOS 16.1+ - SKAN4.0"]; + [[BranchLogger shared] logDebug:@"Not supported SKAN 4.0+, iOS 16.1+" error:nil]; } else { [BNCSKAdNetwork sharedInstance].maxTimeSinceInstall = maxTimeInterval; } @@ -989,7 +1000,7 @@ - (void)logoutWithCallback:(callbackWithStatus)callback { (Branch.trackingDisabled) ? [NSError branchErrorWithCode:BNCTrackingDisabledError] : [NSError branchErrorWithCode:BNCInitError]; - [[BranchLogger shared] logError:@"Branch is not initialized, cannot logout." error:error]; + [[BranchLogger shared] logWarning:@"Branch is not initialized, cannot logout." error:error]; if (callback) {callback(NO, error);} return; } @@ -1399,7 +1410,7 @@ - (void)passPasteItemProviders:(NSArray *)itemProviders { // 2. Check if URL is branch URL and if yes -> store it. [item loadItemForTypeIdentifier:UTTypeURL.identifier options:NULL completionHandler:^(NSURL *url, NSError * _Null_unspecified error) { if (error) { - [[BranchLogger shared] logError:[NSString stringWithFormat:@"%@", error] error:error]; + [[BranchLogger shared] logWarning:@"Failed to load URL from Pasteboard" error:error]; } else if ([Branch isBranchLink:url.absoluteString]) { [self.preferenceHelper setLocalUrl:[url absoluteString]]; @@ -1425,7 +1436,7 @@ + (Branch *)getInstanceInternal:(NSString *)key { // If there was stored key and it isn't the same as the currently used (or doesn't exist), we need to clean up // Note: Link Click Identifier is not cleared because of the potential for that to mess up a deep link if (preferenceHelper.lastRunBranchKey && ![key isEqualToString:preferenceHelper.lastRunBranchKey]) { - [[BranchLogger shared] logWarning:@"The Branch Key has changed, clearing relevant items."]; + [[BranchLogger shared] logWarning:@"The Branch Key has changed, clearing relevant items." error:nil]; preferenceHelper.appVersion = nil; preferenceHelper.randomizedDeviceToken = nil; preferenceHelper.sessionID = nil; @@ -1538,6 +1549,8 @@ - (NSString *)generateShortUrl:(NSArray *)tags // If an ignore UA string is present, we always get a new url. // Otherwise, if we've already seen this request, use the cached version. if (!ignoreUAString && [self.linkCache objectForKey:linkData]) { + [[BranchLogger shared] logVerbose:@"Returning cached Branch Link" error:nil]; + shortURL = [self.linkCache objectForKey:linkData]; } else { BranchShortUrlSyncRequest *req = @@ -1554,7 +1567,7 @@ - (NSString *)generateShortUrl:(NSArray *)tags linkData:linkData linkCache:self.linkCache]; - [[BranchLogger shared] logDebug:@"Creating a custom URL synchronously."]; + [[BranchLogger shared] logVerbose:@"Requesting Branch Link synchronously" error:nil]; BNCServerResponse *serverResponse = [req makeRequest:self.serverInterface key:self.class.branchKey]; shortURL = [req processResponse:serverResponse]; @@ -1772,7 +1785,7 @@ - (void) processRequest:(BNCServerRequest*)req } // On network problems, or Branch down, call the other callbacks and stop processing. else { - [[BranchLogger shared] logDebug:@"Network error: failing queued requests."]; + [[BranchLogger shared] logDebug:@"Network error: failing queued requests." error:nil]; // First, gather all the requests to fail NSMutableArray *requestsToFail = [[NSMutableArray alloc] init]; for (int i = 0; i < self.requestQueue.queueDepth; i++) { @@ -1888,11 +1901,13 @@ - (BOOL)deferInitBlock:(void (^)(void))block { BOOL deferred = NO; @synchronized (self) { if (self.deferInitForPluginRuntime) { + [[BranchLogger shared] logDebug:@"Deferring SDK init until notifyNativeToInit is called" error:nil]; self.cachedInitBlock = block; deferred = YES; } } + // handle default non-deferred state if (!deferred && block) { block(); } @@ -1902,6 +1917,7 @@ - (BOOL)deferInitBlock:(void (^)(void))block { // Releases deferred init block - (void)notifyNativeToInit { @synchronized (self) { + [[BranchLogger shared] logDebug:@"Unlocking Deferred SDK init" error:nil]; self.deferInitForPluginRuntime = NO; } @@ -1915,7 +1931,7 @@ - (void)notifyNativeToInit { // Some methods require init before they are called. Instead of returning an error, we try to fix the situation by calling init ourselves. - (void)initSafetyCheck { if (self.initializationStatus == BNCInitStatusUninitialized) { - [[BranchLogger shared] logDebug:@"Branch avoided an error by preemptively initializing."]; + [[BranchLogger shared] logDebug:@"Branch avoided an error by preemptively initializing." error:nil]; [self initUserSessionAndCallCallback:NO sceneIdentifier:nil urlString:nil]; } } @@ -1925,7 +1941,7 @@ - (void)initUserSessionAndCallCallback:(BOOL)callCallback sceneIdentifier:(NSStr // ignore lifecycle calls while waiting for a plugin runtime. @synchronized (self) { if (self.deferInitForPluginRuntime) { - [[BranchLogger shared] logDebug:@"Branch init is deferred, ignoring init call."]; + [[BranchLogger shared] logDebug:@"Branch init is deferred, ignoring init call." error:nil]; return; } } @@ -1997,8 +2013,8 @@ - (void)initializeSessionAndCallCallback:(BOOL)callCallback sceneIdentifier:(NSS [self.requestQueue insert:req at:0]; - NSString *message = [NSString stringWithFormat:@"request %@ callback %@ link %@", req, req.callback, req.urlString]; - [[BranchLogger shared] logDebug:message]; + NSString *message = [NSString stringWithFormat:@"Request %@ callback %@ link %@", req, req.callback, req.urlString]; + [[BranchLogger shared] logDebug:message error:nil]; } else { @@ -2011,9 +2027,9 @@ - (void)initializeSessionAndCallCallback:(BOOL)callCallback sceneIdentifier:(NSS // put it behind the one that's already on queue [self.requestQueue insert:req at:1]; - [[BranchLogger shared] logDebug:@"Link resolution request"]; - NSString *message = [NSString stringWithFormat:@"request %@ callback %@ link %@", req, req.callback, req.urlString]; - [[BranchLogger shared] logDebug:message]; + [[BranchLogger shared] logDebug:@"Link resolution request" error:nil]; + NSString *message = [NSString stringWithFormat:@"Request %@ callback %@ link %@", req, req.callback, req.urlString]; + [[BranchLogger shared] logDebug:message error:nil]; } } @@ -2082,7 +2098,7 @@ - (void)automaticallyDeeplinkWithReferringParams:(NSDictionary *)latestReferring [branchSharingController configureControlWithData:latestReferringParams]; } else { - [[BranchLogger shared] logWarning:[NSString stringWithFormat:@"The automatic deeplink view controller '%@' for key '%@' does not implement 'configureControlWithData:'.", branchSharingController, key]]; + [[BranchLogger shared] logWarning:[NSString stringWithFormat:@"The automatic deeplink view controller '%@' for key '%@' does not implement 'configureControlWithData:'.", branchSharingController, key] error:nil]; } self.deepLinkPresentingController = [UIViewController bnc_currentViewController]; @@ -2094,7 +2110,7 @@ - (void)automaticallyDeeplinkWithReferringParams:(NSDictionary *)latestReferring [branchSharingController configureControlWithData:latestReferringParams]; } else { - [[BranchLogger shared] logWarning:@"View controller does not implement configureControlWithData:"]; + [[BranchLogger shared] logWarning:@"View controller does not implement configureControlWithData:" error:nil]; } branchSharingController.deepLinkingCompletionDelegate = self; switch (deepLinkInstance.option) { @@ -2156,7 +2172,7 @@ - (void)automaticallyDeeplinkWithReferringParams:(NSDictionary *)latestReferring [branchSharingController configureControlWithData:latestReferringParams]; } else { - [[BranchLogger shared] logWarning:@"View controller does not implement configureControlWithData:"]; + [[BranchLogger shared] logWarning:@"View controller does not implement configureControlWithData:" error:nil]; } branchSharingController.deepLinkingCompletionDelegate = self; if ([self.deepLinkPresentingController presentedViewController]) { diff --git a/Sources/BranchSDK/BranchCSSearchableItemAttributeSet.m b/Sources/BranchSDK/BranchCSSearchableItemAttributeSet.m index 0465b81f7..b5b94844b 100644 --- a/Sources/BranchSDK/BranchCSSearchableItemAttributeSet.m +++ b/Sources/BranchSDK/BranchCSSearchableItemAttributeSet.m @@ -45,7 +45,7 @@ - (instancetype)initWithItemContentType:(nonnull NSString *)type { - (void)setIdentifier:(NSString *)identifier { if (![identifier hasPrefix:BRANCH_SPOTLIGHT_PREFIX]) { - [[BranchLogger shared] logWarning:@"Do not set BranchCSSearchableItemAttributeSet's identifier. It will be overwritten."]; + [[BranchLogger shared] logWarning:@"Do not set BranchCSSearchableItemAttributeSet's identifier. It will be overwritten." error:nil]; } } diff --git a/Sources/BranchSDK/BranchEvent.m b/Sources/BranchSDK/BranchEvent.m index 0dd108ef1..e7634173f 100644 --- a/Sources/BranchSDK/BranchEvent.m +++ b/Sources/BranchSDK/BranchEvent.m @@ -97,13 +97,13 @@ - (void)processResponse:(BNCServerResponse*)response error:(NSError*)error { BOOL lockWin = [[BNCSKAdNetwork sharedInstance] getLockedStatusFromDataResponse:dictionary]; BOOL shouldCallUpdatePostback = [[BNCSKAdNetwork sharedInstance] shouldCallPostbackForDataResponse:dictionary]; - [[BranchLogger shared] logDebug:[NSString stringWithFormat:@"SKAN 4.0 params - conversionValue:%@ coarseValue:%@, locked:%d, shouldCallPostback:%d, currentWindow:%d, firstAppLaunchTime: %@", conversionValue, coarseConversionValue, lockWin, shouldCallUpdatePostback, (int)[BNCPreferenceHelper sharedInstance].skanCurrentWindow, [BNCPreferenceHelper sharedInstance].firstAppLaunchTime]]; + [[BranchLogger shared] logDebug:[NSString stringWithFormat:@"SKAN 4.0 params - conversionValue:%@ coarseValue:%@, locked:%d, shouldCallPostback:%d, currentWindow:%d, firstAppLaunchTime: %@", conversionValue, coarseConversionValue, lockWin, shouldCallUpdatePostback, (int)[BNCPreferenceHelper sharedInstance].skanCurrentWindow, [BNCPreferenceHelper sharedInstance].firstAppLaunchTime] error:nil]; if(shouldCallUpdatePostback){ [[BNCSKAdNetwork sharedInstance] updatePostbackConversionValue: conversionValue.longValue coarseValue:coarseConversionValue lockWindow:lockWin completionHandler:^(NSError * _Nullable error) { if (error) { [[BranchLogger shared] logError:[NSString stringWithFormat:@"Update conversion value failed with error - %@", [error description]] error:error]; } else { - [[BranchLogger shared] logDebug:[NSString stringWithFormat:@"Update conversion value was successful. Conversion Value - %@", conversionValue]]; + [[BranchLogger shared] logDebug:[NSString stringWithFormat:@"Update conversion value was successful. Conversion Value - %@", conversionValue] error:nil]; } }]; } @@ -113,7 +113,7 @@ - (void)processResponse:(BNCServerResponse*)response error:(NSError*)error { if (error) { [[BranchLogger shared] logError:[NSString stringWithFormat:@"Update conversion value failed with error - %@", [error description]] error:error]; } else { - [[BranchLogger shared] logDebug:[NSString stringWithFormat:@"Update conversion value was successful. Conversion Value - %@", conversionValue]]; + [[BranchLogger shared] logDebug:[NSString stringWithFormat:@"Update conversion value was successful. Conversion Value - %@", conversionValue] error:nil]; } }]; } else { @@ -452,7 +452,7 @@ - (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProdu } [self logEvent]; - [[BranchLogger shared] logDebug:[NSString stringWithFormat:@"Created and logged event from transaction: %@", self.description]]; + [[BranchLogger shared] logDebug:[NSString stringWithFormat:@"Created and logged event from transaction: %@", self.description] error:nil]; } else { [[BranchLogger shared] logError:[NSString stringWithFormat:@"Unable to log Branch event from transaction. No products were found with the product ID."] error:nil]; } diff --git a/Sources/BranchSDK/BranchJsonConfig.m b/Sources/BranchSDK/BranchJsonConfig.m index aa3bbb077..430c6b859 100644 --- a/Sources/BranchSDK/BranchJsonConfig.m +++ b/Sources/BranchSDK/BranchJsonConfig.m @@ -17,6 +17,8 @@ NSString * _Nonnull const BranchJsonConfigDeferInitForPluginRuntimeOption = @"deferInitForPluginRuntime"; NSString * _Nonnull const BranchJsonConfigEnableLogging = @"enableLogging"; NSString * _Nonnull const BranchJsonConfigCheckPasteboardOnInstall = @"checkPasteboardOnInstall"; +NSString * _Nonnull const BranchJsonConfigAPIUrl = @"apiUrl"; + @interface BranchJsonConfig() @property (nonatomic, strong) NSDictionary *configuration; @@ -56,13 +58,12 @@ - (void)loadConfigFile NSError *error; id object = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error]; if (!object || error) { - [[BranchLogger shared] logError:[NSString stringWithFormat:@"Failed to parse branch.json. Error: %@", error.localizedDescription] error:error]; + [[BranchLogger shared] logError:@"Failed to parse branch.json" error:error]; return; } if (![object isKindOfClass:NSDictionary.class]) { [[BranchLogger shared] logError:@"Contents of branch.json should be a JSON object." error:nil]; - return; } @@ -72,11 +73,10 @@ - (void)loadConfigFile - (NSData *)configFileContents { if (!self.configFileURL) return nil; - [[BranchLogger shared] logDebug:[NSString stringWithFormat:@"Loading %@", self.configFileURL.pathComponents.lastObject]]; NSError *error; NSData *data = [NSData dataWithContentsOfURL:self.configFileURL options:0 error:&error]; if (!data || error) { - [[BranchLogger shared] logError:[NSString stringWithFormat:@"Failed to load %@. Error: %@", self.configFileURL, error.localizedDescription] error:error]; + [[BranchLogger shared] logError:@"Failed to load branch.json" error:error]; return nil; } return data; @@ -109,7 +109,7 @@ - (void)findConfigFile } if (!configFileURL) { - [[BranchLogger shared] logDebug:@"No branch.json in app bundle."]; + [[BranchLogger shared] logVerbose:@"No branch.json in app bundle" error:nil]; return; } @@ -161,6 +161,11 @@ - (NSString *)testKey return self[BranchJsonConfigTestKeyOption]; } +- (NSString *)apiUrl +{ + return self[BranchJsonConfigAPIUrl]; +} + - (id)objectForKey:(NSString *)key { return self.configuration[key]; diff --git a/Sources/BranchSDK/BranchLastAttributedTouchData.m b/Sources/BranchSDK/BranchLastAttributedTouchData.m index 99316a32d..85bc3e0ab 100644 --- a/Sources/BranchSDK/BranchLastAttributedTouchData.m +++ b/Sources/BranchSDK/BranchLastAttributedTouchData.m @@ -33,7 +33,7 @@ + (void)requestLastTouchAttributedData:(BNCServerInterface *)serverInterface key if (window > -1 && window < 365) { request.attributionWindow = window; } else { - [[BranchLogger shared] logWarning:@"Attribution window is outside the expected range, using 30 days."]; + [[BranchLogger shared] logWarning:@"Attribution window is outside the expected range, using 30 days" error:nil]; } [request makeRequest:serverInterface key:key callback:^(BNCServerResponse *response, NSError *error) { diff --git a/Sources/BranchSDK/BranchLogger.m b/Sources/BranchSDK/BranchLogger.m index e85a16fad..3f5038b57 100644 --- a/Sources/BranchSDK/BranchLogger.m +++ b/Sources/BranchSDK/BranchLogger.m @@ -16,6 +16,15 @@ - (instancetype)init { _loggingEnabled = NO; _logLevelThreshold = BranchLogLevelDebug; _includeCallerDetails = YES; + + // default callback sends logs to os_log + _logCallback = ^(NSString * _Nonnull message, BranchLogLevel logLevel, NSError * _Nullable error) { + NSString *formattedMessage = [BranchLogger formatMessage:message logLevel:logLevel error:error]; + + os_log_t log = os_log_create("io.branch.sdk", "BranchSDK"); + os_log_type_t osLogType = [BranchLogger osLogTypeForBranchLogLevel:logLevel]; + os_log_with_type(log, osLogType, "%{private}@", formattedMessage); + }; } return self; } @@ -32,6 +41,13 @@ + (instancetype)shared { return sharedInstance; } +- (BOOL)shouldLog:(BranchLogLevel)level { + if (!self.loggingEnabled || level < self.logLevelThreshold) { + return NO; + } + return YES; +} + - (void)disableCallerDetails { self.includeCallerDetails = NO; } @@ -40,80 +56,76 @@ - (void)logError:(NSString *)message error:(NSError *_Nullable)error { [self logMessage:message withLevel:BranchLogLevelError error:error]; } -- (void)logWarning:(NSString *)message { - [self logMessage:message withLevel:BranchLogLevelWarning error:nil]; -} - -- (void)logInfo:(NSString *)message { - [self logMessage:message withLevel:BranchLogLevelInfo error:nil]; +- (void)logWarning:(NSString *)message error:(NSError *_Nullable)error { + [self logMessage:message withLevel:BranchLogLevelWarning error:error]; } -- (void)logDebug:(NSString *)message { - [self logMessage:message withLevel:BranchLogLevelDebug error:nil]; +- (void)logDebug:(NSString *)message error:(NSError *_Nullable)error { + [self logMessage:message withLevel:BranchLogLevelDebug error:error]; } -- (void)logVerbose:(NSString *)message { - [self logMessage:message withLevel:BranchLogLevelVerbose error:nil]; +- (void)logVerbose:(NSString *)message error:(NSError *_Nullable)error { + [self logMessage:message withLevel:BranchLogLevelVerbose error:error]; } - (void)logMessage:(NSString *)message withLevel:(BranchLogLevel)level error:(NSError *_Nullable)error { - if (!self.loggingEnabled || message.length == 0 || level < self.logLevelThreshold) { + if (!self.loggingEnabled || level < self.logLevelThreshold || message.length == 0) { return; } - NSString *callerDetails = self.includeCallerDetails ? [self callingClass] : @""; - NSString *logLevelString = [self stringForLogLevel:level]; - NSString *logTag = [NSString stringWithFormat:@"[BranchSDK][%@]", logLevelString]; - NSMutableString *fullMessage = [NSMutableString stringWithFormat:@"%@%@ %@", logTag, callerDetails, message]; - - if (error) { - [fullMessage appendFormat:@", Error: %@ (Domain: %@, Code: %ld)", error.localizedDescription, error.domain, (long)error.code]; + NSString *formattedMessage = message; + if (self.includeCallerDetails) { + formattedMessage = [NSString stringWithFormat:@"%@ %@", [self callingClass], message]; } if (self.logCallback) { - self.logCallback(fullMessage, level, error); - } else { - os_log_t log = os_log_create("io.branch.sdk", "BranchSDK"); - os_log_type_t osLogType = [self osLogTypeForBranchLogLevel:level]; - os_log_with_type(log, osLogType, "%{private}@", fullMessage); + self.logCallback(formattedMessage, level, error); } } -//MARK: Helper Methods -- (os_log_type_t)osLogTypeForBranchLogLevel:(BranchLogLevel)level { - switch (level) { - case BranchLogLevelError: return OS_LOG_TYPE_FAULT; - case BranchLogLevelWarning: return OS_LOG_TYPE_ERROR; - case BranchLogLevelInfo: return OS_LOG_TYPE_INFO; - case BranchLogLevelDebug: return OS_LOG_TYPE_DEBUG; - case BranchLogLevelVerbose: return OS_LOG_TYPE_DEFAULT; - default: return OS_LOG_TYPE_DEFAULT; +- (NSString *)callingClass { + NSArray *stackSymbols = [NSThread callStackSymbols]; + NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"\\[([^\\]]+)\\]" options:0 error:nil]; + if (stackSymbols.count > 3 && regex) { + NSString *callSite = stackSymbols[3]; + NSTextCheckingResult *match = [regex firstMatchInString:callSite options:0 range:NSMakeRange(0, [callSite length])]; + if (match && match.range.location != NSNotFound) { + NSString *callerDetails = [callSite substringWithRange:[match rangeAtIndex:0]]; + return callerDetails; + } } + return @""; +} + ++ (NSString *)formatMessage:(NSString *)message logLevel:(BranchLogLevel)logLevel error:(NSError *)error { + NSString *logLevelString = [BranchLogger stringForLogLevel:logLevel]; + NSString *logTag = [NSString stringWithFormat:@"[BranchSDK][%@]", logLevelString]; + NSMutableString *fullMessage = [NSMutableString stringWithFormat:@"%@%@", logTag, message]; + if (error) { + [fullMessage appendFormat:@" NSError: %@", error]; + } + return fullMessage; } -- (NSString *)stringForLogLevel:(BranchLogLevel)level { ++ (NSString *)stringForLogLevel:(BranchLogLevel)level { switch (level) { case BranchLogLevelVerbose: return @"Verbose"; case BranchLogLevelDebug: return @"Debug"; - case BranchLogLevelInfo: return @"Info"; case BranchLogLevelWarning: return @"Warning"; case BranchLogLevelError: return @"Error"; default: return @"Unknown"; } } -- (NSString *)callingClass { - NSArray *stackSymbols = [NSThread callStackSymbols]; - NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"\\[([^\\]]+)\\]" options:0 error:nil]; - if (stackSymbols.count > 3 && regex) { - NSString *callSite = stackSymbols[3]; - NSTextCheckingResult *match = [regex firstMatchInString:callSite options:0 range:NSMakeRange(0, [callSite length])]; - if (match && match.range.location != NSNotFound) { - NSString *callerDetails = [callSite substringWithRange:[match rangeAtIndex:0]]; - return callerDetails; - } +// Map the Branch log level to a similar Apple log level ++ (os_log_type_t)osLogTypeForBranchLogLevel:(BranchLogLevel)level { + switch (level) { + case BranchLogLevelError: return OS_LOG_TYPE_ERROR; // "report process-level errors" + case BranchLogLevelWarning: return OS_LOG_TYPE_DEFAULT; // "things that might result in a failure" + case BranchLogLevelDebug: return OS_LOG_TYPE_INFO; // "helpful, but not essential, for troubleshooting errors" + case BranchLogLevelVerbose: return OS_LOG_TYPE_DEBUG; // "useful during development or while troubleshooting a specific problem" + default: return OS_LOG_TYPE_DEFAULT; } - return @""; } @end diff --git a/Sources/BranchSDK/BranchOpenRequest.m b/Sources/BranchSDK/BranchOpenRequest.m index 38533f8fe..96a6f7110 100644 --- a/Sources/BranchSDK/BranchOpenRequest.m +++ b/Sources/BranchSDK/BranchOpenRequest.m @@ -102,11 +102,11 @@ - (void)processResponse:(BNCServerResponse *)response error:(NSError *)error { if (sessionData == nil || [sessionData isKindOfClass:[NSString class]]) { } else if ([sessionData isKindOfClass:[NSDictionary class]]) { - [[BranchLogger shared] logWarning:[NSString stringWithFormat:@"Received session data of type '%@' data is '%@'.", NSStringFromClass(sessionData.class), sessionData]]; + [[BranchLogger shared] logWarning:[NSString stringWithFormat:@"Received session data of type '%@' data is '%@'.", NSStringFromClass(sessionData.class), sessionData] error:nil]; sessionData = [BNCEncodingUtils encodeDictionaryToJsonString:(NSDictionary*)sessionData]; } else if ([sessionData isKindOfClass:[NSArray class]]) { - [[BranchLogger shared] logWarning:[NSString stringWithFormat:@"Received session data of type '%@' data is '%@'.", NSStringFromClass(sessionData.class), sessionData]]; + [[BranchLogger shared] logWarning:[NSString stringWithFormat:@"Received session data of type '%@' data is '%@'.", NSStringFromClass(sessionData.class), sessionData] error:nil]; sessionData = [BNCEncodingUtils encodeArrayToJsonString:(NSArray*)sessionData]; } else { [[BranchLogger shared] logError:[NSString stringWithFormat:@"Received session data of type '%@' data is '%@'.", NSStringFromClass(sessionData.class), sessionData] error:error]; @@ -188,7 +188,7 @@ - (void)processResponse:(BNCServerResponse *)response error:(NSError *)error { if (error) { [[BranchLogger shared] logError:[NSString stringWithFormat:@"Update conversion value failed with error - %@", [error description]] error:error]; } else { - [[BranchLogger shared] logDebug:[NSString stringWithFormat:@"Update conversion value was successful for INSTALL Event"]]; + [[BranchLogger shared] logDebug:[NSString stringWithFormat:@"Update conversion value was successful for INSTALL Event"] error:nil]; } }]; } else if (@available(iOS 15.4, macCatalyst 15.4, *)){ @@ -196,7 +196,7 @@ - (void)processResponse:(BNCServerResponse *)response error:(NSError *)error { if (error) { [[BranchLogger shared] logError:[NSString stringWithFormat:@"Update conversion value failed with error - %@", [error description]] error:error]; } else { - [[BranchLogger shared] logDebug:[NSString stringWithFormat:@"Update conversion value was successful for INSTALL Event"]]; + [[BranchLogger shared] logDebug:[NSString stringWithFormat:@"Update conversion value was successful for INSTALL Event"] error:nil]; } }]; } @@ -218,14 +218,14 @@ - (void)processResponse:(BNCServerResponse *)response error:(NSError *)error { BOOL lockWin = [[BNCSKAdNetwork sharedInstance] getLockedStatusFromDataResponse:data]; BOOL shouldCallUpdatePostback = [[BNCSKAdNetwork sharedInstance] shouldCallPostbackForDataResponse:data]; - [[BranchLogger shared] logDebug: [NSString stringWithFormat:@"SKAN 4.0 params - conversionValue:%@ coarseValue:%@, locked:%d, shouldCallPostback:%d, currentWindow:%d, firstAppLaunchTime: %@", conversionValue, coarseConversionValue, lockWin, shouldCallUpdatePostback, (int)preferenceHelper.skanCurrentWindow, preferenceHelper.firstAppLaunchTime]]; + [[BranchLogger shared] logDebug: [NSString stringWithFormat:@"SKAN 4.0 params - conversionValue:%@ coarseValue:%@, locked:%d, shouldCallPostback:%d, currentWindow:%d, firstAppLaunchTime: %@", conversionValue, coarseConversionValue, lockWin, shouldCallUpdatePostback, (int)preferenceHelper.skanCurrentWindow, preferenceHelper.firstAppLaunchTime] error:nil]; if(shouldCallUpdatePostback){ [[BNCSKAdNetwork sharedInstance] updatePostbackConversionValue: conversionValue.longValue coarseValue:coarseConversionValue lockWindow:lockWin completionHandler:^(NSError * _Nullable error) { if (error) { [[BranchLogger shared] logError:[NSString stringWithFormat:@"Update conversion value failed with error - %@", [error description]] error:error]; } else { - [[BranchLogger shared] logDebug:[NSString stringWithFormat:@"Update conversion value was successful. Conversion Value - %@", conversionValue]]; + [[BranchLogger shared] logDebug:[NSString stringWithFormat:@"Update conversion value was successful. Conversion Value - %@", conversionValue] error:nil]; } }]; } @@ -234,7 +234,7 @@ - (void)processResponse:(BNCServerResponse *)response error:(NSError *)error { if (error) { [[BranchLogger shared] logError:[NSString stringWithFormat:@"Update conversion value failed with error - %@", [error description]] error:error]; } else { - [[BranchLogger shared] logDebug:[NSString stringWithFormat:@"Update conversion value was successful. Conversion Value - %@", conversionValue]]; + [[BranchLogger shared] logDebug:[NSString stringWithFormat:@"Update conversion value was successful. Conversion Value - %@", conversionValue] error:nil]; } }]; } else { @@ -292,7 +292,7 @@ + (void) initialize { + (void) setWaitNeededForOpenResponseLock { @synchronized (self) { if (!openRequestWaitQueueIsSuspended) { - [[BranchLogger shared] logDebug:@"Suspended for openRequestWaitQueue."]; + [[BranchLogger shared] logVerbose:@"Suspended for openRequestWaitQueue." error:nil]; openRequestWaitQueueIsSuspended = YES; dispatch_suspend(openRequestWaitQueue); } @@ -300,16 +300,16 @@ + (void) setWaitNeededForOpenResponseLock { } + (void) waitForOpenResponseLock { - [[BranchLogger shared] logDebug:@"Waiting for openRequestWaitQueue."]; + [[BranchLogger shared] logVerbose:@"Waiting for openRequestWaitQueue." error:nil]; dispatch_sync(openRequestWaitQueue, ^ { - [[BranchLogger shared] logDebug:@"Finished waitForOpenResponseLock."]; + [[BranchLogger shared] logVerbose:@"Finished waitForOpenResponseLock." error:nil]; }); } + (void) releaseOpenResponseLock { @synchronized (self) { if (openRequestWaitQueueIsSuspended) { - [[BranchLogger shared] logDebug:@"Resuming openRequestWaitQueue."]; + [[BranchLogger shared] logVerbose:@"Resuming openRequestWaitQueue." error:nil]; openRequestWaitQueueIsSuspended = NO; dispatch_resume(openRequestWaitQueue); } diff --git a/Sources/BranchSDK/BranchQRCode.m b/Sources/BranchSDK/BranchQRCode.m index 1e55e35e4..b88bfe068 100644 --- a/Sources/BranchSDK/BranchQRCode.m +++ b/Sources/BranchSDK/BranchQRCode.m @@ -35,11 +35,11 @@ - (instancetype) init { - (void) setMargin:(NSNumber *)margin { if (margin.intValue > 20) { margin = @(20); - [[BranchLogger shared] logWarning:@"QR code margin was reduced to the maximum of 20."]; + [[BranchLogger shared] logWarning:@"QR code margin was reduced to the maximum of 20." error:nil]; } if (margin.intValue < 1) { margin = @(1); - [[BranchLogger shared] logWarning:@"QR code margin was increased to the minimum of 1."]; + [[BranchLogger shared] logWarning:@"QR code margin was increased to the minimum of 1." error:nil]; } _margin = margin; } @@ -47,11 +47,11 @@ - (void) setMargin:(NSNumber *)margin { - (void) setWidth:(NSNumber *)width { if (width.intValue > 2000) { width = @(2000); - [[BranchLogger shared] logWarning:@"QR code width was reduced to the maximum of 2000."]; + [[BranchLogger shared] logWarning:@"QR code width was reduced to the maximum of 2000." error:nil]; } if (width.intValue < 300) { width = @(300); - [[BranchLogger shared] logWarning:@"QR code width was increased to the minimum of 500."]; + [[BranchLogger shared] logWarning:@"QR code width was increased to the minimum of 500." error:nil]; } _width = width; } @@ -73,7 +73,7 @@ - (void)getQRCodeAsData:(nullable BranchUniversalObject *)buo NSData *data=[NSData dataWithContentsOfURL:[NSURL URLWithString: self.centerLogo]]; UIImage *image=[UIImage imageWithData:data]; if (image == nil) { - [[BranchLogger shared] logWarning:@"QR code center logo was an invalid URL string."]; + [[BranchLogger shared] logWarning:@"QR code center logo was an invalid URL string." error:nil]; } else { settings[@"center_logo_url"] = self.centerLogo; } @@ -137,25 +137,28 @@ - (void)callQRCodeAPI:(nullable NSDictionary *)params NSData *postData = [NSJSONSerialization dataWithJSONObject:params options:0 error:&error]; [request setHTTPBody:postData]; - [[BranchLogger shared] logDebug:[NSString stringWithFormat:@"Network start operation %@.", request.URL.absoluteString]]; + [[BranchLogger shared] logDebug:[NSString stringWithFormat:@"Network start operation %@.", request.URL.absoluteString] error:nil]; NSDate *startDate = [NSDate date]; NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { if (error) { - [[BranchLogger shared] logError:[NSString stringWithFormat:@"QR Code Post Request Error: %@", [error localizedDescription]] error:error]; - completion(nil, error); + if ([NSError branchDNSBlockingError:error]) { + [[BranchLogger shared] logWarning:@"Possible DNS Ad Blocker" error:error]; + } else { + [[BranchLogger shared] logError:@"QR Code request failed" error:error]; + completion(nil, error); + } return; } NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; if (httpResponse.statusCode == 200) { - [[BranchLogger shared] logDebug:[NSString stringWithFormat:@"Network finish operation %@ %1.3fs. Status %ld.", request.URL.absoluteString, [[NSDate date] timeIntervalSinceDate:startDate], - (long)httpResponse.statusCode]]; + (long)httpResponse.statusCode] error:nil]; completion(data, nil); } else { diff --git a/Sources/BranchSDK/BranchScene.m b/Sources/BranchSDK/BranchScene.m index f6c8480b4..c4f3a2f53 100644 --- a/Sources/BranchSDK/BranchScene.m +++ b/Sources/BranchSDK/BranchScene.m @@ -22,6 +22,8 @@ + (BranchScene *)shared NS_EXTENSION_UNAVAILABLE("BranchScene does not support E } - (void)initSessionWithLaunchOptions:(nullable NSDictionary *)options registerDeepLinkHandler:(void (^ _Nonnull)(NSDictionary * _Nullable params, NSError * _Nullable error, UIScene * _Nullable scene))callback NS_EXTENSION_UNAVAILABLE("BranchScene does not support Extensions") { + [[BranchLogger shared] logVerbose:@"BranchScene initSession" error:nil]; + [[Branch getInstance] initSceneSessionWithLaunchOptions:options isReferrable:YES explicitlyRequestedReferrable:NO automaticallyDisplayController:NO registerDeepLinkHandler:^(BNCInitSessionResponse * _Nullable initResponse, NSError * _Nullable error) { if (callback) { if (initResponse) { @@ -34,13 +36,17 @@ - (void)initSessionWithLaunchOptions:(nullable NSDictionary *)options registerDe } - (void)scene:(UIScene *)scene continueUserActivity:(NSUserActivity *)userActivity NS_EXTENSION_UNAVAILABLE("BranchScene does not support Extensions") { + [[BranchLogger shared] logVerbose:@"BranchScene continueUserActivity" error:nil]; + NSString *identifier = scene.session.persistentIdentifier; [[Branch getInstance] continueUserActivity:userActivity sceneIdentifier:identifier]; } - (void)scene:(UIScene *)scene openURLContexts:(NSSet *)URLContexts NS_EXTENSION_UNAVAILABLE("BranchScene does not support Extensions") { + [[BranchLogger shared] logVerbose:@"BranchScene openURLContexts" error:nil]; + if (URLContexts.count != 1) { - [[BranchLogger shared] logWarning:@"Branch only supports a single URLContext"]; + [[BranchLogger shared] logWarning:@"Branch only supports a single URLContext" error:nil]; } UIOpenURLContext *context = [URLContexts allObjects].firstObject; diff --git a/Sources/BranchSDK/BranchShareLink.m b/Sources/BranchSDK/BranchShareLink.m index 2cd4b874b..c6edc50f5 100644 --- a/Sources/BranchSDK/BranchShareLink.m +++ b/Sources/BranchSDK/BranchShareLink.m @@ -115,7 +115,7 @@ - (void) shareDidComplete:(BOOL)completed activityError:(NSError*)error { // Make sure we can share if (!(self.universalObject.canonicalIdentifier || self.universalObject.canonicalUrl || self.universalObject.title)) { - [[BranchLogger shared] logWarning:@"A canonicalIdentifier, canonicalURL, or title are required to uniquely identify content. In order to not break the end user experience with sharing, Branch SDK will proceed to create a URL, but content analytics may not properly include this URL."]; + [[BranchLogger shared] logWarning:@"A canonicalIdentifier, canonicalURL, or title are required to uniquely identify content. In order to not break the end user experience with sharing, Branch SDK will proceed to create a URL, but content analytics may not properly include this URL." error:nil]; } self.serverParameters = [[self.universalObject getParamsForServerRequestWithAddedLinkProperties:self.linkProperties] mutableCopy]; @@ -197,11 +197,12 @@ - (void) presentActivityViewControllerFromViewController:(UIViewController*_Null NSString *emailSubject = self.linkProperties.controlParams[BRANCH_LINK_DATA_KEY_EMAIL_SUBJECT]; if (emailSubject.length <= 0) emailSubject = self.emailSubject; if (emailSubject.length) { + // Key value coding to set email subject + // https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/KeyValueCoding/SearchImplementation.html#//apple_ref/doc/uid/20000955 @try { [shareViewController setValue:emailSubject forKey:@"subject"]; - } - @catch (NSException*) { - [[BranchLogger shared] logWarning: @"Unable to setValue 'emailSubject' forKey 'subject' on UIActivityViewController."]; + } @catch (NSException *exception) { + [[BranchLogger shared] logWarning:[NSString stringWithFormat:@"Exception to setValue 'emailSubject' forKey 'subject' on UIActivityViewController: %@.", exception] error:nil]; } } diff --git a/Sources/BranchSDK/BranchShortUrlSyncRequest.m b/Sources/BranchSDK/BranchShortUrlSyncRequest.m index 8f026b8df..3cbf8da64 100644 --- a/Sources/BranchSDK/BranchShortUrlSyncRequest.m +++ b/Sources/BranchSDK/BranchShortUrlSyncRequest.m @@ -63,7 +63,7 @@ - (BNCServerResponse *)makeRequest:(BNCServerInterface *)serverInterface key:(NS - (NSString *)processResponse:(BNCServerResponse *)response { if (![response.statusCode isEqualToNumber:@200]) { [[BranchLogger shared] logWarning:[NSString stringWithFormat:@"Short link creation received HTTP status code %@. Using long link instead.", - response.statusCode]]; + response.statusCode] error:nil]; NSString *failedUrl = nil; NSString *userUrl = [BNCPreferenceHelper sharedInstance].userUrl; if (userUrl) { diff --git a/Sources/BranchSDK/BranchUniversalObject.m b/Sources/BranchSDK/BranchUniversalObject.m index a21348065..a8c805e89 100644 --- a/Sources/BranchSDK/BranchUniversalObject.m +++ b/Sources/BranchSDK/BranchUniversalObject.m @@ -331,7 +331,7 @@ - (void)registerViewWithCallback:(callbackWithParams)callback { if (!self.canonicalIdentifier && !self.title) { NSString *message = @"Could not register view."; NSError *error = [NSError branchErrorWithCode:BNCContentIdentifierError localizedMessage:message]; - [[BranchLogger shared] logWarning:[NSString stringWithFormat:@"%@", error]]; + [[BranchLogger shared] logWarning:@"TODO: replace this error" error:error]; if (callback) callback([[NSDictionary alloc] init], error); return; } @@ -350,7 +350,7 @@ - (void)registerViewWithCallback:(callbackWithParams)callback { - (NSString *)getShortUrlWithLinkProperties:(BranchLinkProperties *)linkProperties { if (!self.canonicalIdentifier && !self.title) { - [[BranchLogger shared] logWarning:@"A canonicalIdentifier or title are required to uniquely identify content, so could not generate a URL."]; + [[BranchLogger shared] logWarning:@"A canonicalIdentifier or title are required to uniquely identify content, so could not generate a URL." error:nil]; return nil; } @@ -369,7 +369,7 @@ - (void)getShortUrlWithLinkProperties:(BranchLinkProperties *)linkProperties and if (!self.canonicalIdentifier && !self.title) { NSString *message = @"Could not generate a URL."; NSError *error = [NSError branchErrorWithCode:BNCContentIdentifierError localizedMessage:message]; - [[BranchLogger shared] logWarning:[NSString stringWithFormat:@"%@", error]]; + [[BranchLogger shared] logWarning:@"TODO: replace this error" error:error]; if (callback) callback([BNCPreferenceHelper sharedInstance].userUrl, error); return; } @@ -389,7 +389,7 @@ - (NSString *)getShortUrlWithLinkPropertiesAndIgnoreFirstClick:(BranchLinkProper if (!self.canonicalIdentifier && !self.title) { NSString *message = @"Could not generate a URL."; NSError *error = [NSError branchErrorWithCode:BNCContentIdentifierError localizedMessage:message]; - [[BranchLogger shared] logWarning:[NSString stringWithFormat:@"%@", error]]; + [[BranchLogger shared] logWarning:@"TODO: replace this error" error:error]; return nil; } diff --git a/Sources/BranchSDK/NSError+Branch.m b/Sources/BranchSDK/NSError+Branch.m index 524273842..1ffe8bd9d 100644 --- a/Sources/BranchSDK/NSError+Branch.m +++ b/Sources/BranchSDK/NSError+Branch.m @@ -83,4 +83,36 @@ + (NSError *) branchErrorWithCode:(BNCErrorCode)errorCode localizedMessage:(NSSt return [NSError branchErrorWithCode:errorCode error:nil localizedMessage:message]; } ++ (BOOL)branchDNSBlockingError:(NSError *)error { + if (error) { + NSError *underlyingError = error.userInfo[@"NSUnderlyingError"]; + if (underlyingError) { + + /** + Check if an NSError was likely caused by a DNS sinkhole, such as Pi-hole. + The OS level logs will show that the IP address that failed is all 0's, however App level logs will not contain that information. + + `Domain=kCFErrorDomainCFNetwork Code=-1000` - Connection failed due to a malformed URL. A bit misleading since Ad blockers DNS resolve the URL as 0.0.0.0. + https://developer.apple.com/documentation/cfnetwork/cfnetworkerrors/kcfurlerrorbadurl?language=objc + + `_kCFStreamErrorDomainKey=1` Error domain is a POSIX error. + https://opensource.apple.com/source/CF/CF-550.13/CFStream.h.auto.html + + `_kCFStreamErrorCodeKey=22` POSIX error is invalid argument. In this case the IP address is 0.0.0.0, which is invalid. + https://opensource.apple.com/source/xnu/xnu-792/bsd/sys/errno.h.auto.html + */ + BOOL isCFErrorDomainCFNetwork = [((NSString *)kCFErrorDomainCFNetwork) isEqualToString:underlyingError.domain]; + BOOL isCodeMalFormedURL = [@(-1000) isEqual:@(underlyingError.code)]; + + BOOL isErrorDomainPosix = [@(1) isEqual:error.userInfo[@"_kCFStreamErrorDomainKey"]]; + BOOL isPosixInvalidArgument = [@(22) isEqual:error.userInfo[@"_kCFStreamErrorCodeKey"]]; + + if (isCFErrorDomainCFNetwork && isCodeMalFormedURL && isErrorDomainPosix && isPosixInvalidArgument) { + return YES; + } + } + } + return NO; +} + @end diff --git a/Sources/BranchSDK/Private/BNCEncodingUtils.h b/Sources/BranchSDK/Private/BNCEncodingUtils.h index 037f43caf..97879167f 100644 --- a/Sources/BranchSDK/Private/BNCEncodingUtils.h +++ b/Sources/BranchSDK/Private/BNCEncodingUtils.h @@ -64,4 +64,7 @@ extern NSString* BNCWireFormatFromString(NSString *string); + (NSArray*) queryItems:(NSURL*)URL; +// For JSON logging ++ (NSString *)prettyPrintJSON:(NSDictionary *)json; + @end diff --git a/Sources/BranchSDK/Private/BNCKeyChain.h b/Sources/BranchSDK/Private/BNCKeyChain.h index 6d7d1e03a..b898287ab 100644 --- a/Sources/BranchSDK/Private/BNCKeyChain.h +++ b/Sources/BranchSDK/Private/BNCKeyChain.h @@ -53,7 +53,9 @@ key:(NSString * _Nonnull)key cloudAccessGroup:(NSString * _Nullable)accessGroup; -/// The default security access group for the app. -+ (NSString*_Nullable) securityAccessGroup; +/** + The security access group string is prefixed with the Apple Developer Team ID + */ ++ (NSString * _Nullable) securityAccessGroup; @end diff --git a/Sources/BranchSDK/Private/BranchJsonConfig.h b/Sources/BranchSDK/Private/BranchJsonConfig.h index 1a6737e32..425d589d0 100644 --- a/Sources/BranchSDK/Private/BranchJsonConfig.h +++ b/Sources/BranchSDK/Private/BranchJsonConfig.h @@ -16,6 +16,7 @@ extern NSString * _Nonnull const BranchJsonConfigUseTestInstanceOption; extern NSString * _Nonnull const BranchJsonConfigDeferInitForPluginRuntimeOption; extern NSString * _Nonnull const BranchJsonConfigEnableLogging; extern NSString * _Nonnull const BranchJsonConfigCheckPasteboardOnInstall; +extern NSString * _Nonnull const BranchJsonConfigAPIUrl; @interface BranchJsonConfig : NSObject @@ -29,6 +30,7 @@ extern NSString * _Nonnull const BranchJsonConfigCheckPasteboardOnInstall; @property (nonatomic, readonly, assign) BOOL deferInitForPluginRuntime; @property (nonatomic, readonly, assign) BOOL enableLogging; @property (nonatomic, readonly, assign) BOOL checkPasteboardOnInstall; +@property (nonatomic, readonly, nullable, copy) NSString *apiUrl; - (nullable id)objectForKey:(NSString * _Nonnull)key; - (nullable id)objectForKeyedSubscript:(NSString * _Nonnull)key; diff --git a/Sources/BranchSDK/Private/NSError+Branch.h b/Sources/BranchSDK/Private/NSError+Branch.h index 610eff65e..07e36c969 100644 --- a/Sources/BranchSDK/Private/NSError+Branch.h +++ b/Sources/BranchSDK/Private/NSError+Branch.h @@ -43,6 +43,9 @@ typedef NS_ENUM(NSInteger, BNCErrorCode) { + (NSError *) branchErrorWithCode:(BNCErrorCode)errorCode error:(NSError *_Nullable)error; + (NSError *) branchErrorWithCode:(BNCErrorCode)errorCode localizedMessage:(NSString *_Nullable)message; +// Checks if an NSError looks like a DNS blocking error ++ (BOOL)branchDNSBlockingError:(NSError *)error; + @end NS_ASSUME_NONNULL_END diff --git a/Sources/BranchSDK/Public/Branch.h b/Sources/BranchSDK/Public/Branch.h index 7c501de08..64afdaa30 100644 --- a/Sources/BranchSDK/Public/Branch.h +++ b/Sources/BranchSDK/Public/Branch.h @@ -566,8 +566,12 @@ extern NSString * __nonnull const BNCSpotlightFeature; /** Enable debug messages to os_log. */ -- (void)enableLogging; -- (void)enableLoggingAtLevel:(BranchLogLevel)logLevel withCallback:(nullable BranchLogCallback)callback; ++ (void)enableLogging; ++ (void)enableLoggingAtLevel:(BranchLogLevel)logLevel withCallback:(nullable BranchLogCallback)callback; + +// The new logging system is independent of the Branch singleton and can be called earlier. +- (void)enableLogging __attribute__((deprecated(("This API is deprecated. Please use the static version.")))); +- (void)enableLoggingAtLevel:(BranchLogLevel)logLevel withCallback:(nullable BranchLogCallback)callback __attribute__((deprecated(("This API is deprecated. Please use the static version.")))); /** Send requests to EU endpoints. diff --git a/Sources/BranchSDK/Public/BranchLogger.h b/Sources/BranchSDK/Public/BranchLogger.h index 70c6e55b1..d0354b387 100644 --- a/Sources/BranchSDK/Public/BranchLogger.h +++ b/Sources/BranchSDK/Public/BranchLogger.h @@ -9,11 +9,10 @@ #import typedef NS_ENUM(NSUInteger, BranchLogLevel) { - BranchLogLevelVerbose, - BranchLogLevelDebug, - BranchLogLevelInfo, - BranchLogLevelWarning, - BranchLogLevelError, + BranchLogLevelVerbose, // development + BranchLogLevelDebug, // validation and troubleshooting + BranchLogLevelWarning, // potential errors and attempts at recovery. SDK may be in a bad state. + BranchLogLevelError, // severe errors. SDK is probably in a bad state. }; typedef void(^BranchLogCallback)(NSString * _Nonnull message, BranchLogLevel logLevel, NSError * _Nullable error); @@ -29,13 +28,19 @@ NS_ASSUME_NONNULL_BEGIN + (instancetype _Nonnull)shared; +// For expensive Log messages, check if it's even worth building the log message +- (BOOL)shouldLog:(BranchLogLevel)level; + +// Caller details are relatively expensive, option to disable if the cost is too high. - (void)disableCallerDetails; - (void)logError:(NSString * _Nonnull)message error:(NSError * _Nullable)error; -- (void)logWarning:(NSString * _Nonnull)message; -- (void)logInfo:(NSString * _Nonnull)message; -- (void)logDebug:(NSString * _Nonnull)message; -- (void)logVerbose:(NSString * _Nonnull)message; +- (void)logWarning:(NSString * _Nonnull)message error:(NSError * _Nullable)error; +- (void)logDebug:(NSString * _Nonnull)message error:(NSError * _Nullable)error; +- (void)logVerbose:(NSString * _Nonnull)message error:(NSError * _Nullable)error; + +// default Branch log format ++ (NSString *)formatMessage:(NSString *)message logLevel:(BranchLogLevel)logLevel error:(NSError *)error; @end diff --git a/scripts/version.sh b/scripts/version.sh index 56564170c..d0934f33b 100755 --- a/scripts/version.sh +++ b/scripts/version.sh @@ -30,7 +30,7 @@ Options: USAGE } -version=3.3.0 +version=3.4.0 prev_version="$version" if (( $# == 0 )); then