Filters

iOS Basic Integration

👍

SDK Stats

Open Source Github Repo: https://github.com/BranchMetrics/ios-branch-deep-linking

SDK Size: ~220kb (with all Branch features enabled)

Speed: Median 80ms to 250ms

Minimum XCode Version: 12.3+

Minimum OS Version: iOS 9+

📘

iOS SDK 2.0.0+

With the release of the iOS SDK, we have changed the framework name from Branch to BranchSDK. Imports will need to be updated.

1. Configure the Branch Dashboard

3022 989

2. Configure Bundle Identifier

2188

3. Configure Associated Domains

  • Add your link domains from your Branch Dashboard
  • -alternate is needed to ensure proper functioning of Universal Links & Deep Views for users that do not have your app installed.
  • test- is needed if you need use a test key
  • If you use a custom link domain, you will need to include your old link domain, your -alternate link domain, and your new link domain
2188

4. Configure Entitlements

  • Confirm entitlements are within target (This file is configured automatically when completing the steps above in Capabilities tab of Xcode)
2188

5. Configure Info.plist

  • Add Branch Dashboard values
    • Add branch_universal_link_domains with your live key domain
    • Add branch_key with your current Branch keys
    • Add your URI scheme as URL Types -> Item 0 -> URL Schemes
2188
  • The Info.plist can also be configured by pasting this XML snippet into the source code.
<key>branch_universal_link_domains</key>
    <array>
        <string>timber.app.link</string>
        <string>timber-alternate.app.link</string>
        <string>timber.test.app.link</string>
        <string>timber-alternate.test.app.link</string>
    </array>
    <key>CFBundleURLTypes</key>
    <array>
        <dict>
            <key>CFBundleTypeRole</key>
            <string>Editor</string>
            <key>CFBundleURLSchemes</key>
            <array>
                <string>Timber</string>
            </array>
            <key>CFBundleURLName</key>
            <string>io.Branch.Timber</string>
        </dict>
    </array>
    <key>branch_key</key>
    <dict>
        <key>live</key>
        <string>key_live_hd1YSj4JCoSXyxk9R2jsyjrclAslPL21G</string>
        <key>test</key>
        <string>key_test_pl5EWe1UNaOQyus7V2ipnasydFspH54C</string>
    </dict>

6. Install Branch

Please choose one of the following integration methods to install the Branch SDK into your app.


Learn more about Swift Package Manager.

To add the Branch iOS SDK to your project as a Swift package dependency:

  1. In Xcode, go to File -> Add Packages.
  2. Use the search bar to look for either ios-branch-sdk-spm or https://github.com/BranchMetrics/ios-branch-sdk-spm.
  3. Select the ios-branch-sdk-spm package and click Add Package to continue through the installer.
  4. Check that the Branch iOS SDK now appears in your project's Package Dependencies tab.
  5. Navigate to your project's Build Phases tab and expand the Link Binary With Libraries section.
  6. Click on the + button to search for and add the following dependencies:
  7. Linked Frameworks and Libraries Import Status Description
    CoreServices Required Access and manage key operating system services, such as launch and identity services.
    SystemConfiguration Required Allow applications to access a device’s network configuration settings. Determine the reachability of the device, such as whether Wi-Fi or cell connectivity is active. Used for connection type.
    CoreTelephony Required Access information about a user’s cellular service provider, such as its unique identifier and whether the carrier allows VoIP. Used for mobile carrier.
    WebKit Required Integrate web content seamlessly into your app, and customize content interactions to meet your app’s needs. Used for web browser user agent.
    CoreSpotlight Required Index your app so users can search the content from Spotlight and Safari.
    AdServices Optional Attribute app-download campaigns that originate from the App Store, Apple News, or Stocks on iOS devices. This is used for obtaining Apple Attribution Token.
    AdSupport Optional Provide apps with access to an advertising identifier. This will give access to IDFA.
    StoreKit Optional Provide apps with ability to measure ad-driven installs via SKAdNetwork.
    LinkPresentation Optional Support customization of share sheet.
  8. Confirm that you have the required dependencies added, as well as any optional ones you would like.

Learn more about CocoaPods.

