diff --git a/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 000000000..919434a62
--- /dev/null
+++ b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/Branch-TestBed/Branch-TestBed.xcodeproj/project.pbxproj b/Branch-TestBed/Branch-TestBed.xcodeproj/project.pbxproj
index 23e32a6c7..bfd8bb661 100644
--- a/Branch-TestBed/Branch-TestBed.xcodeproj/project.pbxproj
+++ b/Branch-TestBed/Branch-TestBed.xcodeproj/project.pbxproj
@@ -188,7 +188,6 @@
5F644C492B7AA811000DCD78 /* BNCEventUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 5F644BB82B7AA811000DCD78 /* BNCEventUtils.m */; };
5F67F48E228F535500067429 /* BNCEncodingUtilsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5F67F48D228F535500067429 /* BNCEncodingUtilsTests.m */; };
5F6D86D92BB5E9650068B536 /* BNCClassSerializationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5F6D86D82BB5E9650068B536 /* BNCClassSerializationTests.m */; };
- 5F83B9ED2433BAAA0054A022 /* BNCServerInterface.Test.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D16837E2098C901008819E3 /* BNCServerInterface.Test.m */; };
5F86501A2B76DA3200364BDE /* NSMutableDictionaryBranchTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5F8650192B76DA3200364BDE /* NSMutableDictionaryBranchTests.m */; };
5F892EC5236116CD0023AEC1 /* NSErrorBranchTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5F892EC4236116CC0023AEC1 /* NSErrorBranchTests.m */; };
5F8B7B4021B5F5CD009CE0A6 /* libBranch.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 466B58381B17773000A69EDE /* libBranch.a */; };
@@ -235,6 +234,8 @@
C1614D56285BC8A00098946B /* LinkPresentation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C1614D55285BC8A00098946B /* LinkPresentation.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
C17DAF7B2AC20C2000B16B1A /* BranchClassTests.m in Sources */ = {isa = PBXBuildFile; fileRef = C17DAF7A2AC20C2000B16B1A /* BranchClassTests.m */; };
C1CC888229BAAFC000BDD2B5 /* BNCReferringURLUtilityTests.m in Sources */ = {isa = PBXBuildFile; fileRef = C1CC888129BAAFC000BDD2B5 /* BNCReferringURLUtilityTests.m */; };
+ E56394312CC7AC9F00E18E65 /* BranchFileLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = E563942F2CC7AC9500E18E65 /* BranchFileLogger.m */; };
+ E56394332CC7ACB600E18E65 /* BranchFileLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = E56394322CC7ACAA00E18E65 /* BranchFileLogger.h */; settings = {ATTRIBUTES = (Public, ); }; };
E72489D228E40D0200DCD8FD /* PasteControlViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E72489D128E40D0200DCD8FD /* PasteControlViewController.m */; };
E7A728BD2AA9A112009343B7 /* BNCAPIServerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = E7A728BC2AA9A112009343B7 /* BNCAPIServerTest.m */; };
F1CF14111F4CC79F00BB2694 /* CoreSpotlight.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 67F270881BA9FCFF002546A7 /* CoreSpotlight.framework */; settings = {ATTRIBUTES = (Required, ); }; };
@@ -539,6 +540,8 @@
C1614D55285BC8A00098946B /* LinkPresentation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = LinkPresentation.framework; path = System/Library/Frameworks/LinkPresentation.framework; sourceTree = SDKROOT; };
C17DAF7A2AC20C2000B16B1A /* BranchClassTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BranchClassTests.m; sourceTree = ""; };
C1CC888129BAAFC000BDD2B5 /* BNCReferringURLUtilityTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BNCReferringURLUtilityTests.m; sourceTree = ""; };
+ E563942F2CC7AC9500E18E65 /* BranchFileLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BranchFileLogger.m; sourceTree = ""; };
+ E56394322CC7ACAA00E18E65 /* BranchFileLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BranchFileLogger.h; sourceTree = ""; };
E72489D028E40D0200DCD8FD /* PasteControlViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PasteControlViewController.h; sourceTree = ""; };
E72489D128E40D0200DCD8FD /* PasteControlViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PasteControlViewController.m; sourceTree = ""; };
E7A728BC2AA9A112009343B7 /* BNCAPIServerTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BNCAPIServerTest.m; sourceTree = ""; };
@@ -676,6 +679,7 @@
5F644B252B7AA810000DCD78 /* BranchSDK */ = {
isa = PBXGroup;
children = (
+ E563942F2CC7AC9500E18E65 /* BranchFileLogger.m */,
5F644BB02B7AA811000DCD78 /* BNCAppGroupsData.m */,
5F644BA82B7AA811000DCD78 /* BNCAppleReceipt.m */,
5F644B2B2B7AA810000DCD78 /* BNCApplication.m */,
@@ -755,6 +759,7 @@
5F644B522B7AA810000DCD78 /* Public */ = {
isa = PBXGroup;
children = (
+ E56394322CC7ACAA00E18E65 /* BranchFileLogger.h */,
5F644B5E2B7AA810000DCD78 /* BNCCallbacks.h */,
5F644B5A2B7AA810000DCD78 /* BNCCurrency.h */,
5F644B612B7AA810000DCD78 /* BNCInitSessionResponse.h */,
@@ -986,6 +991,7 @@
5F644BFE2B7AA811000DCD78 /* BNCServerInterface.h in Headers */,
5F644BFF2B7AA811000DCD78 /* BNCProductCategory.h in Headers */,
5F644C1C2B7AA811000DCD78 /* NSString+Branch.h in Headers */,
+ E56394332CC7ACB600E18E65 /* BranchFileLogger.h in Headers */,
5F644C132B7AA811000DCD78 /* NSMutableDictionary+Branch.h in Headers */,
5F644C122B7AA811000DCD78 /* BNCApplication.h in Headers */,
5F5FDA122B7DE22A00F14A43 /* BranchLogger.h in Headers */,
@@ -1317,6 +1323,7 @@
5F644BD72B7AA811000DCD78 /* BNCNetworkService.m in Sources */,
5F644C402B7AA811000DCD78 /* UIViewController+Branch.m in Sources */,
5F644BC12B7AA811000DCD78 /* BNCServerRequestQueue.m in Sources */,
+ E56394312CC7AC9F00E18E65 /* BranchFileLogger.m in Sources */,
5F644C452B7AA811000DCD78 /* BranchOpenRequest.m in Sources */,
5F644C312B7AA811000DCD78 /* BNCLinkData.m in Sources */,
5F644BD22B7AA811000DCD78 /* BranchContentDiscoveryManifest.m in Sources */,
diff --git a/BranchSDK.xcodeproj/project.pbxproj b/BranchSDK.xcodeproj/project.pbxproj
index 7219bec79..02f1cb075 100644
--- a/BranchSDK.xcodeproj/project.pbxproj
+++ b/BranchSDK.xcodeproj/project.pbxproj
@@ -489,6 +489,11 @@
5FCDD5B22B7AC89100EAF29F /* BranchSDK.h in Headers */ = {isa = PBXBuildFile; fileRef = 5FF2AFDF28E7C22100393216 /* BranchSDK.h */; settings = {ATTRIBUTES = (Public, ); }; };
5FCDD5B32B7AC89200EAF29F /* BranchSDK.h in Headers */ = {isa = PBXBuildFile; fileRef = 5FF2AFDF28E7C22100393216 /* BranchSDK.h */; settings = {ATTRIBUTES = (Public, ); }; };
5FCDD5B42B7AC89200EAF29F /* BranchSDK.h in Headers */ = {isa = PBXBuildFile; fileRef = 5FF2AFDF28E7C22100393216 /* BranchSDK.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ E52E5B062CC79E4E00F553EE /* BranchFileLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = E52E5B052CC79E4E00F553EE /* BranchFileLogger.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ E52E5B072CC79E4E00F553EE /* BranchFileLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = E52E5B052CC79E4E00F553EE /* BranchFileLogger.h */; };
+ E52E5B0A2CC79E5C00F553EE /* BranchFileLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = E52E5B092CC79E5C00F553EE /* BranchFileLogger.m */; };
+ E52E5B0B2CC79E5C00F553EE /* BranchFileLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = E52E5B092CC79E5C00F553EE /* BranchFileLogger.m */; };
+ E563942E2CC7A8E600E18E65 /* BranchFileLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = E52E5B052CC79E4E00F553EE /* BranchFileLogger.h */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -698,6 +703,8 @@
5FF2AFDC28E7BF8A00393216 /* build_xcframework.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = build_xcframework.sh; sourceTree = ""; };
5FF2AFDE28E7C22100393216 /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = ""; };
5FF2AFDF28E7C22100393216 /* BranchSDK.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BranchSDK.h; sourceTree = ""; };
+ E52E5B052CC79E4E00F553EE /* BranchFileLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BranchFileLogger.h; sourceTree = ""; };
+ E52E5B092CC79E5C00F553EE /* BranchFileLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BranchFileLogger.m; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -811,6 +818,7 @@
5FCDD36B2B7AC6A100EAF29F /* BranchSDK */ = {
isa = PBXGroup;
children = (
+ E52E5B092CC79E5C00F553EE /* BranchFileLogger.m */,
5FCDD3F62B7AC6A100EAF29F /* BNCAppGroupsData.m */,
5FCDD3EE2B7AC6A100EAF29F /* BNCAppleReceipt.m */,
5FCDD3712B7AC6A100EAF29F /* BNCApplication.m */,
@@ -890,6 +898,7 @@
5FCDD3982B7AC6A100EAF29F /* Public */ = {
isa = PBXGroup;
children = (
+ E52E5B052CC79E4E00F553EE /* BranchFileLogger.h */,
5FCDD3A42B7AC6A100EAF29F /* BNCCallbacks.h */,
5FCDD3A02B7AC6A100EAF29F /* BNCCurrency.h */,
5FCDD3A72B7AC6A100EAF29F /* BNCInitSessionResponse.h */,
@@ -1029,6 +1038,7 @@
5FCDD4A12B7AC6A200EAF29F /* BNCServerResponse.h in Headers */,
5FCDD4C22B7AC6A200EAF29F /* BranchDeepLinkingController.h in Headers */,
5FCDD4B92B7AC6A200EAF29F /* BranchPasteControl.h in Headers */,
+ E52E5B062CC79E4E00F553EE /* BranchFileLogger.h in Headers */,
5FCDD5072B7AC6A300EAF29F /* BNCUrlQueryParameter.h in Headers */,
5FCDD5462B7AC6A300EAF29F /* BNCConfig.h in Headers */,
5FCDD4E62B7AC6A200EAF29F /* UIViewController+Branch.h in Headers */,
@@ -1110,6 +1120,7 @@
5FCDD4C32B7AC6A200EAF29F /* BranchDeepLinkingController.h in Headers */,
5FCDD4BA2B7AC6A200EAF29F /* BranchPasteControl.h in Headers */,
5FCDD49F2B7AC6A200EAF29F /* Branch.h in Headers */,
+ E52E5B072CC79E4E00F553EE /* BranchFileLogger.h in Headers */,
5FCDD5082B7AC6A300EAF29F /* BNCUrlQueryParameter.h in Headers */,
5FCDD5472B7AC6A300EAF29F /* BNCConfig.h in Headers */,
5F5FDA1B2B7DE31E00F14A43 /* BranchLogger.h in Headers */,
@@ -1190,6 +1201,7 @@
5FCDD4A02B7AC6A200EAF29F /* Branch.h in Headers */,
5FCDD5092B7AC6A300EAF29F /* BNCUrlQueryParameter.h in Headers */,
5FCDD5482B7AC6A300EAF29F /* BNCConfig.h in Headers */,
+ E563942E2CC7A8E600E18E65 /* BranchFileLogger.h in Headers */,
5FCDD4E82B7AC6A200EAF29F /* UIViewController+Branch.h in Headers */,
5FCDD54B2B7AC6A300EAF29F /* BranchConstants.h in Headers */,
5F5FDA1C2B7DE31E00F14A43 /* BranchLogger.h in Headers */,
@@ -1608,6 +1620,7 @@
5FCDD4592B7AC6A100EAF29F /* BNCNetworkService.m in Sources */,
5FCDD5942B7AC6A400EAF29F /* UIViewController+Branch.m in Sources */,
5FCDD4172B7AC6A100EAF29F /* BNCServerRequestQueue.m in Sources */,
+ E52E5B0A2CC79E5C00F553EE /* BranchFileLogger.m in Sources */,
5FCDD5A32B7AC6A400EAF29F /* BranchOpenRequest.m in Sources */,
5FCDD5672B7AC6A300EAF29F /* BNCLinkData.m in Sources */,
5FCDD44A2B7AC6A100EAF29F /* BranchContentDiscoveryManifest.m in Sources */,
@@ -1712,6 +1725,7 @@
5FCDD45A2B7AC6A100EAF29F /* BNCNetworkService.m in Sources */,
5FCDD5952B7AC6A400EAF29F /* UIViewController+Branch.m in Sources */,
5FCDD4182B7AC6A100EAF29F /* BNCServerRequestQueue.m in Sources */,
+ E52E5B0B2CC79E5C00F553EE /* BranchFileLogger.m in Sources */,
5FCDD5A42B7AC6A400EAF29F /* BranchOpenRequest.m in Sources */,
5FCDD5682B7AC6A400EAF29F /* BNCLinkData.m in Sources */,
5FCDD44B2B7AC6A100EAF29F /* BranchContentDiscoveryManifest.m in Sources */,
diff --git a/Sources/BranchSDK/BNCSystemObserver.m b/Sources/BranchSDK/BNCSystemObserver.m
index e171a7271..6c5d8a2ec 100644
--- a/Sources/BranchSDK/BNCSystemObserver.m
+++ b/Sources/BranchSDK/BNCSystemObserver.m
@@ -165,6 +165,17 @@ + (BOOL)compareUriSchemes : (NSString *) serverUriScheme {
return false;
}
++ (BOOL)compareLinkDomain:(NSString *)serverLinkDomain {
+ NSArray *linkDomains = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"branch_universal_link_domains"];
+
+ for (NSString *domain in linkDomains) {
+ if ([domain isEqualToString:serverLinkDomain]) {
+ return true;
+ }
+ }
+ return false;
+}
+
+ (NSString *)bundleIdentifier {
return [[NSBundle mainBundle] bundleIdentifier];
}
diff --git a/Sources/BranchSDK/Branch+Validator.m b/Sources/BranchSDK/Branch+Validator.m
index 8a387a803..a56ab5410 100644
--- a/Sources/BranchSDK/Branch+Validator.m
+++ b/Sources/BranchSDK/Branch+Validator.m
@@ -13,6 +13,11 @@
#import "BNCEncodingUtils.h"
#import "BNCServerAPI.h"
#import "UIViewController+Branch.h"
+#import "BNCConfig.h"
+#import "Branch.h"
+#if !TARGET_OS_TV
+#import "BranchFileLogger.h"
+#endif
void BNCForceBranchValidatorCategoryToLoad(void) {
// Empty body but forces loader to load the category.
@@ -30,6 +35,62 @@ static inline void BNCAfterSecondsPerformBlockOnMainThread(NSTimeInterval second
dispatch_after(BNCDispatchTimeFromSeconds(seconds), dispatch_get_main_queue(), block);
}
+typedef NS_ENUM(NSUInteger, BranchValidationError) {
+ BranchLinkDomainError, // for link domain or alternate domain mismatch
+ BranchURISchemeError, // for uri scheme mismatch
+ BranchAppIDError, // for bundle ID or app prefix mismatch
+ BranchATTError // for idfa missing error
+};
+
+NSString *BranchValidationErrorDescription(BranchValidationError error) {
+ switch (error) {
+ case BranchLinkDomainError:
+ return @"Check the link domain and alternate domain values in your info.plist file under the key 'branch_universal_link_domains'. The values should match with the ones on the Branch dashboard.\n\n";
+ case BranchURISchemeError:
+ return @"The URI scheme in your info.plist file shoudl match with the URI scheme value for iOS on the Branch dashboard.\n\n";
+ case BranchAppIDError:
+ return @"Check your bundle ID and Apple App Prefix from the Apple Developer website and ensure it matches with the values you have added on the Branch dashboard.\n\n";
+ case BranchATTError:
+ return @"The ATT prompt ensures that the Branch SDK can access the IDFA when the user permits it. Add the ATT prompt in your app for IDFA access.\n\n";
+ }
+ return @"Unknown";
+}
+
+NSString *BranchValidationErrorReferenceDescription(BranchValidationError error) {
+ switch (error) {
+ case BranchLinkDomainError:
+ return @"Link Domain Reference";
+ case BranchURISchemeError:
+ return @"URI Scheme Reference";
+ case BranchAppIDError:
+ return @"App Prefix/Bundle ID Reference";
+ case BranchATTError:
+ return @"ATT Prompt Reference";
+ }
+ return @"Unknown";
+}
+
+NSURL *BranchValidationErrorReference(BranchValidationError error) {
+ NSString *urlString;
+
+ switch (error) {
+ case BranchLinkDomainError:
+ urlString = @"https://help.branch.io/developers-hub/docs/ios-basic-integration#4-configure-infoplist";
+ break;
+ case BranchURISchemeError:
+ urlString = @"https://help.branch.io/developers-hub/docs/ios-basic-integration#4-configure-infoplist";
+ break;
+ case BranchAppIDError:
+ urlString = @"https://help.branch.io/developers-hub/docs/ios-basic-integration#1-configure-branch-dashboard";
+ break;
+ case BranchATTError:
+ urlString = @"https://help.branch.io/developers-hub/docs/ios-advanced-features#include-apples-attrackingmanager";
+ break;
+ }
+
+ return [NSURL URLWithString:urlString];
+}
+
#pragma mark - Branch (Validator)
@implementation Branch (Validator)
@@ -62,20 +123,23 @@ - (void) validateIntegrationWithServerResponse:(BNCServerResponse*)response {
NSString*serverUriScheme = BNCStringFromWireFormat(response.data[@"ios_uri_scheme"]) ?: @"";
NSString*serverBundleID = BNCStringFromWireFormat(response.data[@"ios_bundle_id"]) ?: @"";
NSString*serverTeamID = BNCStringFromWireFormat(response.data[@"ios_team_id"]) ?: @"";
+ NSString*defaultDomain = BNCStringFromWireFormat(response.data[@"default_short_url_domain"]) ?: @"";
+ NSString*alternateDomain = BNCStringFromWireFormat(response.data[@"alternate_short_url_domain"]) ?: @"";
+ NSString*attOptInStatus = [BNCSystemObserver attOptedInStatus];
// Verify:
NSLog(@"** Initiating Branch integration verification **");
NSLog(@"-------------------------------------------------");
NSLog(@"------ Checking for URI scheme correctness ------");
- NSString *clientUriScheme = [NSString stringWithFormat:@"%@%@", [BNCSystemObserver defaultURIScheme], @"://"];
NSString *uriScheme = [BNCSystemObserver compareUriSchemes:serverUriScheme] ? passString : errorString;
+ bool doUriSchemesMatch = [BNCSystemObserver compareUriSchemes:serverUriScheme];
NSLog(@"-------------------------------------------------");
NSLog(@"-- Checking for bundle identifier correctness ---");
NSString *clientBundleIdentifier = [[NSBundle mainBundle] bundleIdentifier] ?: @"";
- bool doUriSchemesMatch = [serverBundleID isEqualToString:clientBundleIdentifier];
- NSString *bundleIdentifier = doUriSchemesMatch ? passString : errorString;
+ bool doBundleIDsMatch = [serverBundleID isEqualToString:clientBundleIdentifier];
+ NSString *bundleIdentifier = doBundleIDsMatch ? passString : errorString;
NSString *bundleIdentifierMessage =
[NSString stringWithFormat:@"%@: Dashboard Link Settings page '%@' compared to client side '%@'",
bundleIdentifier, serverBundleID, clientBundleIdentifier];
@@ -107,9 +171,37 @@ - (void) validateIntegrationWithServerResponse:(BNCServerResponse*)response {
BOOL testsFailed = NO;
NSString *kPassMark = @"✅\t";
NSString *kFailMark = @"❌\t";
+ NSString *kWarningMark = @"⚠️\t";
// Build an alert string:
- NSString *alertString = @"\n";
+ NSString *alertString = @"";
+ NSMutableArray *errors = [[NSMutableArray alloc] init];
+ alertString = [alertString stringByAppendingFormat:@"\nBranch SDK Version: %@\n", BNC_SDK_VERSION];
+ if ([Branch useTestBranchKey]) {
+ alertString = [alertString stringByAppendingFormat:@"The SDK is using the test key\n\n"];
+ } else {
+ alertString = [alertString stringByAppendingFormat:@"The SDK is using the live key\n\n"];
+ }
+ if ([BNCSystemObserver compareLinkDomain:defaultDomain]) {
+ alertString = [alertString stringByAppendingFormat:@"%@Default Link Domain matches:\n\t'%@'\n", kPassMark, defaultDomain];
+ } else {
+ testsFailed = YES;
+ alertString = [alertString stringByAppendingFormat:@"%@Default Link Domain mismatch:\n\t'%@'\n", kFailMark, defaultDomain];
+ if (![errors containsObject:@(BranchLinkDomainError)]) {
+ [errors addObject:@(BranchLinkDomainError)];
+ }
+ }
+
+ if ([BNCSystemObserver compareLinkDomain:alternateDomain]) {
+ alertString = [alertString stringByAppendingFormat:@"%@Alternate Link Domain matches:\n\t'%@'\n", kPassMark, alternateDomain];
+ } else {
+ testsFailed = YES;
+ alertString = [alertString stringByAppendingFormat:@"%@Alternate Link Domain mismatch:\n\t'%@'\n", kFailMark, alternateDomain];
+ if (![errors containsObject:@(BranchLinkDomainError)]) {
+ [errors addObject:@(BranchLinkDomainError)];
+ }
+ }
+
if (serverUriScheme.length && doUriSchemesMatch) {
alertString = [alertString stringByAppendingFormat:@"%@URI Scheme matches:\n\t'%@'\n",
kPassMark, serverUriScheme];
@@ -117,6 +209,9 @@ - (void) validateIntegrationWithServerResponse:(BNCServerResponse*)response {
testsFailed = YES;
alertString = [alertString stringByAppendingFormat:@"%@URI Scheme mismatch:\n\t'%@'\n",
kFailMark, serverUriScheme];
+ if (![errors containsObject:@(BranchURISchemeError)]) {
+ [errors addObject:@(BranchURISchemeError)];
+ }
}
if ([serverBundleID isEqualToString:clientBundleIdentifier]) {
@@ -126,6 +221,9 @@ - (void) validateIntegrationWithServerResponse:(BNCServerResponse*)response {
testsFailed = YES;
alertString = [alertString stringByAppendingFormat:@"%@App Bundle ID mismatch:\n\t'%@'\n",
kFailMark, serverBundleID];
+ if (![errors containsObject:@(BranchAppIDError)]) {
+ [errors addObject:@(BranchAppIDError)];
+ }
}
if ([serverTeamID isEqualToString:clientTeamId]) {
@@ -135,10 +233,22 @@ - (void) validateIntegrationWithServerResponse:(BNCServerResponse*)response {
testsFailed = YES;
alertString = [alertString stringByAppendingFormat:@"%@Team ID mismatch:\n\t'%@'\n",
kFailMark, serverTeamID];
+ if (![errors containsObject:@(BranchAppIDError)]) {
+ [errors addObject:@(BranchAppIDError)];
+ }
}
-
+
+ if ([attOptInStatus isEqualToString:@"authorized"]) {
+ alertString = [alertString stringByAppendingFormat:@"%@IDFA is accessible\n", kPassMark];
+ } else {
+ alertString = [alertString stringByAppendingFormat:@"%@IDFA is not accessible\n", kWarningMark];
+ if (![errors containsObject:@(BranchATTError)]) {
+ [errors addObject:@(BranchATTError)];
+ }
+ }
+
if (testsFailed) {
- alertString = [alertString stringByAppendingString:@"\nFailed!\nCheck the log for details."];
+ alertString = [alertString stringByAppendingString:@"\nFailed!"];
} else {
alertString = [alertString stringByAppendingString:@"\nPassed!"];
}
@@ -154,19 +264,31 @@ - (void) validateIntegrationWithServerResponse:(BNCServerResponse*)response {
BNCPerformBlockOnMainThreadAsync(^{
UIAlertController *alertController =
- [UIAlertController alertControllerWithTitle:@"Branch Integration"
+ [UIAlertController alertControllerWithTitle:@"Branch Integration Validator"
message:alertString
preferredStyle:UIAlertControllerStyleAlert];
if (testsFailed) {
[alertController
- addAction:[UIAlertAction actionWithTitle:@"Bummer"
+ addAction:[UIAlertAction actionWithTitle:@"What should I change?"
+ style:UIAlertActionStyleDefault
+ handler:^ (UIAlertAction *action) { [self showSolutionsForErrors:(errors)]; }]];
+ [alertController
+ addAction:[UIAlertAction actionWithTitle:@"Export Logs"
+ style:UIAlertActionStyleDefault
+ handler:^ (UIAlertAction *action) { [self showExportedLogs]; }]];
+ [alertController
+ addAction:[UIAlertAction actionWithTitle:@"Done"
style:UIAlertActionStyleDefault
handler:nil]];
} else {
[alertController
- addAction:[UIAlertAction actionWithTitle:@"Next Step"
+ addAction:[UIAlertAction actionWithTitle:@"Done"
+ style:UIAlertActionStyleDefault
+ handler:nil]];
+ [alertController
+ addAction:[UIAlertAction actionWithTitle:@"Export Logs"
style:UIAlertActionStyleDefault
- handler:^ (UIAlertAction *action) { [self showNextStep]; }]];
+ handler:^ (UIAlertAction *action) { [self showExportedLogs]; }]];
}
[alertController setValue:styledAlertString forKey:@"attributedMessage"];
[[UIViewController bnc_currentViewController]
@@ -176,6 +298,57 @@ - (void) validateIntegrationWithServerResponse:(BNCServerResponse*)response {
});
}
+- (void) showSolutionsForErrors:(NSArray*) errors {
+ NSString *message = @"";
+ UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"What should I change?" message: @"" preferredStyle: UIAlertControllerStyleAlert];
+ for (NSNumber *errorNumber in errors) {
+ BranchValidationError error = (BranchValidationError)[errorNumber integerValue];
+
+ message = [message stringByAppendingString:BranchValidationErrorDescription(error)];
+
+ [alertController
+ addAction:[UIAlertAction actionWithTitle:BranchValidationErrorReferenceDescription(error)
+ style:UIAlertActionStyleDefault
+ handler:^ (UIAlertAction *action) {
+ Class applicationClass = NSClassFromString(@"UIApplication");
+ id sharedApplication = [applicationClass performSelector:@selector(sharedApplication)];
+ if ([sharedApplication respondsToSelector:@selector(openURL:)])
+ [sharedApplication performSelector:@selector(openURL:) withObject:BranchValidationErrorReference(error)];
+ }]];
+ }
+
+ alertController.message = message;
+ [alertController
+ addAction:[UIAlertAction actionWithTitle:@"Done"
+ style:UIAlertActionStyleDefault
+ handler:nil]];
+
+ [[UIViewController bnc_currentViewController]
+ presentViewController:alertController
+ animated:YES
+ completion:nil];
+}
+
+- (void) showExportedLogs {
+ #if !TARGET_OS_TV
+ if ([[BranchFileLogger sharedInstance] isLogFilePopulated]) {
+ UIViewController *currentVC = [UIViewController bnc_currentViewController];
+ [[BranchFileLogger sharedInstance] shareLogFileFromViewController:currentVC];
+ } else {
+ UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"No log file available" message: @"Ensure that logging is enabled and you are running the app in debug mode to export logs." preferredStyle: UIAlertControllerStyleAlert];
+ [alertController
+ addAction:[UIAlertAction actionWithTitle:@"Done"
+ style:UIAlertActionStyleDefault
+ handler:nil]];
+ [[UIViewController bnc_currentViewController]
+ presentViewController:alertController
+ animated:YES
+ completion:nil];
+ }
+ #endif
+}
+
+//MARK: Not in use until development of Integration Validator Phase 2 Changes
- (void) showNextStep {
NSString *message =
@"\nGreat! Remove the 'validateSDKIntegration' line in your app.\n\n"
diff --git a/Sources/BranchSDK/Branch.m b/Sources/BranchSDK/Branch.m
index 9b4d4f87e..bdfc59cc7 100644
--- a/Sources/BranchSDK/Branch.m
+++ b/Sources/BranchSDK/Branch.m
@@ -2107,6 +2107,8 @@ - (void)handleInitSuccessAndCallCallback:(BOOL)callCallback sceneIdentifier:(NSS
id sharedApplication = [applicationClass performSelector:@selector(sharedApplication)];
if ([sharedApplication respondsToSelector:@selector(openURL:)])
[sharedApplication performSelector:@selector(openURL:) withObject:comp.URL];
+ } else if ([latestReferringParams[@"validate_integration"] isEqualToString:@"true"]) {
+ [self validateSDKIntegration];
}
if (callCallback) {
diff --git a/Sources/BranchSDK/BranchFileLogger.m b/Sources/BranchSDK/BranchFileLogger.m
new file mode 100644
index 000000000..10aceb5ce
--- /dev/null
+++ b/Sources/BranchSDK/BranchFileLogger.m
@@ -0,0 +1,114 @@
+//
+// BranchFileLogger.m
+//
+//
+// Created by Sharath Sriram on 15/10/24.
+//
+#if !TARGET_OS_TV
+
+#import "BranchFileLogger.h"
+
+@interface BranchFileLogger ()
+
+@property (nonatomic, strong) NSString *logFilePath;
+
+@end
+
+@implementation BranchFileLogger
+
++ (instancetype)sharedInstance {
+ static BranchFileLogger *sharedInstance = nil;
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ sharedInstance = [[self alloc] init];
+ });
+ return sharedInstance;
+}
+
+- (instancetype)init {
+ if (self = [super init]) {
+ _logFilePath = [self getLogFilePath];
+ [self clearLogs]; // Clear logs at the start of each app session
+ }
+ return self;
+}
+
+// Get the log file path in the app’s documents directory
+- (NSString *)getLogFilePath {
+ NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
+ NSString *documentsDirectory = [paths firstObject];
+ return [documentsDirectory stringByAppendingPathComponent:@"app_log.txt"];
+}
+
+// Append a message to the log file
+- (void)logMessage:(NSString *)message {
+ NSString *timestampedMessage = [NSString stringWithFormat:@"%@: %@\n", [self currentTimestamp], message];
+
+ NSFileHandle *fileHandle = [NSFileHandle fileHandleForWritingAtPath:self.logFilePath];
+ if (!fileHandle) {
+ [[NSFileManager defaultManager] createFileAtPath:self.logFilePath contents:nil attributes:nil];
+ fileHandle = [NSFileHandle fileHandleForWritingAtPath:self.logFilePath];
+ }
+
+ [fileHandle seekToEndOfFile];
+ NSData *data = [timestampedMessage dataUsingEncoding:NSUTF8StringEncoding];
+ [fileHandle writeData:data];
+ [fileHandle closeFile];
+}
+
+// Helper: Get the current timestamp
+- (NSString *)currentTimestamp {
+ NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
+ [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
+ return [formatter stringFromDate:[NSDate date]];
+}
+
+// Clear the log file (called at app start)
+- (void)clearLogs {
+ [[NSFileManager defaultManager] removeItemAtPath:self.logFilePath error:nil];
+ [[NSFileManager defaultManager] createFileAtPath:self.logFilePath contents:nil attributes:nil];
+}
+
+- (BOOL)isLogFilePopulated {
+ NSString *logFilePath = [self getLogFilePath];
+
+ // Check if the file exists
+ if (![[NSFileManager defaultManager] fileExistsAtPath:logFilePath]) {
+ return NO;
+ }
+
+ // Check if the file is non-empty
+ NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:logFilePath error:nil];
+ unsigned long long fileSize = [attributes fileSize];
+
+ return fileSize > 0; // Return YES if file is populated, NO otherwise
+}
+
+- (void)shareLogFileFromViewController:(UIViewController *)viewController {
+ NSString *logFilePath = [self getLogFilePath];
+
+ // Check if the log file exists
+ if (![[NSFileManager defaultManager] fileExistsAtPath:logFilePath]) {
+ NSLog(@"No log file found to share.");
+ return;
+ }
+
+ // Create a URL from the log file path
+ NSURL *logFileURL = [NSURL fileURLWithPath:logFilePath];
+
+ // Create an activity view controller with the log file
+ UIActivityViewController *activityVC =
+ [[UIActivityViewController alloc] initWithActivityItems:@[logFileURL]
+ applicationActivities:nil];
+
+ // Exclude certain activities if necessary (optional)
+ activityVC.excludedActivityTypes = @[UIActivityTypePostToFacebook,
+ UIActivityTypePostToTwitter];
+
+ // Present the share sheet
+ [viewController presentViewController:activityVC animated:YES completion:nil];
+}
+
+@end
+
+#endif
diff --git a/Sources/BranchSDK/BranchLogger.m b/Sources/BranchSDK/BranchLogger.m
index d64a65568..0ad29fabf 100644
--- a/Sources/BranchSDK/BranchLogger.m
+++ b/Sources/BranchSDK/BranchLogger.m
@@ -7,6 +7,9 @@
//
#import "BranchLogger.h"
+#if !TARGET_OS_TV
+#import "BranchFileLogger.h"
+#endif
#import
@implementation BranchLogger
@@ -81,6 +84,11 @@ - (void)logMessage:(NSString *)message withLevel:(BranchLogLevel)level error:(NS
if (self.logCallback) {
self.logCallback(formattedMessage, level, error);
}
+ #if !TARGET_OS_TV
+ #ifdef DEBUG
+ [[BranchFileLogger sharedInstance] logMessage:formattedMessage];
+ #endif
+ #endif
}
- (NSString *)callingClass {
diff --git a/Sources/BranchSDK/Private/BNCSystemObserver.h b/Sources/BranchSDK/Private/BNCSystemObserver.h
index 9b8119027..dd5d663a5 100644
--- a/Sources/BranchSDK/Private/BNCSystemObserver.h
+++ b/Sources/BranchSDK/Private/BNCSystemObserver.h
@@ -34,5 +34,6 @@
+ (NSString *)environment;
+ (BOOL)isAppClip;
+ (BOOL)compareUriSchemes:(NSString *) serverUriScheme;
++ (BOOL)compareLinkDomain:(NSString*) serverLinkDomain;
@end
diff --git a/Sources/BranchSDK/Public/BranchFileLogger.h b/Sources/BranchSDK/Public/BranchFileLogger.h
new file mode 100644
index 000000000..6ded601d7
--- /dev/null
+++ b/Sources/BranchSDK/Public/BranchFileLogger.h
@@ -0,0 +1,24 @@
+//
+// BranchFileLogger.h
+//
+//
+// Created by Sharath Sriram on 15/10/24.
+//
+
+#if !TARGET_OS_TV
+
+#import
+#import
+
+@interface BranchFileLogger : NSObject
+
++ (instancetype)sharedInstance;
+- (void)logMessage:(NSString *)message;
+- (NSString *)getLogFilePath;
+- (void)clearLogs;
+- (BOOL)isLogFilePopulated;
+- (void)shareLogFileFromViewController:(UIViewController *)viewController;
+
+@end
+
+#endif