From 4b9f0ee2415f0fb6ef506342df3dbb28afd88ccc Mon Sep 17 00:00:00 2001 From: Saeed Bashir Date: Fri, 16 Feb 2024 11:06:39 +0500 Subject: [PATCH 1/6] feat: branch sdk integration --- Core/Core.xcodeproj/project.pbxproj | 22 ++++++++- .../Configuration/Config/BranchConfig.swift | 3 +- OpenEdX/AppDelegate.swift | 1 + OpenEdX/Info.plist | 7 +++ .../DeepLinkManager/DeepLinkManager.swift | 27 ++++++++--- .../DeepLinkManager/Link/DeepLink.swift | 48 ++++++++++++++++++- .../DeepLinkManager/Link/PushLink.swift | 13 ++--- .../Services/BranchService.swift | 20 +++++++- .../PushNotificationsManager.swift | 2 +- OpenEdX/OpenEdX.entitlements | 7 +++ Podfile | 1 + Podfile.lock | 8 +++- config_script/process_config.py | 30 ++++++++++-- 13 files changed, 161 insertions(+), 28 deletions(-) diff --git a/Core/Core.xcodeproj/project.pbxproj b/Core/Core.xcodeproj/project.pbxproj index 1c68a8ad8..a164f4918 100644 --- a/Core/Core.xcodeproj/project.pbxproj +++ b/Core/Core.xcodeproj/project.pbxproj @@ -130,8 +130,8 @@ A595689B2B6173DF00ED4F90 /* BranchConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = A595689A2B6173DF00ED4F90 /* BranchConfig.swift */; }; A5F4E7B52B61544A00ACD166 /* BrazeConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5F4E7B42B61544A00ACD166 /* BrazeConfig.swift */; }; BA30427F2B20B320009B64B7 /* SocialAuthError.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA30427D2B20B299009B64B7 /* SocialAuthError.swift */; }; - BA4AFB442B6A5AF100A21367 /* CheckBoxView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA4AFB432B6A5AF100A21367 /* CheckBoxView.swift */; }; BA4AFB422B5A7A0900A21367 /* VideoDownloadQualityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA4AFB412B5A7A0900A21367 /* VideoDownloadQualityView.swift */; }; + BA4AFB442B6A5AF100A21367 /* CheckBoxView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA4AFB432B6A5AF100A21367 /* CheckBoxView.swift */; }; BA593F1C2AF8E498009ADB51 /* ScrollSlidingTabBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA593F1B2AF8E498009ADB51 /* ScrollSlidingTabBar.swift */; }; BA593F1E2AF8E4A0009ADB51 /* FrameReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA593F1D2AF8E4A0009ADB51 /* FrameReader.swift */; }; BA76135C2B21BC7300B599B7 /* SocialAuthResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA76135B2B21BC7300B599B7 /* SocialAuthResponse.swift */; }; @@ -307,8 +307,8 @@ A595689A2B6173DF00ED4F90 /* BranchConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BranchConfig.swift; sourceTree = ""; }; A5F4E7B42B61544A00ACD166 /* BrazeConfig.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BrazeConfig.swift; sourceTree = ""; }; BA30427D2B20B299009B64B7 /* SocialAuthError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SocialAuthError.swift; sourceTree = ""; }; - BA4AFB432B6A5AF100A21367 /* CheckBoxView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckBoxView.swift; sourceTree = ""; }; BA4AFB412B5A7A0900A21367 /* VideoDownloadQualityView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoDownloadQualityView.swift; sourceTree = ""; }; + BA4AFB432B6A5AF100A21367 /* CheckBoxView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckBoxView.swift; sourceTree = ""; }; BA593F1B2AF8E498009ADB51 /* ScrollSlidingTabBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScrollSlidingTabBar.swift; sourceTree = ""; }; BA593F1D2AF8E4A0009ADB51 /* FrameReader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FrameReader.swift; sourceTree = ""; }; BA76135B2B21BC7300B599B7 /* SocialAuthResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SocialAuthResponse.swift; sourceTree = ""; }; @@ -860,6 +860,7 @@ 0770DE0428D07831006D8A5D /* Sources */, 0770DE0528D07831006D8A5D /* Frameworks */, 0770DE0628D07831006D8A5D /* Resources */, + 977ABB5AB2E4B7F1F11DDB6B /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -961,6 +962,23 @@ shellPath = /bin/sh; shellScript = "if [[ -f \"${PODS_ROOT}/SwiftGen/bin/swiftgen\" ]]; then\n \"${PODS_ROOT}/SwiftGen/bin/swiftgen\"\nelse\n echo \"warning: SwiftGen is not installed. Run 'pod install --repo-update' to install it.\"\nfi\n"; }; + 977ABB5AB2E4B7F1F11DDB6B /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-App-Core/Pods-App-Core-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-App-Core/Pods-App-Core-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-App-Core/Pods-App-Core-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; ED83AD5255805030E042D62A /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; diff --git a/Core/Core/Configuration/Config/BranchConfig.swift b/Core/Core/Configuration/Config/BranchConfig.swift index 43faec57f..6f2a785b6 100644 --- a/Core/Core/Configuration/Config/BranchConfig.swift +++ b/Core/Core/Configuration/Config/BranchConfig.swift @@ -18,8 +18,9 @@ public final class BranchConfig: NSObject { init(dictionary: [String: AnyObject]) { super.init() - enabled = dictionary[BranchKeys.enabled] as? Bool == true key = dictionary[BranchKeys.key] as? String + enabled = dictionary[BranchKeys.enabled] as? Bool ?? false && key?.isEmpty == false + } } diff --git a/OpenEdX/AppDelegate.swift b/OpenEdX/AppDelegate.swift index e10373d43..391bde85c 100644 --- a/OpenEdX/AppDelegate.swift +++ b/OpenEdX/AppDelegate.swift @@ -16,6 +16,7 @@ import GoogleSignIn import FacebookCore import MSAL import Theme +import BranchSDK @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { diff --git a/OpenEdX/Info.plist b/OpenEdX/Info.plist index b74f3967c..332b1fc1e 100644 --- a/OpenEdX/Info.plist +++ b/OpenEdX/Info.plist @@ -29,5 +29,12 @@ UIViewControllerBasedStatusBarAppearance + branch_universal_link_domains + + edx.app.link + edx-alternate.app.link + edx.test-app.link + edx-alternate.test-app.link + diff --git a/OpenEdX/Managers/DeepLinkManager/DeepLinkManager.swift b/OpenEdX/Managers/DeepLinkManager/DeepLinkManager.swift index 157bf2bb7..677188fee 100644 --- a/OpenEdX/Managers/DeepLinkManager/DeepLinkManager.swift +++ b/OpenEdX/Managers/DeepLinkManager/DeepLinkManager.swift @@ -10,15 +10,25 @@ import Core import UIKit public protocol DeepLinkService { - func configureWith(launchOptions: [UIApplication.LaunchOptionsKey: Any]?) - func handledURLWith(app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any]) -> Bool + func configureWith( + manager: DeepLinkManager, + config: ConfigProtocol, + launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) + + func handledURLWith( + app: UIApplication, + open url: URL, + options: [UIApplication.OpenURLOptionsKey: Any] + ) -> Bool } -class DeepLinkManager { +public class DeepLinkManager { private var services: [DeepLinkService] = [] + private let config: ConfigProtocol - // Init manager public init(config: ConfigProtocol) { + self.config = config services = servicesFor(config: config) } @@ -39,7 +49,7 @@ class DeepLinkManager { // Configure services func configureDeepLinkService(launchOptions: [UIApplication.LaunchOptionsKey: Any]?) { for service in services { - service.configureWith(launchOptions: launchOptions) + service.configureWith(manager: self, config: config, launchOptions: launchOptions) } } @@ -61,8 +71,11 @@ class DeepLinkManager { } // This method process the deep link with response parameters - func processDeepLink(with params: [String: Any]) { - if anyServiceEnabled { + func processDeepLink(with params: [AnyHashable: Any]?) { + guard let params = params else { return } + + let deeplink = DeepLink(dictionary: params) + if anyServiceEnabled && deeplink.type != .none { // redirect if possible } } diff --git a/OpenEdX/Managers/DeepLinkManager/Link/DeepLink.swift b/OpenEdX/Managers/DeepLinkManager/Link/DeepLink.swift index 3df8a21e6..8f7f3a407 100644 --- a/OpenEdX/Managers/DeepLinkManager/Link/DeepLink.swift +++ b/OpenEdX/Managers/DeepLinkManager/Link/DeepLink.swift @@ -6,13 +6,57 @@ // import Foundation +import Core enum DeepLinkType: String { + case courseDashboard = "course_dashboard" + case courseVideos = "course_videos" + case discussions = "course_discussion" + case courseDates = "course_dates" + case courseHandout = "course_handout" + case courseComponent = "course_component" + case courseAnnouncement = "course_announcement" + case discussionTopic = "discussion_topic" + case discussionPost = "discussion_post" + case discussionComment = "discussion_comment" + case discovery = "discovery" + case discoveryCourseDetail = "discovery_course_detail" + case discoveryProgramDetail = "discovery_program_detail" + case program = "program" + case programDetail = "program_detail" + case userProfile = "user_profile" + case profile = "profile" case none } +private enum DeepLinkKeys: String, RawStringExtractable { + case courseID = "course_id" + case pathID = "path_id" + case screenName = "screen_name" + case topicID = "topic_id" + case threadID = "thread_id" + case commentID = "comment_id" + case componentID = "component_id" +} + public class DeepLink { - init(dictionary: [String: Any]) { - + let courseID: String? + let screenName: String? + let pathID: String? + let topicID: String? + let threadID: String? + let commentID: String? + let componentID: String? + var type: DeepLinkType + + init(dictionary: [AnyHashable: Any]) { + courseID = dictionary[DeepLinkKeys.courseID] as? String + screenName = dictionary[DeepLinkKeys.screenName] as? String + pathID = dictionary[DeepLinkKeys.pathID] as? String + topicID = dictionary[DeepLinkKeys.topicID] as? String + threadID = dictionary[DeepLinkKeys.threadID] as? String + commentID = dictionary[DeepLinkKeys.commentID] as? String + componentID = dictionary[DeepLinkKeys.componentID] as? String + type = DeepLinkType(rawValue: screenName ?? DeepLinkType.none.rawValue) ?? .none } } diff --git a/OpenEdX/Managers/DeepLinkManager/Link/PushLink.swift b/OpenEdX/Managers/DeepLinkManager/Link/PushLink.swift index 262bda304..64d792b1a 100644 --- a/OpenEdX/Managers/DeepLinkManager/Link/PushLink.swift +++ b/OpenEdX/Managers/DeepLinkManager/Link/PushLink.swift @@ -6,8 +6,9 @@ // import Foundation +import Core -enum DataKeys: String { +enum DataKeys: String, RawStringExtractable { case title case body case aps @@ -19,11 +20,11 @@ public class PushLink: DeepLink { let title: String? let body: String? - override init(dictionary: [String: Any]) { - let aps = dictionary[DataKeys.aps.rawValue] as? [String: Any] - let alert = aps?[DataKeys.alert.rawValue] as? [String: Any] - title = alert?[DataKeys.title.rawValue] as? String - body = alert?[DataKeys.body.rawValue] as? String + override init(dictionary: [AnyHashable: Any]) { + let aps = dictionary[DataKeys.aps] as? [String: Any] + let alert = aps?[DataKeys.alert] as? [String: Any] + title = alert?[DataKeys.title] as? String + body = alert?[DataKeys.body] as? String super.init(dictionary: dictionary) } diff --git a/OpenEdX/Managers/DeepLinkManager/Services/BranchService.swift b/OpenEdX/Managers/DeepLinkManager/Services/BranchService.swift index 07a402a60..329617bfa 100644 --- a/OpenEdX/Managers/DeepLinkManager/Services/BranchService.swift +++ b/OpenEdX/Managers/DeepLinkManager/Services/BranchService.swift @@ -7,11 +7,26 @@ import Foundation import UIKit +import Core +import BranchSDK class BranchService: DeepLinkService { // configure service - func configureWith(launchOptions: [UIApplication.LaunchOptionsKey: Any]?) { + func configureWith( + manager: DeepLinkManager, + config: ConfigProtocol, + launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) { + guard let key = config.branch.key, config.branch.enabled else { return } + Branch.setBranchKey(key) + if Branch.branchKey() != nil { + Branch.getInstance().initSession(launchOptions: launchOptions) { params, error in + guard let params = params, error == nil else { return } + + manager.processDeepLink(with: params) + } + } } // handle url and call DeepLinkanager.processDeepLink() with params @@ -20,6 +35,7 @@ class BranchService: DeepLinkService { open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] ) -> Bool { - false + Branch.getInstance().application(app, open: url, options: options) + return true } } diff --git a/OpenEdX/Managers/PushNotificationsManager/PushNotificationsManager.swift b/OpenEdX/Managers/PushNotificationsManager/PushNotificationsManager.swift index 130818dd5..be832bcbb 100644 --- a/OpenEdX/Managers/PushNotificationsManager/PushNotificationsManager.swift +++ b/OpenEdX/Managers/PushNotificationsManager/PushNotificationsManager.swift @@ -22,7 +22,7 @@ protocol PushNotificationsListener { extension PushNotificationsListener { func didReceiveRemoteNotification(userInfo: [AnyHashable: Any]) { - guard let dictionary = userInfo as? [String: Any], + guard let dictionary = userInfo as? [String: AnyHashable], shouldListenNotification(userinfo: userInfo), let deepLinkManager = Container.shared.resolve(DeepLinkManager.self) else { return } diff --git a/OpenEdX/OpenEdX.entitlements b/OpenEdX/OpenEdX.entitlements index 80b5221de..08f1694af 100644 --- a/OpenEdX/OpenEdX.entitlements +++ b/OpenEdX/OpenEdX.entitlements @@ -8,5 +8,12 @@ Default + com.apple.developer.associated-domains + + applinks:edx.app.link + applinks:edx-alternate.app.link + applinks:edx.test-app.link + applinks:edx-alternate.test-app.link + diff --git a/Podfile b/Podfile index 291bcb28e..a482a8636 100644 --- a/Podfile +++ b/Podfile @@ -28,6 +28,7 @@ abstract_target "App" do pod 'SwiftUIIntrospect', '~> 0.8' pod 'Kingfisher', '~> 7.8' pod 'Swinject', '2.8.3' + pod 'BranchSDK', '~> 3.0.1' end target "Authorization" do diff --git a/Podfile.lock b/Podfile.lock index 20a87d7f1..c555629b0 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,5 +1,6 @@ PODS: - Alamofire (5.8.0) + - BranchSDK (3.0.1) - FirebaseAnalytics (10.15.0): - FirebaseAnalytics/AdIdSupport (= 10.15.0) - FirebaseCore (~> 10.0) @@ -112,6 +113,7 @@ PODS: DEPENDENCIES: - Alamofire (~> 5.7) + - BranchSDK (~> 3.0.1) - FirebaseAnalytics (~> 10.11) - FirebaseCrashlytics (~> 10.11) - KeychainSwift (~> 20.0) @@ -125,6 +127,7 @@ DEPENDENCIES: SPEC REPOS: trunk: - Alamofire + - BranchSDK - FirebaseAnalytics - FirebaseCore - FirebaseCoreExtension @@ -158,6 +161,7 @@ CHECKOUT OPTIONS: SPEC CHECKSUMS: Alamofire: 0e92e751b3e9e66d7982db43919d01f313b8eb91 + BranchSDK: e268bcf41469051c9e83efcd6fd85d0ba91d1d0f FirebaseAnalytics: 47cef43728f81a839cf1306576bdd77ffa2eac7e FirebaseCore: 2cec518b43635f96afe7ac3a9c513e47558abd2e FirebaseCoreExtension: d3f1ea3725fb41f56e8fbfb29eeaff54e7ffb8f6 @@ -180,6 +184,6 @@ SPEC CHECKSUMS: SwiftyMocky: c5e96e4ff76ec6dbf5a5941aeb039b5a546954a0 Swinject: 893c9a543000ac2f10ee4cbaf0933c6992c935d5 -PODFILE CHECKSUM: 544edab2f9ecc4ac18973fb8865f1d0613ec8a28 +PODFILE CHECKSUM: 758e4bb1c4ccff8f637ac431533c4e2a8d22e281 -COCOAPODS: 1.15.0 +COCOAPODS: 1.15.2 diff --git a/config_script/process_config.py b/config_script/process_config.py index 36340bfc3..5d40f9e6f 100644 --- a/config_script/process_config.py +++ b/config_script/process_config.py @@ -133,11 +133,16 @@ def __init__(self, plist_manager): def get_environment_variable(self, variable): return os.getenv(variable) - def add_url_scheme(self, scheme, plist): + def add_url_scheme(self, scheme, plist, addURLIdentifier): body = { 'CFBundleTypeRole': 'Editor', 'CFBundleURLSchemes': scheme } + + if addBundleURL: + bundle_identifier = self.plist_manager.get_bundle_identifier() + body['CFBundleURLName'] = bundle_identifier + existing = plist.get('CFBundleURLTypes', []) found = any(scheme in entry.get('CFBundleURLSchemes', []) for entry in existing) @@ -177,7 +182,21 @@ def add_firebase_config(self, config, firebase_info_plist_path): self.plist_manager.write_to_plist_file(plist, self.plist_manager.get_firebase_info_plist_path()) else: print("Firebase config is empty. Skipping") - + + def add_branch_config(self, config, plist): + branch = config.get('BRANCH', {}) + enabled = branch.get('ENABLED') + uriScheme = branch.get('URI_SCHEME') + + if enabled: + if uriScheme: + scheme = [uriScheme] + else: + bundle_identifier = self.plist_manager.get_bundle_identifier() + scheme = [bundle_identifier] + + self.add_url_scheme(scheme, plist, True) + def add_facebook_config(self, config, plist): facebook = config.get('FACEBOOK', {}) key = facebook.get('FACEBOOK_APP_ID') @@ -188,7 +207,7 @@ def add_facebook_config(self, config, plist): plist["FacebookClientToken"] = client_token plist["FacebookDisplayName"] = self.plist_manager.get_product_name() scheme = ["fb" + key] - self.add_url_scheme(scheme, plist) + self.add_url_scheme(scheme, plist, False) def add_google_config(self, config, plist): google = config.get('GOOGLE', {}) @@ -198,7 +217,7 @@ def add_google_config(self, config, plist): if key and client_id: plist["GIDClientID"] = client_id scheme = ['.'.join(reversed(key.split('.')))] - self.add_url_scheme(scheme, plist) + self.add_url_scheme(scheme, plist, False) def add_microsoft_config(self, config, plist): microsoft = config.get('MICROSOFT', {}) @@ -207,7 +226,7 @@ def add_microsoft_config(self, config, plist): if key: bundle_identifier = self.plist_manager.get_bundle_identifier() scheme = ["msauth." + bundle_identifier] - self.add_url_scheme(scheme, plist) + self.add_url_scheme(scheme, plist, False) self.add_application_query_schemes(["msauthv2", "msauthv3"], plist) def update_info_plist(self, plist_data, plist_path): @@ -264,6 +283,7 @@ def process_plist_files(configuration_manager, plist_manager, config): configuration_manager.add_facebook_config(config, info_plist_content) configuration_manager.add_google_config(config, info_plist_content) configuration_manager.add_microsoft_config(config, info_plist_content) + configuration_manager.add_branch_config(config, info_plist_content) configuration_manager.update_info_plist(info_plist_content, info_plist_path) From 7e4a2c206edccf7d2484b455d7067155162290ea Mon Sep 17 00:00:00 2001 From: Saeed Bashir Date: Fri, 16 Feb 2024 16:01:28 +0500 Subject: [PATCH 2/6] fix: fix crash because of unnamed variable --- config_script/process_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config_script/process_config.py b/config_script/process_config.py index 5d40f9e6f..86bacae55 100644 --- a/config_script/process_config.py +++ b/config_script/process_config.py @@ -133,7 +133,7 @@ def __init__(self, plist_manager): def get_environment_variable(self, variable): return os.getenv(variable) - def add_url_scheme(self, scheme, plist, addURLIdentifier): + def add_url_scheme(self, scheme, plist, addBundleURL): body = { 'CFBundleTypeRole': 'Editor', 'CFBundleURLSchemes': scheme From fffde3c0eb6b87cd7f2146e3b236eb725904926c Mon Sep 17 00:00:00 2001 From: Saeed Bashir Date: Mon, 19 Feb 2024 10:49:32 +0500 Subject: [PATCH 3/6] refactor: address review feedback --- Core/Core.xcodeproj/project.pbxproj | 35 +++++++++---------- OpenEdX/AppDelegate.swift | 1 - OpenEdX/Info.plist | 7 ---- .../Services/BranchService.swift | 3 +- Podfile | 1 - Podfile.lock | 6 +--- config_script/process_config.py | 16 ++++++++- 7 files changed, 34 insertions(+), 35 deletions(-) diff --git a/Core/Core.xcodeproj/project.pbxproj b/Core/Core.xcodeproj/project.pbxproj index a164f4918..28ccc5ca5 100644 --- a/Core/Core.xcodeproj/project.pbxproj +++ b/Core/Core.xcodeproj/project.pbxproj @@ -126,6 +126,7 @@ 07DDFCBD29A780BB00572595 /* UINavigationController+Animation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07DDFCBC29A780BB00572595 /* UINavigationController+Animation.swift */; }; 07E0939F2B308D2800F1E4B2 /* Data_Certificate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07E0939E2B308D2800F1E4B2 /* Data_Certificate.swift */; }; 141F1D302B7328D4009E81EB /* WebviewCookiesUpdateProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 141F1D2F2B7328D4009E81EB /* WebviewCookiesUpdateProtocol.swift */; }; + 142EDD6C2B831D1400F9F320 /* BranchSDK in Frameworks */ = {isa = PBXBuildFile; productRef = 142EDD6B2B831D1400F9F320 /* BranchSDK */; }; A53A32352B233DEC005FE38A /* ThemeConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = A53A32342B233DEC005FE38A /* ThemeConfig.swift */; }; A595689B2B6173DF00ED4F90 /* BranchConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = A595689A2B6173DF00ED4F90 /* BranchConfig.swift */; }; A5F4E7B52B61544A00ACD166 /* BrazeConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5F4E7B42B61544A00ACD166 /* BrazeConfig.swift */; }; @@ -355,6 +356,7 @@ BAF0D4CB2AD6AE14007AC334 /* FacebookLogin in Frameworks */, 025EF2F62971740000B838AB /* YouTubePlayerKit in Frameworks */, C8C446EF233F81B9FABB77D2 /* Pods_App_Core.framework in Frameworks */, + 142EDD6C2B831D1400F9F320 /* BranchSDK in Frameworks */, BA8FA66C2AD59BBC00EA029A /* GoogleSignIn in Frameworks */, E055A5392B18DC95008D9E5E /* Theme.framework in Frameworks */, ); @@ -860,7 +862,6 @@ 0770DE0428D07831006D8A5D /* Sources */, 0770DE0528D07831006D8A5D /* Frameworks */, 0770DE0628D07831006D8A5D /* Resources */, - 977ABB5AB2E4B7F1F11DDB6B /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -871,6 +872,7 @@ 025EF2F52971740000B838AB /* YouTubePlayerKit */, BA8FA66B2AD59BBC00EA029A /* GoogleSignIn */, BAF0D4CA2AD6AE14007AC334 /* FacebookLogin */, + 142EDD6B2B831D1400F9F320 /* BranchSDK */, ); productName = Core; productReference = 0770DE0828D07831006D8A5D /* Core.framework */; @@ -910,6 +912,7 @@ 025EF2F42971740000B838AB /* XCRemoteSwiftPackageReference "YouTubePlayerKit" */, BA8FA65E2AD574D700EA029A /* XCRemoteSwiftPackageReference "GoogleSignIn-iOS" */, BA8FA6712AD6ABA300EA029A /* XCRemoteSwiftPackageReference "facebook-ios-sdk" */, + 142EDD6A2B831D1400F9F320 /* XCRemoteSwiftPackageReference "ios-branch-sdk-spm" */, ); productRefGroup = 0770DE0928D07831006D8A5D /* Products */; projectDirPath = ""; @@ -962,23 +965,6 @@ shellPath = /bin/sh; shellScript = "if [[ -f \"${PODS_ROOT}/SwiftGen/bin/swiftgen\" ]]; then\n \"${PODS_ROOT}/SwiftGen/bin/swiftgen\"\nelse\n echo \"warning: SwiftGen is not installed. Run 'pod install --repo-update' to install it.\"\nfi\n"; }; - 977ABB5AB2E4B7F1F11DDB6B /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-App-Core/Pods-App-Core-resources-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Copy Pods Resources"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-App-Core/Pods-App-Core-resources-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-App-Core/Pods-App-Core-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; ED83AD5255805030E042D62A /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -2182,6 +2168,14 @@ minimumVersion = 1.5.0; }; }; + 142EDD6A2B831D1400F9F320 /* XCRemoteSwiftPackageReference "ios-branch-sdk-spm" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/BranchMetrics/ios-branch-sdk-spm"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 3.2.0; + }; + }; BA8FA65E2AD574D700EA029A /* XCRemoteSwiftPackageReference "GoogleSignIn-iOS" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/google/GoogleSignIn-iOS"; @@ -2206,6 +2200,11 @@ package = 025EF2F42971740000B838AB /* XCRemoteSwiftPackageReference "YouTubePlayerKit" */; productName = YouTubePlayerKit; }; + 142EDD6B2B831D1400F9F320 /* BranchSDK */ = { + isa = XCSwiftPackageProductDependency; + package = 142EDD6A2B831D1400F9F320 /* XCRemoteSwiftPackageReference "ios-branch-sdk-spm" */; + productName = BranchSDK; + }; BA8FA66B2AD59BBC00EA029A /* GoogleSignIn */ = { isa = XCSwiftPackageProductDependency; package = BA8FA65E2AD574D700EA029A /* XCRemoteSwiftPackageReference "GoogleSignIn-iOS" */; diff --git a/OpenEdX/AppDelegate.swift b/OpenEdX/AppDelegate.swift index 391bde85c..e10373d43 100644 --- a/OpenEdX/AppDelegate.swift +++ b/OpenEdX/AppDelegate.swift @@ -16,7 +16,6 @@ import GoogleSignIn import FacebookCore import MSAL import Theme -import BranchSDK @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { diff --git a/OpenEdX/Info.plist b/OpenEdX/Info.plist index 332b1fc1e..b74f3967c 100644 --- a/OpenEdX/Info.plist +++ b/OpenEdX/Info.plist @@ -29,12 +29,5 @@ UIViewControllerBasedStatusBarAppearance - branch_universal_link_domains - - edx.app.link - edx-alternate.app.link - edx.test-app.link - edx-alternate.test-app.link - diff --git a/OpenEdX/Managers/DeepLinkManager/Services/BranchService.swift b/OpenEdX/Managers/DeepLinkManager/Services/BranchService.swift index 329617bfa..56993ea23 100644 --- a/OpenEdX/Managers/DeepLinkManager/Services/BranchService.swift +++ b/OpenEdX/Managers/DeepLinkManager/Services/BranchService.swift @@ -35,7 +35,6 @@ class BranchService: DeepLinkService { open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] ) -> Bool { - Branch.getInstance().application(app, open: url, options: options) - return true + return Branch.getInstance().application(app, open: url, options: options) } } diff --git a/Podfile b/Podfile index a482a8636..291bcb28e 100644 --- a/Podfile +++ b/Podfile @@ -28,7 +28,6 @@ abstract_target "App" do pod 'SwiftUIIntrospect', '~> 0.8' pod 'Kingfisher', '~> 7.8' pod 'Swinject', '2.8.3' - pod 'BranchSDK', '~> 3.0.1' end target "Authorization" do diff --git a/Podfile.lock b/Podfile.lock index c555629b0..e96b3c125 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,6 +1,5 @@ PODS: - Alamofire (5.8.0) - - BranchSDK (3.0.1) - FirebaseAnalytics (10.15.0): - FirebaseAnalytics/AdIdSupport (= 10.15.0) - FirebaseCore (~> 10.0) @@ -113,7 +112,6 @@ PODS: DEPENDENCIES: - Alamofire (~> 5.7) - - BranchSDK (~> 3.0.1) - FirebaseAnalytics (~> 10.11) - FirebaseCrashlytics (~> 10.11) - KeychainSwift (~> 20.0) @@ -127,7 +125,6 @@ DEPENDENCIES: SPEC REPOS: trunk: - Alamofire - - BranchSDK - FirebaseAnalytics - FirebaseCore - FirebaseCoreExtension @@ -161,7 +158,6 @@ CHECKOUT OPTIONS: SPEC CHECKSUMS: Alamofire: 0e92e751b3e9e66d7982db43919d01f313b8eb91 - BranchSDK: e268bcf41469051c9e83efcd6fd85d0ba91d1d0f FirebaseAnalytics: 47cef43728f81a839cf1306576bdd77ffa2eac7e FirebaseCore: 2cec518b43635f96afe7ac3a9c513e47558abd2e FirebaseCoreExtension: d3f1ea3725fb41f56e8fbfb29eeaff54e7ffb8f6 @@ -184,6 +180,6 @@ SPEC CHECKSUMS: SwiftyMocky: c5e96e4ff76ec6dbf5a5941aeb039b5a546954a0 Swinject: 893c9a543000ac2f10ee4cbaf0933c6992c935d5 -PODFILE CHECKSUM: 758e4bb1c4ccff8f637ac431533c4e2a8d22e281 +PODFILE CHECKSUM: 544edab2f9ecc4ac18973fb8865f1d0613ec8a28 COCOAPODS: 1.15.2 diff --git a/config_script/process_config.py b/config_script/process_config.py index 86bacae55..9987dab98 100644 --- a/config_script/process_config.py +++ b/config_script/process_config.py @@ -149,7 +149,16 @@ def add_url_scheme(self, scheme, plist, addBundleURL): if not found: existing.append(body) plist['CFBundleURLTypes'] = existing - + + def add_custom_array(self, key, array, plist): + existing = plist.get(key, []) + + for element in array: + if element not in existing: + existing.append(element) + + plist[key] = existing + def add_application_query_schemes(self, schemes, plist): existing = plist.get('LSApplicationQueriesSchemes', []) for scheme in schemes: @@ -187,6 +196,10 @@ def add_branch_config(self, config, plist): branch = config.get('BRANCH', {}) enabled = branch.get('ENABLED') uriScheme = branch.get('URI_SCHEME') + prefix = branch.get('DEEPLINK_PREFIX') + + if not prefix: + prefix = "edx" if enabled: if uriScheme: @@ -195,6 +208,7 @@ def add_branch_config(self, config, plist): bundle_identifier = self.plist_manager.get_bundle_identifier() scheme = [bundle_identifier] + self.add_custom_array("branch_universal_link_domains", [prefix+".app.link", prefix+"-alternate.app.link", prefix+".test-app.link", prefix+"-alternate.test-app.link"], plist) self.add_url_scheme(scheme, plist, True) def add_facebook_config(self, config, plist): From d74d03d67e04c99abc6ff82cb2d76e2a55467ee6 Mon Sep 17 00:00:00 2001 From: Saeed Bashir Date: Mon, 19 Feb 2024 16:25:38 +0500 Subject: [PATCH 4/6] chore: add associated domains based on config --- OpenEdX/OpenEdX.entitlements | 9 ++------- config_script/process_config.py | 35 +++++++++++++++++++++++++++++---- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/OpenEdX/OpenEdX.entitlements b/OpenEdX/OpenEdX.entitlements index 08f1694af..3b6f8f26b 100644 --- a/OpenEdX/OpenEdX.entitlements +++ b/OpenEdX/OpenEdX.entitlements @@ -2,18 +2,13 @@ + CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION + aps-environment development com.apple.developer.applesignin Default - com.apple.developer.associated-domains - - applinks:edx.app.link - applinks:edx-alternate.app.link - applinks:edx.test-app.link - applinks:edx-alternate.test-app.link - diff --git a/config_script/process_config.py b/config_script/process_config.py index 9987dab98..3c497a6b8 100644 --- a/config_script/process_config.py +++ b/config_script/process_config.py @@ -22,6 +22,9 @@ def get_bundle_identifier(self): def get_info_plist_path(self): return os.getenv('INFOPLIST_PATH') + def get_entitlements_plist_path(self): + return os.getenv('CODE_SIGN_ENTITLEMENTS') + def get_wrapper_name(self): return os.getenv('WRAPPER_NAME') @@ -40,6 +43,15 @@ def get_app_info_plist_path(self): else: return None + def get_entitlements_path(self): + built_products_path = self.get_built_products_path() + entitlements_plist_path = self.get_entitlements_path() + + if built_products_path and entitlements_plist_path: + return os.path.join(built_products_path, entitlements_plist_path) + else: + return None + def get_firebase_info_plist_path(self): built_products_path = self.get_built_products_path() wrapper_name = self.get_wrapper_name() @@ -192,7 +204,7 @@ def add_firebase_config(self, config, firebase_info_plist_path): else: print("Firebase config is empty. Skipping") - def add_branch_config(self, config, plist): + def add_branch_config(self, config, plist, entitlements): branch = config.get('BRANCH', {}) enabled = branch.get('ENABLED') uriScheme = branch.get('URI_SCHEME') @@ -208,8 +220,19 @@ def add_branch_config(self, config, plist): bundle_identifier = self.plist_manager.get_bundle_identifier() scheme = [bundle_identifier] - self.add_custom_array("branch_universal_link_domains", [prefix+".app.link", prefix+"-alternate.app.link", prefix+".test-app.link", prefix+"-alternate.test-app.link"], plist) - self.add_url_scheme(scheme, plist, True) + self.add_custom_array("branch_universal_link_domains", [ + prefix+".app.link", + prefix+"-alternate.app.link", + prefix+".test-app.link", + prefix+"-alternate.test-app.link" + ], plist) + self.add_custom_array("com.apple.developer.associated-domains", [ + "applinks:"+prefix+".app.link", + "applinks:"+prefix+"-alternate.app.link", + "applinks:"+prefix+".test-app.link", + "applinks:"+prefix+"-alternate.test-app.link" + ], entitlements) + self.add_url_scheme(scheme, plist, True) def add_facebook_config(self, config, plist): facebook = config.get('FACEBOOK', {}) @@ -289,6 +312,9 @@ def get_current_config(configuration, scheme_mappings): return None def process_plist_files(configuration_manager, plist_manager, config): + entitlements_path = plist_manager.get_entitlements_plist_path() + entitlements_content = plist_manager.get_info_plist_contents(entitlements_path) + firebase_info_plist_path = plist_manager.get_firebase_config_path() info_plist_path = plist_manager.get_app_info_plist_path() info_plist_content = plist_manager.get_info_plist_contents(info_plist_path) @@ -297,9 +323,10 @@ def process_plist_files(configuration_manager, plist_manager, config): configuration_manager.add_facebook_config(config, info_plist_content) configuration_manager.add_google_config(config, info_plist_content) configuration_manager.add_microsoft_config(config, info_plist_content) - configuration_manager.add_branch_config(config, info_plist_content) + configuration_manager.add_branch_config(config, info_plist_content, entitlements_content) configuration_manager.update_info_plist(info_plist_content, info_plist_path) + configuration_manager.update_info_plist(entitlements_content, entitlements_path) bundle_config_path = plist_manager.get_bundle_config_path() config_plist = plist_manager.yaml_to_plist() From 3f665537b09deee2cd4b3387e5948d065b15137c Mon Sep 17 00:00:00 2001 From: Saeed Bashir Date: Mon, 19 Feb 2024 16:31:17 +0500 Subject: [PATCH 5/6] refactor: adding CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION at correct place --- OpenEdX.xcodeproj/project.pbxproj | 6 ++++++ OpenEdX/OpenEdX.entitlements | 2 -- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/OpenEdX.xcodeproj/project.pbxproj b/OpenEdX.xcodeproj/project.pbxproj index 85704b35b..b8b38fd4a 100644 --- a/OpenEdX.xcodeproj/project.pbxproj +++ b/OpenEdX.xcodeproj/project.pbxproj @@ -639,6 +639,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION = YES; CODE_SIGN_ENTITLEMENTS = OpenEdX/OpenEdX.entitlements; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; @@ -727,6 +728,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION = YES; CODE_SIGN_ENTITLEMENTS = OpenEdX/OpenEdX.entitlements; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; @@ -821,6 +823,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION = YES; CODE_SIGN_ENTITLEMENTS = OpenEdX/OpenEdX.entitlements; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; @@ -909,6 +912,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION = YES; CODE_SIGN_ENTITLEMENTS = OpenEdX/OpenEdX.entitlements; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; @@ -1057,6 +1061,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION = YES; CODE_SIGN_ENTITLEMENTS = OpenEdX/OpenEdX.entitlements; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; @@ -1091,6 +1096,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION = YES; CODE_SIGN_ENTITLEMENTS = OpenEdX/OpenEdX.entitlements; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; diff --git a/OpenEdX/OpenEdX.entitlements b/OpenEdX/OpenEdX.entitlements index 3b6f8f26b..80b5221de 100644 --- a/OpenEdX/OpenEdX.entitlements +++ b/OpenEdX/OpenEdX.entitlements @@ -2,8 +2,6 @@ - CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION - aps-environment development com.apple.developer.applesignin From 444f008d567c6637189140cff3e75ad6e794c27d Mon Sep 17 00:00:00 2001 From: Saeed Bashir Date: Mon, 19 Feb 2024 17:07:31 +0500 Subject: [PATCH 6/6] chore: adding default values for Associated Domains --- OpenEdX/OpenEdX.entitlements | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/OpenEdX/OpenEdX.entitlements b/OpenEdX/OpenEdX.entitlements index 80b5221de..08f1694af 100644 --- a/OpenEdX/OpenEdX.entitlements +++ b/OpenEdX/OpenEdX.entitlements @@ -8,5 +8,12 @@ Default + com.apple.developer.associated-domains + + applinks:edx.app.link + applinks:edx-alternate.app.link + applinks:edx.test-app.link + applinks:edx-alternate.test-app.link +