To add the Branch iOS SDK to your project using the CocoaPods dependency manager:

  1. Open your project's podfile. If it doesn't have one yet, create one using pod init.
  2. Use the following sample code for your podfile, and base it on your project's requirements:
        		platform :ios, '11.0'
    
    # Replace APP_NAME with the name of your app
    target 'APP_NAME' do
    
    # If using Swift, include the following line:
    use_frameworks!
    
    	# For Branch iOS SDK 2.0.0+
    	pod 'BranchSDK'
    
    	# For Branch iOS SDK <2.0.0, remove previous pod line and uncomment the following line:
    	# pod 'Branch'
    end
        	
  3. Run pod install && pod update to install the project dependencies.
  4. Confirm in your target's General tab that a Pods_... dependency is now listed.

Learn more about Carthage.

Please note that Carthage 0.37.0+ is required for xcframework support, and in turn Branch requires the Carthage --use-xcframeworks option.

To add the Branch iOS SDK to your project using the Carthage dependency manager:

  1. Add github "BranchMetrics/ios-branch-deep-linking" to your project's Cartfile.
  2. Navigate to your project's Build Phases tab and expand the Link Binary With Libraries section.
  3. Click on the + button to search for and add the following dependencies:
  4. Linked Frameworks and Libraries Import Status Description
    CoreServices Required Access and manage key operating system services, such as launch and identity services.
    SystemConfiguration Required Allow applications to access a device’s network configuration settings. Determine the reachability of the device, such as whether Wi-Fi or cell connectivity is active. Used for connection type.
    CoreTelephony Required Access information about a user’s cellular service provider, such as its unique identifier and whether the carrier allows VoIP. Used for mobile carrier.
    WebKit Required Integrate web content seamlessly into your app, and customize content interactions to meet your app’s needs. Used for web browser user agent.
    CoreSpotlight Required Index your app so users can search the content from Spotlight and Safari.
    AdServices Optional Attribute app-download campaigns that originate from the App Store, Apple News, or Stocks on iOS devices. This is used for obtaining Apple Attribution Token.
    AdSupport Optional Provide apps with access to an advertising identifier. This will give access to IDFA.
    StoreKit Optional Provide apps with ability to measure ad-driven installs via SKAdNetwork.
    LinkPresentation Optional Support customization of share sheet.
  5. Confirm that you have the required dependencies added, as well as any optional ones you would like.

  1. Manually install the Branch xcframework from GitHub. If you prefer a static xcframework, please download the pre-built Branch static ZIP file available with Branch iOS SDK v1.38.0+.
  2. Navigate to your project's Build Phases tab and expand the Link Binary With Libraries section.
  3. Click on the + button to search for and add the following dependencies:
  4. Linked Frameworks and Libraries Import Status Description
    CoreServices Required Access and manage key operating system services, such as launch and identity services.
    SystemConfiguration Required Allow applications to access a device’s network configuration settings. Determine the reachability of the device, such as whether Wi-Fi or cell connectivity is active. Used for connection type.
    CoreTelephony Required Access information about a user’s cellular service provider, such as its unique identifier and whether the carrier allows VoIP. Used for mobile carrier.
    WebKit Required Integrate web content seamlessly into your app, and customize content interactions to meet your app’s needs. Used for web browser user agent.
    CoreSpotlight Required Index your app so users can search the content from Spotlight and Safari.
    AdServices Optional Attribute app-download campaigns that originate from the App Store, Apple News, or Stocks on iOS devices. This is used for obtaining Apple Attribution Token.
    AdSupport Optional Provide apps with access to an advertising identifier. This will give access to IDFA.
    StoreKit Optional Provide apps with ability to measure ad-driven installs via SKAdNetwork.
    LinkPresentation Optional Support customization of share sheet.
  5. Confirm that you have the required dependencies added, as well as any optional ones you would like.

7. Initialize Branch

🚧

Branch SDK and Firebase SDK

If you are using both the Branch SDK and the Firebase SDK for deep linking, you must configure Branch initialization differently. After completing the steps below, visit how to Handle Branch Links when using Branch & Firebase SDK

Apps not Using Scenes

  • Update your app's 'AppDelegate.swift'
import UIKit
// iOS SDK 2.0.0+
import BranchSDK
// iOS SDK <2.0.0
// import Branch

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
  // if you are using the TEST key
  Branch.setUseTestBranchKey(true)
  // listener for Branch Deep Link data
  Branch.getInstance().initSession(launchOptions: launchOptions) { (params, error) in
       // do stuff with deep link data (nav to page, display content, etc)
      print(params as? [String: AnyObject] ?? {})
  }
  return true
}

func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
    Branch.getInstance().application(app, open: url, options: options)
    return true
}

