iOS Advanced Features
Do more with the Branch iOS SDK by leveraging advanced features for specific use cases.
Overview
The Branch iOS SDK exposes a set of methods specifically made for iOS apps, which you can call using Swift or Objective-C.
Prerequisites
Before you get started implementing the features on this page, you first need to:
- Create a Branch Dashboard.
- Integrate the Branch iOS SDK into your mobile app.
- Validate your Branch iOS SDK integration.
Set Initialization Metadata
Some third-party Data Integration Partners require setting certain identifiers before initializing the Branch iOS SDK. Do this using the setRequestMetadataKey()
method.
// Before Branch initialization
// Inside the `didFinishLaunchingWithOptions()` method
Branch.getInstance().setRequestMetadataKey("KEY", "VALUE")
// Before Branch initialization
// Inside the `didFinishLaunchingWithOptions()` method
[[Branch getInstance] setRequestMetadataKey:@"{ANALYTICS_ID}" value: @"{VALUE}"];
Delay Branch Initialization
It is possible to delay Branch initialization for Installs so that you can request tracking permission from the user first.
To delay Branch initialization:
- Create a boolean flag to represent an Install session and set it to
true
(in this example, the flag is calledfirstOpen
). - Before you initialize Branch with
initSession()
indidFinishLaunchingWithOptions()
, add the following logic:- If
false
, continue withinitSession()
. - If
true
:- Persist
launchOptions
throughout onboarding flow, or store locally whenfirstOpen
istrue
. - Continue with onboarding flow.
- Persist
- If
- After determining the user's tracking preference:
- Enable or disable Branch tracking based on the user's preference.
- Initialize the Branch SDK with the persisted
launchOptions
information.
- Set
firstOpen
(the Install boolean) tofalse
.
ESP CTD (Email)
Note: These steps are only required if you have an iOS app and use the Branch Email integration.
In order for Apple to recognize your ESP's click tracking domain (CTD) as an Apple Universal Link, the CTD must be added to your Associated Domains entitlement. This allows your app to open immediately, without the browser opening.
To add your ESP's CTD to your associated domains:
- Find and copy the click tracking domain for your ESP. There are several ways to do this, including retrieving it from your ESP's settings or inspecting a recent email you've sent using the ESP.
- Navigate to the
Signing & Capabilities
tab of your project file in Xcode, then scroll to theAssociated Domains
section. - Add your ESP's CTD to the list of domains, appending
applinks:
to the beginning of the CTD. For example, if the CTD isemail.brand.com
then addapplinks:email.brand.com
to the domain list. Also addapplinks:email-alternate.brand.com
to the domain list.
Email is part of Branch's Engagement product. Learn more here.
General Deep Linking
Branch Deep Links point to specific content that exists inside your app.
If a user clicks a Branch Deep Link and they have your app installed, the Deep Link will take them directly to your app and the specific content featured in your ad.
If the user does not have your app installed, they will be routed to the fallback URL you specified in your Branch Dashboard.
Deep Link Prerequisites
Before you can create a Branch Deep Link, you first need to:
-
Create a
BranchUniversalObject
instance that will represent a unique piece of content:let buo: BranchUniversalObject = BranchUniversalObject(canonicalIdentifier: "item/12345") buo.title = "My Content Title" buo.contentDescription = "My Content Description" buo.imageUrl = "https://example.com/mycontent-12345.png" buo.contentMetadata.contentSchema = .product; buo.contentMetadata.customMetadata["property1"] = "blue" buo.contentMetadata.customMetadata["property2"] = "red"
BranchUniversalObject *buo = [[BranchUniversalObject alloc] initWithCanonicalIdentifier:@"item/12345"]; buo.title = @"My Content Title"; buo.contentDescription = @"My Content Description"; buo.imageUrl = @"https://example.com/mycontent-12345.png"; buo.contentMetadata.contentSchema = BranchContentSchemaCommerceProduct; buo.contentMetadata.customMetadata[@"property1"] = @"blue"; buo.contentMetadata.customMetadata[@"property2"] = @"red";
-
Create a
BranchLinkProperties
instance that will contain info about the URL associated with the content:let lp: BranchLinkProperties = BranchLinkProperties() lp.channel = "facebook" lp.feature = "sharing" lp.campaign = "content 123 launch" lp.stage = "new user" lp.tags = ["one", "two", "three"] lp.addControlParam("$desktop_url", withValue: "http://example.com/desktop") lp.addControlParam("$ios_url", withValue: "http://example.com/ios") lp.addControlParam("$ipad_url", withValue: "http://example.com/ios") lp.addControlParam("$android_url", withValue: "http://example.com/android") lp.addControlParam("$match_duration", withValue: "2000") lp.addControlParam("custom_data", withValue: "yes") lp.addControlParam("look_at", withValue: "this") lp.addControlParam("nav_to", withValue: "over here") lp.addControlParam("random", withValue: UUID.init().uuidString)
BranchLinkProperties *lp = [[BranchLinkProperties alloc] init]; lp.feature = @"facebook"; lp.channel = @"sharing"; lp.campaign = @"content 123 launch"; lp.stage = @"new user"; lp.tags = @[@"one", @"two", @"three"]; [lp addControlParam:@"$desktop_url" withValue: @"http://example.com/desktop"]; [lp addControlParam:@"$ios_url" withValue: @"http://example.com/ios"]; [lp addControlParam:@"$ipad_url" withValue: @"http://example.com/ios"]; [lp addControlParam:@"$android_url" withValue: @"http://example.com/android"]; [lp addControlParam:@"$match_duration" withValue: @"2000"]; [lp addControlParam:@"custom_data" withValue: @"yes"]; [lp addControlParam:@"look_at" withValue: @"this"]; [lp addControlParam:@"nav_to" withValue: @"over here"]; [lp addControlParam:@"random" withValue: [[NSUUID UUID] UUIDString]];
Create Deep Links
Once you have a BranchUniversalObject
and a BranchLinkProperties
instance, you can use the getShortUrlWithLinkProperties()
method to create a Branch Deep Link.
let buo: BranchUniversalObject = BranchUniversalObject(canonicalIdentifier: "item/12345")
let lp: BranchLinkProperties = BranchLinkProperties()
buo.getShortUrl(with: lp) { url, error in
print(url ?? "")
}
BranchUniversalObject *buo = [[BranchUniversalObject alloc] initWithCanonicalIdentifier:@"item/12345"];
BranchLinkProperties *lp = [[BranchLinkProperties alloc] init];
[buo getShortUrlWithLinkProperties:lp andCallback:^(NSString* url, NSError* error) {
if (!error) {
NSLog(@"@", url);
}
}];
The Branch iOS SDK offers a variety of methods for creating Deep Links, depending on your project requirements.
Read Deep Links
You can read a Branch Deep Link to retrieve data from it.
The best practice is to get the data from the listener, since this will prevent a possible race condition.
Do this in your AppDelegate file, within the didFinishLaunchingWithOptions()
method:
// In AppDelegate file, inside `didFinishLaunchingWithOptions()` method
// Branch listener object
Branch.getInstance().initSession(launchOptions: launchOptions) { params, error in
// Referring params
print(params as? [String: AnyObject] ?? {})
}
// Get latest referring params for Deep Link
// Warning: This method may return results from a previous referral
let sessionParams = Branch.getInstance().getLatestReferringParams()
// Get first referring params for Deep Link
let installParams = Branch.getInstance().getFirstReferringParams()
// In AppDelegate file, inside `didFinishLaunchingWithOptions()` method
// Branch listener object
[[Branch getInstance] initSessionWithLaunchOptions:launchOptions
andRegisterDeepLinkHandler:^(NSDictionary * _Nullable params,
NSError * _Nullable error) {
if (!error) {
// Referring params
NSLog(@"Referring link params %@",params);
}
}];
// Get latest referring params for Deep Link
// Warning: This method may return results from a previous referral
NSDictionary *sessionParams = [[Branch getInstance] getLatestReferringParams];
// Get first referring params for Deep Link
NSDictionary *installParams = [[Branch getInstance] getFirstReferringParams];
These methods return Deep Link properties. For the synchronous version of getLatestReferringParams()
, use the getLatestReferringParamsSynchronous()
method.
Navigate to Content
Using data you've retrieved from a Branch Deep Link, you can navigate the user to specific content.
This is handled within the Branch.initSessionWithLaunchOptions()
method (also sometimes called simply the initSession()
method), which you can learn more about in the iOS SDK Full Reference.
// Within AppDelegate `application.didFinishLaunchingWithOptions`
Branch.getInstance().initSession(launchOptions: launchOptions) { params , error in
// Option 1: Read deep link data
guard let data = params as? [String: AnyObject] else { return }
// Option 2: Save deep link data to global model
SomeCustomClass.sharedInstance.branchData = data
// Option 3: Display data
let alert = UIAlertController(title: "Deep link data", message: "\(data)", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Okay", style: .default, handler: nil))
self.window?.rootViewController?.present(alert, animated: true, completion: nil)
// Option 4: Navigate to view controller
guard let options = data["nav_to"] as? String else { return }
switch options {
case "landing_page": self.window?.rootViewController?.present( SecondViewController(), animated: true, completion: nil)
case "tutorial": self.window?.rootViewController?.present( SecondViewController(), animated: true, completion: nil)
case "content": self.window?.rootViewController?.present( SecondViewController(), animated: true, completion: nil)
default: break
}
}
// Within AppDelegate `application.didFinishLaunchingWithOptions`
[[Branch getInstance] initSessionWithLaunchOptions:launchOptions andRegisterDeepLinkHandler:^(NSDictionary * _Nonnull params, NSError * _Nullable error) {
// Option 1: Read deep link data
NSLog(@"%@", params);
// Option 2: Save deep link data to global model
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:params.description forKey:@"BranchData"];
[defaults synchronize];
// Option 3: Display data
UIAlertController * alert = [UIAlertController alertControllerWithTitle:@"Title" message:params.description preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *button = [UIAlertAction actionWithTitle:@"Deep Link Data" style:UIAlertActionStyleDefault handler:nil];
[alert addAction:button];
[self.window.rootViewController presentViewController:alert animated:YES completion:nil];
// Option 4: Navigate to view controller
if ([params objectForKey:@"navHere"]) {
ViewController *anotherViewController = [[ViewController alloc] initWithNibName:@"anotherViewController" bundle:nil];
[self.window.rootViewController presentViewController:anotherViewController animated:YES completion:nil];
}
}];
Store Deep Link Data
To store Branch Deep Link data, you can save the data to a global model:
// In AppDelegate file, inside `didFinishLaunchingWithOptions()` method
Branch.getInstance().initSession(launchOptions: launchOptions) { params , error in
// Read Deep Link data
guard let data = params as? [String: AnyObject] else { return }
// Save Deep Link data to global model
SomeCustomClass.sharedInstance.branchData = data
}
// In AppDelegate file, inside `didFinishLaunchingWithOptions()` method
[[Branch getInstance] initSessionWithLaunchOptions:launchOptions andRegisterDeepLinkHandler:^(NSDictionary * _Nonnull params, NSError * _Nullable error) {
// Save Deep Link data to global model
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:params.description forKey:@"BranchData"];
[defaults synchronize];
}];
NativeLink™ Deferred Deep Linking
Use iOS pasteboard to enable deferred deep linking via Branch NativeLink™, which enables 100% matching on iOS through Installs.
Prerequisite
Minimum SDK Version: v1.39.4
To use this feature you must:
or
- Manually configure your Branch Link to use
$ios_nativelink
Access
Please note that Deferred Deep Linking is part of Branch's Engagement package. Learn more on our Pricing page.
Implementation Options
Basic Example
To enable this feature, call the checkPasteboardOnInstall()
method in the AppDelegate file. Call this method prior to Branch initialization.
// Inside the AppDelegate file
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Call `checkPasteboardOnInstall()` before Branch initialization
Branch.getInstance().checkPasteboardOnInstall()
// Branch initialization (listener for Branch Deep Link data)
Branch.getInstance().initSession(launchOptions: launchOptions) { (params, error) in
// Do stuff with Branch Deep Link data (nav to page, display content, etc)
print(params as? [String: AnyObject] ?? {})
}
return true
}
// Inside the AppDelegate file
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Call `checkPasteboardOnInstall()` before Branch initialization
[[Branch getInstance] checkPasteboardOnInstall];
// Branch initialization (listener for Branch Deep Link data)
[[Branch getInstance] initSessionWithLaunchOptions:launchOptions andRegisterDeepLinkHandler:^(NSDictionary * _Nonnull params, NSError * _Nullable error) {
// Do stuff with Branch Deep Link (nav to page, display content, etc)
NSLog(@"%@", params);
}];
return YES;
}
Example With iOS 15.X Check
If you only want to enable this feature on iOS 15.X, include an iOS version check prior to calling the checkPasteboardOnInstall()
method. Both the version check and the method call happen inside the AppDelegate file, before Branch initialization.
// Inside the AppDelegate file
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
if #available(iOS 16.0, *) {
// Don't check pasteboard on install, instead utilize UIPasteControl
} else if #available(iOS 15.0, *) {
// Call `checkPasteboardOnInstall()` before Branch initialization
branch.checkPasteboardOnInstall()
}
// Branch initialization (listener for Branch Deep Link data)
Branch.getInstance().initSession(launchOptions: launchOptions) { (params, error) in
// Do stuff with Branch Deep Link data (nav to page, display content, etc)
print(params as? [String: AnyObject] ?? {})
}
return true
}
// Inside the AppDelegate file
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
if (@available(iOS 16.0, *)) {
// Don't check pasteboard on install, instead utilize UIPasteControl
} else if (@available(iOS 15.0, *)) {
// Call `checkPasteboardOnInstall()` before Branch initialization
[[Branch getInstance] checkPasteboardOnInstall];
}
// Branch initialization (listener for Branch Deep Link data)
[[Branch getInstance] initSessionWithLaunchOptions:launchOptions andRegisterDeepLinkHandler:^(NSDictionary * _Nonnull params, NSError * _Nullable error) {
// Do stuff with Branch Deep Link data (nav to page, display content, etc)
NSLog(@"%@", params);
}];
return YES;
}
Example With iOS 15.X and Pasteboard Visibility Checks
You can also check whether the pasteboard toast will show or not by using the willShowPasteboardToast()
method. This call happens inside the AppDelegate file, before Branch initialization.
// Inside the AppDelegate file
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
if #available(iOS 16.0, *) {
// Don't check pasteboard on install, instead utilize UIPasteControl
} else if #available(iOS 15.0, *) {
// Call `checkPasteboardOnInstall()` before Branch initialization
branch.checkPasteboardOnInstall()
}
// Check if pasteboard toast will show
if Branch.getInstance().willShowPasteboardToast(){
// You can notify the user of what just occurred here
}
// Branch initialization (listener for Branch Deep Link data)
Branch.getInstance().initSession(launchOptions: launchOptions) { (params, error) in
// Do stuff with Branch Deep Link data (nav to page, display content, etc)
print(params as? [String: AnyObject] ?? {})
}
return true
}
// Inside the AppDelegate file
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
if (@available(iOS 16.0, *)) {
// Don't check pasteboard on install, instead utilize UIPasteControl
} else if (@available(iOS 15.0, *)) {
// Call `checkPasteboardOnInstall()` before Branch initialization
[[Branch getInstance] checkPasteboardOnInstall];
}
// Check if pasteboard toast will show
if ([[Branch getInstance] willShowPasteboardToast]) {
// You can notify the user of what just occurrred here
}
// Branch initialization (listener for Branch Deep Link data)
[[Branch getInstance] initSessionWithLaunchOptions:launchOptions andRegisterDeepLinkHandler:^(NSDictionary * _Nonnull params, NSError * _Nullable error) {
// Do stuff with Branch Deep Link data (nav to page, display content, etc)
NSLog(@"%@", params);
}];
return YES;
}
iOS 16 UIPasteControl Support
With iOS 16, Apple introduced an automatic modal prompt to request permissions from the user whenever the pasteboard is accessed for an item. UIPasteControl
is an alternative for you to create your own prompt requesting access to the pasteboard.
This approach does not interfere with Branch initialization and Branch will treat the paste action as if it were an in-app Branch Deep Link.
Backwards Compatibility
Do not call both
checkPasteboardOnInstall()
andpassPasteItemProviders()
or useBranchPasteControl()
without properly version checking, ascheckPasteboardOnInstall()
will be called on iOS 16+ as well.
Example With passPasteItemProviders()
API Call
passPasteItemProviders()
API CallIf you are using UIPasteControl, its target (which also conforms to protocol UIPasteConfigurationSupporting) will receive the pasted information when the button is tapped.
Pass the list of objects to the Branch SDK using the passPasteItemProviders()
API within the paste(itemProviders:) function. Do this inside of the ViewController.
// Inside the ViewController
override func paste(itemProviders: [NSItemProvider]) {
if #available(iOS 16.0, *) {
Branch.getInstance().passPaste(itemProviders)
} else {
// Fallback on earlier versions
}
}
// Inside the ViewController
if (@available(iOS 16.0, *)) {
[[Branch getInstance] passPasteItemProviders:itemProviders]
}
You can also configure the paste button's look using UIPasteControl.Configuration()
inside of the ViewController.
// Inside the ViewController
if #available(iOS 16.0, *) {
let appleUIPasteControlButton: UIPasteControl = {
let pcConfig = UIPasteControl.Configuration()
pcConfig.baseBackgroundColor = UIColor(red: 55/255, green: 153/255, blue: 211/255, alpha: 1)
pcConfig.baseForegroundColor = .white
pcConfig.cornerStyle = .capsule
// Three options: icon only, label only, or icon and label
pcConfig.displayMode = .iconAndLabel
let frame = CGRect(x: 20 , y: 60, width: 40, height: 40)
let pc = UIPasteControl(configuration: pcConfig)
pc.frame = frame
self.pasteConfiguration = UIPasteConfiguration(acceptableTypeIdentifiers: [UTType.url.identifier])
// Very important: must set target so that the overridden `paste(itemProviders)` function gets called
pc.target = self
return pc;
}()
view.addSubview(appleUIPasteControlButton)
}
Example With BranchPasteControl()
BranchPasteControl()
Instead of calling the passPasteItemProviders()
API, you can also use the wrapper class BranchPasteControl()
to automatically conform to the UIPasteConfigurationSupporting protocol.
You can still configure the paste button's look by calling the UIPasteControl.Configuration()
method.
Make both calls inside of the ViewController.
// Inside the ViewController
if #available(iOS 16.0, *) {
// Setup `UIPasteControl` configuration
let pcConfig = UIPasteControl.Configuration()
pcConfig.baseBackgroundColor = UIColor.blue
pcConfig.displayMode = UIPasteControl.DisplayMode.iconOnly
// Create frame and button
let frameDimension = CGRect(x: 0, y: 0, width: 40, height: 40)
let bc = BranchPasteControl(frame: frameDimension, andConfiguration: pcConfig)
// Add `BranchPasteControl()` button to superview
view.addSubview(bc)
}
// Inside the ViewController
if (@available(iOS 16.0, *)) {
// Setup `UIPasteControl` configuration
UIPasteControlConfiguration *pcConfig = [[UIPasteControlConfiguration alloc] init];
pcConfig.baseBackgroundColor = UIColor.blueColor;
pcConfig.displayMode = UIPasteControlDisplayModeIconOnly;
// Create frame and button
CGRect frameDimension = CGRectMake(0, 0, 120.0, 30.0);
BranchPasteControl *bc = [[BranchPasteControl alloc] initWithFrame:frameDimension AndConfiguration:pcConfig];
// Add `BranchPasteControl` button to superview
[view addSubview:bc];
}
BranchPasteControl & UIPasteControl Tips
BranchPasteControl.frame & UIPasteControl.frame:
Based on Branch's testing there are undeclared restrictions as to the width and height forUIPasteControl
corresponding to the declaredDisplayMode
. Branch found that the minimum height for all display modes is 40, while the minimum widths are as follows:
- .iconOnly: 40
- .labelOnly: 60
- .iconAndLabel: 80
BranchPasteControl()
only accepts UTType.url as an acceptable type identifier for itsUIPasteConfiguration
. If the main purpose is to support NativeLink, Branch strongly suggests doing the same.If utilizing your own
UIPasteControl
, Branch recommends clearing the iOS paste board after accessing it.When there is not an acceptable type copied to the iOS paste board, the
BranchPasteControl
andUIPasteControl
UI will be greyed out.
Event Tracking
By default, the Branch iOS SDK tracks clicks, opens, installs, reinstalls, and impressions automatically (out-of-the-box).
You can also use the BranchEvent
class to track special user actions or application specific events. For example, you can track when a user adds an item to a shopping cart or searches for a keyword.
In short, a BranchEvent
instance corresponds to an in-app event that you want to log with Branch.
You can use a BranchUniversalObject
(BUO) instance to populate the contentItems
field of the BranchEvent
class. This is how you associate BUO data with a specific event.
Learn more about tracking events and the logEvent()
method in our guides.
Sharing
If you want to create Branch Deep Links that have special properties when shared, you can use a variety of methods from the Branch iOS SDK to customize your user's sharing experience.
iOS Share Sheet
Use the showShareSheetWithLinkProperties()
method to create a Branch Deep Link that has both a shareText
message and a BranchLinkProperties
object associated with it.
let buo = BranchUniversalObject(canonicalIdentifier: "item/12345")
let lp = BranchLinkProperties()
let message = "Check out this link"
buo.showShareSheet(with: lp, andShareText: message, from: self) { (activityType, completed) in
print(activityType ?? "")
}
BranchUniversalObject *buo = [[BranchUniversalObject alloc] initWithCanonicalIdentifier:@"item/12345"];
BranchLinkProperties *lp = [BranchLinkProperties new];
buo showShareSheetWithLinkProperties:lp andShareText:@"Super amazing thing I want to share!" fromViewController:self completion:^(NSString* activityType, BOOL completed) {
NSLog(@"finished presenting");
}];
The showShareSheetWithLinkProperties()
method uses the UIViewController
for link sharing.
You can also use the showShareSheetWithShareText()
method if you don't want to include a BranchLinkProperties
object.
Email
You can customize a BranchLinkProperties
object to have certain values when your Branch Deep Link is shared specifically via email.
The share text will fill in the body, and you can specify the email subject in the BranchLinkProperties
object, as well as other parameters related to email.
let lp = BranchLinkProperties()
lp.feature = "share"
lp.channel = "facebook"
lp.addControlParam("$email_subject", withValue: "Your Awesome Deal")
lp.addControlParam("$email_html_header", withValue: "<style>your awesome CSS</style>\nOr Dear Friend,")
lp.addControlParam("$email_html_footer", withValue: "Thanks!")
lp.addControlParam("$email_html_link_text", withValue: "Tap here")
BranchLinkProperties *lp = [[BranchLinkProperties alloc] init];
lp.feature = @"share";
lp.channel = @"facebook";
[lp addControlParam:@"$email_subject" withValue:@"Your Awesome Deal"];
[lp addControlParam:@"$email_html_header" withValue:@"<style>your awesome CSS</style>\nOr Dear Friend,"];
[lp addControlParam:@"$email_html_footer" withValue:@"Thanks!"];
[lp addControlParam:@"$email_html_link_text" withValue:@"Tap here"];
Dynamic Messaging
With the Branch iOS SDK, you can change the text of a message that is shared based on the source. Do this using the channel
property associated with a BranchShareLink
instance.
// Import delegate
class ViewController: UITableViewController, BranchShareLinkDelegate
let buo = BranchUniversalObject(canonicalIdentifier: "item/12345")
let lp = BranchLinkProperties()
let shareLink = BranchShareLink(universalObject: buo, linkProperties: lp)
func branchShareLinkWillShare(_ shareLink: BranchShareLink) {
// Choose shareSheet.activityType
shareLink.shareText = "\(shareLink.linkProperties.channel)"
}
// Impost delegate
@interface ViewController () <BranchShareLinkDelegate>
BranchUniversalObject *buo = [[BranchUniversalObject alloc] initWithCanonicalIdentifier:@"item/12345"];
BranchLinkProperties *lp = [BranchLinkProperties new];
BranchShareLink *shareLink =
[[BranchShareLink alloc]
initWithUniversalObject:buo
linkProperties:lp];
- (void) branchShareLinkWillShare:(BranchShareLink*)shareLink {
// Choose shareSheet.activityType
shareLink.shareText = [NSString stringWithFormat:@"@%", shareLink.linkProperties.channel];
}
LPLinkMetadata
To associate LPLinkMetadata
with a Branch Deep Link, use the addLPLinkMetadata()
method on a BranchShareLink
instance. Then, present the iOS Share Sheet to the user with the presentActivityViewController()
method.
let buo = BranchUniversalObject(canonicalIdentifier: "item/12345")
let lp = BranchLinkProperties()
let shareLink = BranchShareLink(universalObject: buo, linkProperties: lp)
shareLink.addLPLinkMetadata("LPLinkMetaData Link Title", icon: iconImg)
shareLink.presentActivityViewController(from: self, anchor: nil)
BranchUniversalObject *buo = [[BranchUniversalObject alloc] initWithCanonicalIdentifier:@"item/12345"];
BranchLinkProperties *lp = [BranchLinkProperties new];
BranchShareLink *shareLink =
[[BranchShareLink alloc]
initWithUniversalObject:buo
linkProperties:lp];
[shareLink addLPLinkMetadata:@"LPLinkMetadata Link Title" icon:iconImg];
[shareLink presentActivityViewControllerFromViewController:self anchor:nil];
Dynamic Links Without Share Sheet
If you've built your own share sheet and you want to create a Branch Deep Link for an individual share message or you have another use case, you can create Branch Deep Links directly:
let buo = BranchUniversalObject(canonicalIdentifier: "item/12345")
buo.getShortUrl(with: linkProperties) { (url, error) in
if (error == nil) {
print("Got my Branch link to share: (url)")
} else {
print(String(format: "Branch error : %@", error! as CVarArg))
}
}
BranchUniversalObject *buo = [[BranchUniversalObject alloc] initWithCanonicalIdentifier:@"item/12345"];
[buo getShortUrlWithLinkProperties:linkProperties andCallback:^(NSString *url, NSError *error) {
if (!error) {
NSLog(@"got my Branch invite link to share: %@", url);
}
}];
Handle Links in Your Own App
Use the code below to deep link into your own app from within the app itself. This is done by launching a Chrome intent.
Note: Handling a new Branch Deep Link in your app will clear the current session data and a new referred OPEN
will be attributed.
// The following call would return `false`
Branch.getInstance().handleDeepLink("myapp://")
// The following call would return `true`
Branch.getInstance().handleDeepLink("myapp://open?link_click_id=12345")
// The following call would return `YES`
NSURL *URL = [NSURL URLWithString:@"myapp://open?link_click_id=12345"];
[[Branch getInstance] handleDeepLink:URL];
Web-Only Content
Handle Deep Links for Web-Only Content (Email)
This feature is relevant for Branch Email integration customers.
If you have links to content that exists only on the web and not in the app (for example, a temporary marketing webpage), then you want to ensure that all links which have not had the deep linking script applied will open in a browser. Do this using the following code within your deep link handler code block:
// Inside your deep link handler code block
branch.initSession(launchOptions: launchOptions, andRegisterDeepLinkHandler: { (params, error) in
// Params are the deep linked params associated with the link that the user clicked
// This uses query parameter $web_only=true
// This should match the query parameter on the web URL you enter in the email
if (params?["$3p"] != nil && params?["$web_only"] != nil) {
if let urlString = params?["$original_url"] as? String {
if let url = URL(string: urlString) {
// Check to make sure your existing deep linking logic, if any, is not executed, perhaps by returning early
application.openURL(url)
}
} else {
// Is a Branch Deep Link
self.handleBranchDeeplink(params)
}
}
})
// Inside your deep link handler code block
[branch initSessionWithLaunchOptions:launchOptions andRegisterDeepLinkHandler:^(NSDictionary *params, NSError *error) {
// Params are the deep linked params associated with the link that the user clicked
// This uses query parameter $web_only=true
// This should match the query parameter on the web URL you enter in the email
if (params[@"$3p"] && params[@"$web_only"]) {
NSURL *url = [NSURL URLWithString:params[@"$original_url"]];
if (url) {
// Check to make sure your existing deep linking logic, if any, is not executed, perhaps by returning early
[application openURL:url];
}
} else {
// Is a Branch Deep Link
GDLog(@"Branch Deep Link: %@", [params description]);
[self handleBranchDeeplink:params];
}
}];
Learn more about the initSessionWithLaunchOptions()
and handleBranchDeeplink()
methods in the iOS SDK Full Reference.
Please note that Email is part of Branch's Engagement product. Learn more here.
Handle Universal Links With Web-Only Content
Web-only Branch Links that redirect to a site hosting its own AASA file where Universal Links (UL) is enable will cause unexpected behavior.
Since Branch does not have a way to bypass UL, you must add a query parameter exclusion in the AASA file to persist web-only behavior when redirecting to a website.
This only applies if you are trying to redirect via $web_only=true
to the website.
Add the following filter to the AASA file:
{
"/": "*",
"?": { "$web_only": "true" },
"exclude": true,
"comment": "Matches any URL which has a query item with name '$web_only' and a value of exactly true"
}
Now if $web_only=true
is appended to the final fallback URL/redirect, iOS will not attempt to launch the app even if it is installed.
An example of the appended parameter: https://myhomepage.com/?$web_only=true
The example URL with the query parameter can now be used as the fallback for a web-only Branch Deep Link.
Push Notifications
To handle push notifications, use the handlePushNotifications()
method and include the Branch Link you would like to see as part of the push notification.
// NSDictionary userInfo = @{@"branch": @"https://bnc.lt/...", ... };
// NSDictionary userInfo = @{@"branch": @"https://app.link/...", ... };
Branch.getInstance().handlePushNotification(response.notification.request.content.userInfo)
// NSDictionary userInfo = @{@"branch": @"https://bnc.lt/...", ... };
// NSDictionary userInfo = @{@"branch": @"https://app.link/...", ... };
[[Branch getInstance] handlePushNotification:userInfo];
Note: The format of your push notification payload will vary based on your push provider setup. Since there is no consistent format across providers, Branch relies on the relevant data being easily discoverable in your payload, such as in the userInfo
example above, where a top-level dictionary key called branch
contains the Branch Link value.
Here is another example of a payload where the Branch Link is easily discoverable, this time in JSON:
{
"aps": {
"alert": "Push notification with a Branch deep link",
"badge": "1"
},
"branch": "https://example.app.link/u3fzDwyyjF"
}
QR Codes
To use a Branch QR Code, first create a BranchQRCode
object. Fill out relevant properties for that object, then use BranchQRCode
methods like getAsImage()
and showShareSheetWithQRCode()
to take different actions with your Branch QR Code.
let qrCode = BranchQRCode()
qrCode.codeColor = UIColor.white
qrCode.backgroundColor = UIColor.blue
qrCode.centerLogo = "https://cdn.branch.io/branch-assets/1598575682753-og_image.png"
qrCode.width = 1024
qrCode.margin = 1
qrCode.imageFormat = .JPEG
let buo = BranchUniversalObject(canonicalIdentifier: "item/12345")
let lp = BranchLinkProperties()
qrCode.getAsImage(buo, linkProperties: lp) { qrCodeImage, error in
// Do something with your Branch QR Code here
}
// Or display the Branch QR Code directly in a Share Sheet
qrCode.showShareSheetWithQRCode(from: self, anchor: nil, universalObject: buo, linkProperties: lp) { error in
// Show a Share Sheet with the QR code
}
BranchQRCode *qrCode = [BranchQRCode new];
qrCode.codeColor = [[UIColor new] initWithRed:0.1 green:0.8392 blue:0.8667 alpha:1.0];
qrCode.backgroundColor = [UIColor whiteColor];
qrCode.width = @700;
qrCode.margin = @1;
qrCode.centerLogo = @"https://cdn.branch.io/branch-assets/1598575682753-og_image.png";
qrCode.imageFormat = BranchQRCodeImageFormatPNG;
BranchUniversalObject *buo = [[BranchUniversalObject alloc] initWithCanonicalIdentifier:@"item/12345"];
BranchLinkProperties *lp = [BranchLinkProperties new];
[qrCode getQRCodeAsImage:buo linkProperties:lp completion:^(UIImage * _Nonnull qrCode, NSError * _Nonnull error) {
// Do something with the Branch QR Code here
}];
// Or display the QR code directly in a Share Sheet
[qrCode showShareSheetWithQRCodeFromViewController:self anchor:nil universalObject:buo linkProperties:lp completion:^(NSError * _Nullable error) {
// Showing a Share Sheet with the Branch QR Code
}];
To learn more about Branch QR Code methods, visit our iOS SDK Full Reference.
Access
Basic Branch QR Codes are included in the free tier of the Branch Growth Platform.
For more advanced QR Code capabilities, see our Engagement Pro package, which includes access to the QR Code API as well as the ability to create custom QR Codes in the Branch Dashboard.
App Clips
Introduced in iOS 14, an App Clip is a mini app that shares some functionality with your full app. Because the App Clip limits its functionality to just a portion of what the full app can do, the App Clip is lightweight and efficient. You can present users with your App Clip during unique moments in their journey, like when they click a location-based suggestion from Siri Suggestions. If they don't have your full app downloaded, that click can bring them to an App Clip instead.
The Xcode target for your App Clip lives in the same project as the target for your full app, allowing you to share code between the two.
Important
- The Associated Domains entitlement has a new
appclips
type, which is required if you’re implementing App Clips.- The AASA file must be updated to support App Clips via a Branch database update. Please submit a ticket to make this request. Make sure to include your App Clip bundle ID and team ID in your request.
Learn more about App Clip creation from Apple's Developer Documentation.
Implementation
An App Clip needs the Branch iOS SDK integrated into it the same way a full app does.
However, a few things change when you integrate the Branch iOS SDK into an App Clip compared to a full app:
- You do not need to use the
applinks
setting in the App Clip's Associated Domains entitlement. - Cocoapods will not install the Branch iOS SDK into your App Clip.
Visit the Branch iOS SDK Basic Integration guide for steps on integrating the SDK.
Set User Identity
Similar to full apps, it is possible to set the identity of a user while they're using an App Clip. To do so, use the setIdentity()
method. Learn more about this method in the "Tracking" section or in the iOS SDK Full Reference.
App Clip Analytics
Branch will automatically attribute App Clip sessions and touches (like a Branch QR Code scan).
Session:
Dimension | Value |
---|---|
name | Install or Open |
user_data_environment | APP_CLIP |
last_attributed_touch_data_tilde_creative_name | $app_clip_id if present |
Touch:
Dimension | Value |
---|---|
name | Click |
last_attributed_touch_data_tilde_customer_placement | APP_CLIP |
last_attributed_touch_data_tilde_creative_name | $app_clip_id if present |
Persist App Clip Install Data to Full App Install
To persist App Clip install data to the subsequent full app install:
- Add an App Groups entitlement and choose a group that will be used to share data between the App Clip and subsequent full app install.
- In both your App Clip and your full app, inform the Branch iOS SDK of the App Group name prior to calling
initSession()
. See Apple's Developer Documentation for more info.
[[Branch getInstance] setAppClipAppGroup:@"group.io.branch"];
Branch.getInstance().setAppClipAppGroup("group.io.branch")
Handle URL Invocations
It is possible to associate Branch Deep Links with specific App Clips. In this scenario, the Branch Deep Link acts as the App Clip Invocation URL.
When creating a Branch Deep Link to use in this way, you'll need to specify which App Clip the Branch Deep Link should open. Do this via the $app_clip_id
Branch Deep Link parameter.
Imagine a scenario where you have two App Clips: one for Stores and one for Products.
On the iTunesConnect Dashboard, you would register the following as advanced App Clip Experiences:
your.app.link/ac/s/*
for the Stores App Clipyour.app.link/ac/p/*
for the Products App Clip
Then, you would create a Branch Deep Link and set the $app_clip_id
:
Now Branch will automatically create a Deep Link with the App Clip ID as part of the path: https://your.app.link/ac/s/QfJ2H7c7jcb
Additionally, you can specify an alias for these Branch Deep Links with the alias
key - for example, a Deep Link with an alias
set to 12345
would look like: https://your.app.link/ac/s/12345
. In the example above, this would be a great way to create a link to "store 12345" in the Stores App Clip!
Note: The Deep Link https://your.app.link/ac/s/12345
returns the same payload as https://your.app.link/12345
. The path elements are only to ease registering App Clip experiences.
Important: Character Length Limit
Unlike most App Clips, App Clip Code has a short URL limit. The length limit varies, but is about 35 characters. It is possible your Branch Deep Link will be too long to be used in this situation.
Use the shortest placement identifier possible to increase the odds your generated link will be short enough. We recommend specifying a short $app_clip_id and a short alias.
Learn more at Apple's Developer Documentation.
Invoke App Clips on iOS Channels
Once you register your App Clip (containing the Branch SDK) with Apple, they allow you to invoke App Clips on a few channels.
View this example application on various channels to see the different ways it responds.
iMessage
Branch Links will automatically register and display your App Clip CTA on iMessage by default if they are registered as App Clip Invocation URLs.
Web Banner
You can display an App Clip banner on your website yourself. To do this, add the standard Apple meta tag to your website:
<meta name="apple-itunes-app" content="app-id=myAppStoreID, app-clip-bundle-id=appClipBundleID>
If you want to display the banner on a Branch Deepview, add it to the HTML code in the Branch Dashboard Deepview Manager.
For more information, please refer to Apple's Developer Documentation.
Detect Screenshots
When one of your users takes a screenshot within your app, you have the option to surface a pop-up that encourages them to share the content directly instead. A Branch Deep Link is generated, which they can easily copy and share using the pop-up.
let buo = BranchUniversalObject(canonicalIdentifier: "item/12345")
let lp = BranchLinkProperties()
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(screenshotTaken), name: UIApplication.userDidTakeScreenshotNotification, object: nil)
}
@objc func screenshotTaken() {
print(“Screenshot taken! Showing Branch link.”)
// Use the respective BranchUniversalObject and BranchLinkProperties to create a short URL
buo.getShortUrl(with: lp) { url, error in
let alert = UIAlertController(title: “You took a screenshot!”, message: “Tap below to share a link to this page \(url)”, preferredStyle: .actionSheet)
alert.addAction(UIAlertAction(title: “Share”, style: .default , handler:{ (UIAlertAction)in
// Share the link here
}))
alert.addAction(UIAlertAction(title: “Dismiss”, style: .cancel, handler: nil))
// Show the alert
self.present(alert, animated: true, completion: nil)
}
}
Learn more about screenshot detection on the Branch Blog.
User Data
Google DMA Compliance
In response to the European Union's enactment of the Digital Markets Act (DMA), the Branch iOS SDK includes the setDMAParamsForEEA()
method to help you pass consent information from your user to Google.
The setDMAParamsForEEA()
method takes 3 parameters:
Parameter Name | Type | Description | When true | When false |
---|---|---|---|---|
eeaRegion | Boolean | Whether European regulations, including the DMA, apply to this user and conversion. | User is included in European Union regulations. For example, if the user is located within the EEA, they are within the scope of DMA. | User is considered excluded from European Union regulations. |
adPersonalizationConsent | Boolean | Whether end user has granted or denied ads personalization consent. | User has granted consent for ads personalization. | User has denied consent for ads personalization. |
adUserDataUsageConsent | Boolean | Whether end user has granted or denied consent for 3P transmission of user level data for ads. | User has granted consent for 3P transmission of user-level data for ads. | User has denied consent for 3P transmission of user-level data for ads. |
Default Behavior
When eeaRegion
is set to true
, the parameters adPersonalizationConsent
and adUserDataUsageConsent
must also be set.
When parameters are successfully set using setDMAParamsForEEA()
, they will be sent along with every future request to the following Branch endpoints:
/v1/install
/v1/open
/v2/event
Warning:
NULL
by DefaultPlease note that the 3 parameters passed to
setDMAParamsForEEA()
are allNULL
by default.Failure to include user consent signals may result in attribution or campaign performance degradation. For additional information, please reach out to your Google AM.
Example Usage
// Example for an EEA resident who has denied both ad personalization and data usage consent
Branch.getInstance().setDMAParamsForEEA(true,false,false)
// Example for an EEA resident who has denied both ad personalization and data usage consent
[[Branch getInstance]
setDMAParamsForEEA:YES
adPersonalizationConsent:NO
adUserDataUsageConsent:NO];
// Example for an EEA resident who has consented to ad personalization but denied data usage consent
Branch.getInstance().setDMAParamsForEEA(true,true,false)
// Example for an EEA resident who has consented to ad personalization but denied data usage consent
[[Branch getInstance]
setDMAParamsForEEA:YES
adPersonalizationConsent:YES
adUserDataUsageConsent:NO];
// Example for an EEA resident who has denied ad personalization but granted data usage consent
Branch.getInstance().setDMAParamsForEEA(true,false,true)
// Example for an EEA resident who has denied ad personalization but granted data usage consent
[[Branch getInstance]
setDMAParamsForEEA:YES
adPersonalizationConsent:NO
adUserDataUsageConsent:YES];
Set User Identity
An "identity" is a unique alias attributed to a specific user in the Branch system.
Some scenarios which could leverage the setIdentity()
function:
- You have your own user IDs that you want to see reflected in the Branch system.
- You want referral and event data to persist across platforms so you can see how your users access your service from different devices.
- You want referral and event data to persist across uninstall/reinstall events.
Sending PII
Be sure to not send any PII through the
setIdentity()
method. For additional details, please view our guide on Best Practices to Avoid Sending PII to Branch.
This method must be called after initSession()
, either within a callback or after a delay. Otherwise, Branch 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.
To confirm that user identities are being set as expected, use the Liveview section of the Branch Dashboard.
// Login
Branch.getInstance().setIdentity("your_user_id")
// Logout
Branch.getInstance().logout() // Or replace with `logoutWithCallback()` to customize further
// Login
[[Branch getInstance] setIdentity:@"your_user_id"];
// Logout
[[Branch getInstance] logout];
Learn more about best practices related to the setIdentity()
function, visit our Full Reference guide.
You can also visit the Full Reference to learn how to disable tracking across your entire application with the setTrackingDisabled()
method.
Tracking ATT Opt-In and Opt-Out Prompt Responses
To track prompt performance, use the handleATTAuthorizationStatus()
method. This method logs a Branch Event every time someone submits a response regarding whether they want to share their device data using Apple's AppTrackingTransparency
framework:
if #available(iOS 14.0, *) {
if ATTrackingManager.trackingAuthorizationStatus == .notDetermined {
ATTrackingManager.requestTrackingAuthorization { (status) in
Branch.getInstance().handleATTAuthorizationStatus(status.rawValue)
}
}
}
if (@available(iOS 14.0, *)) {
if (ATTrackingManager.trackingAuthorizationStatus == ATTrackingManagerAuthorizationStatusNotDetermined) {
[ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {
[[Branch getInstance] handleATTAuthorizationStatus:status];
}];
}
}
After Branch sees the user opt-in via ATT, Branch starts tracking an additional analytics event called “second install” for ad-driven installs, which gets deduped from "first install" on the Branch Dashboard. All conversion events will be attributed to "second install". Learn more on the Branch Blog.
Include Apple's ATTrackingManager
By default, the Branch iOS SDK does not include the ATTrackingManager
, which is required by Apple if you want to collect the IDFA for attribution purposes. Learn more about Apple's App Transparency Tracking Manager.
Note that in order for the ATTrackingManager
to function, you must include the AdSupport
framework in your Branch iOS SDK implementation.
If you have already implemented ATTrackingManager
in your app, Branch will automatically have access to the IDFA.
WARNING: Once Branch receives opt-in information, the Branch iOS SDK will fire a "second install" event to attribute ad-driven installs. To ensure that the "second install" event is automatically fired as soon as the user opts-in, present the ATT prompt after the Branch iOS SDK has finished initializing. If you present the ATT prompt earlier, the "second install" event will not fire until the next app open.
If you still need to implement ATTrackingManager
, use the sample code below to see how to display a prompt and log the IDFA:
func requestIDFAPermission() {
if #available(iOS 14, *) {
DispatchQueue.main.async {
ATTrackingManager.requestTrackingAuthorization { (status) in
if (status == .authorized) {
let idfa = ASIdentifierManager.shared().advertisingIdentifier
print("IDFA: " + idfa.uuidString)
} else {
print("Failed to get IDFA")
}
}
}
}
}
- (void)requestIDFAPermission {
if (@available(iOS 14.0, *)) {
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
dispatch_async(dispatch_get_main_queue(), ^{
[ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {
if (status == ATTrackingManagerAuthorizationStatusAuthorized) {
NSUUID *idfa = [[ASIdentifierManager sharedManager] advertisingIdentifier];
NSLog(@"IDFA: %@", idfa);
} else {
NSLog(@"Failed to get IDFA permission");
}
dispatch_semaphore_signal(semaphore);
}];
});
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
}
}
Starting from Branch iOS SDK 1.39.1, the SDK will see the authorization status if it is granted by the end-user. There is no additional work on your end to inform the Branch SDK.
On older versions of the SDK, the server infers the authorization status by the presence of the IDFA. Again, there is no additional work on your end to inform the Branch SDK.
Apple Search Ads
Branch can help track your Apple Search Ad campaigns by fetching the search ad attribution from
Apple at app install. To learn more, visit Branch's guide on Apple Search Ads.
Disable Tracking
You can also visit the Full Reference guide to learn how to disable tracking across your entire application with the setTrackingDisabled()
method.
Updated 2 months ago