func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
  // handler for Universal Links
    Branch.getInstance().continue(userActivity)
    return true
}

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
  // handler for Push Notifications
  Branch.getInstance().handlePushNotification(userInfo)
}
#import "AppDelegate.h"
// iOS SDK 2.0.0+
@import BranchSDK;
// iOS SDK <2.0.0
// @import Branch;

@interface AppDelegate ()

@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  // if you are using the TEST key
  [Branch setUseTestBranchKey:YES];
  // listener for Branch Deep Link data
  [[Branch getInstance] initSessionWithLaunchOptions:launchOptions andRegisterDeepLinkHandler:^(NSDictionary * _Nonnull params, NSError * _Nullable error) {
    // do stuff with deep link data (nav to page, display content, etc)
    NSLog(@"%@", params);
  }];
  return YES;
}

- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
  [[Branch getInstance] application:app openURL:url options:options];
  return YES;
}

- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler {
  // handler for Universal Links
  [[Branch getInstance] continueUserActivity:userActivity];
  return YES;
}

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
  // handler for Push Notifications
  [[Branch getInstance] handlePushNotification:userInfo];
}

@end

Apps Using Scenes

  • In your app's AppDelegate file:
import UIKit
// iOS SDK 2.0.0+
import BranchSDK
// iOS SDK <2.0.0
// import Branch

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
      // Override point for customization after application launch.

              // This version of initSession includes the source UIScene in the callback
        BranchScene.shared().initSession(launchOptions: launchOptions, registerDeepLinkHandler: { (params, error, scene) in
            
        })
      return true
  }

  func applicationWillTerminate(_ application: UIApplication) {
      // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
  }

  // MARK: UISceneSession Lifecycle

  func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
      // Called when a new scene session is being created.
      // Use this method to select a configuration to create the new scene with.
      return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
  }

  func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
      // Called when the user discards a scene session.
      // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
      // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
  }
}
#import "AppDelegate.h"
// iOS SDK 2.0.0+
@import BranchSDK;
// iOS SDK <2.0.0
// @import Branch;

@interface AppDelegate ()

@end

@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.

    [[BranchScene shared] initSessionWithLaunchOptions:launchOptions registerDeepLinkHandler:^(NSDictionary * _Nullable params, NSError * _Nullable error, UIScene * _Nullable scene) {
        
    }];

    return YES;
}


- (void)applicationWillTerminate:(UIApplication *)application {
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}


#pragma mark - UISceneSession lifecycle


- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options {
    // Called when a new scene session is being created.
    // Use this method to select a configuration to create the new scene with.
    return [[UISceneConfiguration alloc] initWithName:@"Default Configuration" sessionRole:connectingSceneSession.role];
}


- (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet<UISceneSession *> *)sceneSessions {
    // Called when the user discards a scene session.
    // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
    // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}

@end
  • In your app's SceneDelegate file:
import UIKit
// iOS SDK 2.0.0+
import BranchSDK
// iOS SDK <2.0.0
// import Branch

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
  var window: UIWindow?
  func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
      // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
      // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
      // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
      guard let _ = (scene as? UIWindowScene) else { return }
    
      // workaround for SceneDelegate continueUserActivity not getting called on cold start
      if let userActivity = connectionOptions.userActivities.first {
        BranchScene.shared().scene(scene, continue: userActivity)
      } else if !connectionOptions.urlContexts.isEmpty {
        BranchScene.shared().scene(scene, openURLContexts: connectionOptions.urlContexts)
      }
  }
  
  func sceneDidDisconnect(_ scene: UIScene) {
      // Called as the scene is being released by the system.
      // This occurs shortly after the scene enters the background, or when its session is discarded.
      // Release any resources associated with this scene that can be re-created the next time the scene connects.
      // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).
  }
  
  func sceneDidBecomeActive(_ scene: UIScene) {
      // Called when the scene has moved from an inactive state to an active state.
      // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
  }
  
  func sceneWillResignActive(_ scene: UIScene) {
      // Called when the scene will move from an active state to an inactive state.
      // This may occur due to temporary interruptions (ex. an incoming phone call).
  }
  
  func sceneWillEnterForeground(_ scene: UIScene) {
      // Called as the scene transitions from the background to the foreground.
      // Use this method to undo the changes made on entering the background.
  }
  
  func sceneDidEnterBackground(_ scene: UIScene) {
      // Called as the scene transitions from the foreground to the background.
      // Use this method to save data, release shared resources, and store enough scene-specific state information
      // to restore the scene back to its current state.
  }
  
  func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
        BranchScene.shared().scene(scene, continue: userActivity)
  }
  
  func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
        BranchScene.shared().scene(scene, openURLContexts: URLContexts)
  }
}
#import "SceneDelegate.h"
// iOS SDK 2.0.0+
@import BranchSDK;
// iOS SDK <2.0.0
// @import Branch;

@interface SceneDelegate ()
@end
@implementation SceneDelegate
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
    // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
    // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
    // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
    // workaround for SceneDelegate continueUserActivity not getting called on cold start
    NSUserActivity *activity = [[connectionOptions userActivities] allObjects].firstObject;

    if (activity) {
            [[BranchScene shared] scene:scene continueUserActivity:activity];
     } else if ([[connectionOptions URLContexts] count] != 0) {
            [[BranchScene shared] scene:scene openURLContexts: [connectionOptions URLContexts]];
     }  
}
- (void)sceneDidDisconnect:(UIScene *)scene {
    // Called as the scene is being released by the system.
    // This occurs shortly after the scene enters the background, or when its session is discarded.
    // Release any resources associated with this scene that can be re-created the next time the scene connects.
    // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).
}
- (void)sceneDidBecomeActive:(UIScene *)scene {
    // Called when the scene has moved from an inactive state to an active state.
    // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
}
- (void)sceneWillResignActive:(UIScene *)scene {
    // Called when the scene will move from an active state to an inactive state.
    // This may occur due to temporary interruptions (ex. an incoming phone call).
}
- (void)sceneWillEnterForeground:(UIScene *)scene {
    // Called as the scene transitions from the background to the foreground.
    // Use this method to undo the changes made on entering the background.
}
- (void)sceneDidEnterBackground:(UIScene *)scene {
    // Called as the scene transitions from the foreground to the background.
    // Use this method to save data, release shared resources, and store enough scene-specific state information
    // to restore the scene back to its current state.
}
- (void)scene:(UIScene *)scene continueUserActivity:(NSUserActivity *)userActivity {
    [[BranchScene shared] scene:scene continueUserActivity:userActivity];
}
- (void)scene:(UIScene *)scene openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts {
    [[BranchScene shared] scene:scene openURLContexts:URLContexts];
}
@end

Apps using SwiftUI

  • Create an AppDelegate.swift file in your project:
import UIKit
// iOS SDK 2.0.0+
import BranchSDK
// iOS SDK <2.0.0
// import Branch

class AppDelegate: UIResponder, UIApplicationDelegate {
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
        
        Branch.getInstance().initSession(launchOptions: launchOptions) { (params, error) in
            // do stuff with deep link data (nav to page, display content, etc)
            print(params as? [String: AnyObject] ?? {})
        }
        
        return true
    }
    
}
  • In your App.swift file:
import SwiftUI
// iOS SDK 2.0.0+
import BranchSDK
// iOS SDK <2.0.0
// import Branch

@main
struct YourAppNameApp: App {
    
    @UIApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate
    
    var body: some Scene {
        WindowGroup {
            ContentView()
                .onOpenURL(perform: { url in
                    Branch.getInstance().handleDeepLink(url)
                })
        }
    }
}

Track Users

🚧

Sending PII

Be sure to not send any PII through this method. For additional details, please view our guide on Best Practices to Avoid Sending PII to Branch

  • Sets the identity of a user (ID, UUID, etc) for events, deep links, and referrals

❗️

Invoke setIdentity after initSession

This method should only be invoked after initSession completes, either within the callback or after a delay. If it is invoked before, then we will silently initialize the SDK before the callback has been set in order to carry out this method's required task. As a result, you may experience issues where the initSession callback does not fire.

// login
Branch.getInstance().setIdentity("your_user_id")

// logout
Branch.getInstance().logout() // or .logoutWithCallback() to customize further
// login
[[Branch getInstance] setIdentity:@"your_user_id"];

// logout
[[Branch getInstance] logout];

Appendix

Add CTD for Universal Email

If you use Branch's Universal Email integration, you must add your ESP’s CTD to your Associated Domains entitlement, in order for links to open in iOS. This allows Apple to recognize the click tracking domain as a Universal Link, opening the app immediately without the browser opening.

  1. In Xcode, go to the Capabilities tab of your project file.
  2. Scroll down and enable Associated Domains if it is not already enabled.
1006
  1. Copy your click tracking domain from the email you received from Branch, or retrieve it from your ESP's settings.
  2. In the Domains section, click the + icon and add your click tracking domain. For example, if your click tracking domain is email.example.com, add an entry for applinks:email.example.com.
928