iOS 高级功能

创建内容引用 (Content Reference)

let buo = BranchUniversalObject.init(canonicalIdentifier: "content/12345")
buo.title = "My Content Title"
buo.contentDescription = "My Content Description"
buo.imageUrl = "https://lorempixel.com/400/400"
buo.publiclyIndex = true
buo.locallyIndex = true
buo.contentMetadata.customMetadata["key1"] = "value1"
BranchUniversalObject *buo = [[BranchUniversalObject alloc] initWithCanonicalIdentifier:@"content/12345"];
buo.title = @"My Content Title";
buo.contentDescription = @"My Content Description";
buo.imageUrl = @"https://lorempixel.com/400/400";
buo.publiclyIndex = YES;
buo.locallyIndex = YES;
buo.contentMetadata.customMetadata[@"key1"] = @"value1";

创建没有共享表的动态链接

如果您已经建立了自己的共享表,并且只想为单个共享消息创建 Branch Link 或有另一个用例,则可以通过以下调用直接创建深度链接:

[branchUniversalObject getShortUrlWithLinkProperties:linkProperties andCallback:^(NSString *url, NSError *error) {
        if (!error) {
            NSLog(@"got my Branch invite link to share: %@", url);
        }
    }];
branchUniversalObject.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))
        }
    }

您可以在上面找到 linkProperties above. You would next use the returned link and help the user post it to (in this example) Facebook.

Specifying a shared email subjects

大多数共享选项仅包含一串文本,但电子邮件除外,该电子邮件具有主题和正文。共享文本将填充在正文中,您可以在链接属性中指定电子邮件主题,如下所示。

BranchLinkProperties *linkProperties = [[BranchLinkProperties alloc] init];
    linkProperties.feature = @"share";
    linkProperties.channel = @"facebook";
    [linkProperties addControlParam:@"$email_subject" withValue:@"Your Awesome Deal"];
let linkProperties: BranchLinkProperties = BranchLinkProperties()
    linkProperties.feature = "share"
    linkProperties.channel = "facebook"
    linkProperties.addControlParam("$email_subject", withValue: "Your Awesome Deal")

创建链接引用

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]];

创建深度链接

buo.getShortUrl(with: lp) { url, error in
        print(url ?? "")
    }
[buo getShortUrlWithLinkProperties:lp andCallback:^(NSString* url, NSError* error) {
    if (!error) {
        NSLog(@"@", url);
    }
}];

分享深度链接

let message = "Check out this link"
buo.showShareSheet(with: lp, andShareText: message, from: self) { (activityType, completed) in
  print(activityType ?? "")
}
buo showShareSheetWithLinkProperties:lp andShareText:@"Super amazing thing I want to share!" fromViewController:self completion:^(NSString* activityType, BOOL completed) {
    NSLog(@"finished presenting");
}];

Share with LPLinkMetadata

  • Create a BranchShareLink instance with a BranchUniversalObject and LinkProperties.
  • Set the BranchShareLink's LPLinkMetadata by using the addLPLinkMetadata() function.
  • Present the BranchShareLink's Share Sheet.
//Initialize a BranchShareLink with a BranchUniversalObject and BranchLinkProperties.
//Then set the BranchShareLink's LPLinkMetadata with a preview title and icon.

let bsl = BranchShareLink(universalObject: buo, linkProperties: lp)
bsl.addLPLinkMetadata("LPLinkMetaData Link Title", icon: iconImg)
bsl.presentActivityViewController(from: self, anchor: nil)
//Initialize a BranchShareLink with a BranchUniversalObject and BranchLinkProperties.
//Then set the BranchShareLink's LPLinkMetadata with a preview title and icon.

BranchShareLink *bsl = [[BranchShareLink alloc] initWithUniversalObject:buo linkProperties:lp];
[bsl addLPLinkMetadata:@"LPLinkMetadata Link Title" icon:iconImg];
[bsl presentActivityViewControllerFromViewController:self anchor:nil];

读取深度链接

  • 从深度链接中提取 Branch 数据
  • 最佳做法是从 listener (to prevent a race condition)
  • Returns deep link properties
// listener (within AppDelegate didFinishLaunchingWithOptions)
Branch.getInstance().initSession(launchOptions: launchOptions) { params, error in
  print(params as? [String: AnyObject] ?? {})
}

// latest
let sessionParams = Branch.getInstance().getLatestReferringParams()

// first
let installParams = Branch.getInstance().getFirstReferringParams()
[[Branch getInstance] initSessionWithLaunchOptions:launchOptions
                        andRegisterDeepLinkHandler:^(NSDictionary * _Nullable params,
                                                     NSError * _Nullable error) {
    if (!error) {
        //Referring params
        NSLog(@"Referring link params %@",params);
    }
}];

// latest
NSDictionary *sessionParams = [[Branch getInstance] getLatestReferringParams];

// first
NSDictionary *installParams =  [[Branch getInstance] getFirstReferringParams];

NativeLink™ Deferred Deep Linking

  • Use iOS pasteboard to enable deferred deep linking via Branch NativeLink™

🚧

先决条件

Minimum SDK Version: v1.39.4

To use this feature you must:

or

Options for Implementation

  • Enable in the AppDelegate by calling checkPasteboardOnInstall() before the Branch initialization in didFinishLaunchingWithOptions
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    // enable pasteboard check  
    Branch.getInstance().checkPasteboardOnInstall()
    
    // 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
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // enable pasteboard check
        [[Branch getInstance] checkPasteboardOnInstall];

        // 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;
}
  • Enable in the AppDelegate for iOS 15+ Only
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    // enable pasteboard check for iOS 15+ only
          if #available(iOS 15.0, *) {
           Branch.getInstance().checkPasteboardOnInstall()
        }
    
    // 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
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // enable pasteboard check for iOS 15+ only
        if (@available(iOS 15.0, *)) {
        [[Branch getInstance] checkPasteboardOnInstall];
    }
    

        // 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;
}
  • Enable in the AppDelegate with check notification
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    // enable pasteboard check  
          if #available(iOS 15.0, *) {
           Branch.getInstance().checkPasteboardOnInstall()
        }
  
    // check if pasteboard toast will show
    if Branch.getInstance().willShowPasteboardToast(){
        // devlopers can notify the user of what just occurred here if they choose
        
    }
  
    // 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
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // enable pasteboard check
        if (@available(iOS 15.0, *)) {
        [[Branch getInstance] checkPasteboardOnInstall];
    }
  
    // check if pasteboard toast will show
    if ([[Branch getInstance] willShowPasteboardToast]) {
        // developers can notify the user of what just occurrred here if they choose
        
    }

        // 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;
}

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 the Branch initialization and Branch will treat the paste action as if it was an in-app deep link.

❗️

Backwards Compatibility

Do not call both checkPasteboardOnInstall and passPasteItemProviders or use BranchPasteControl without properly version checking, as checkPasteboardOnInstall will be called on iOS 16+ as well.

if #available(iOS 16, *) {
    Branch.getInstance().passPaste(itemProviders)
}
if (@available(iOS 16.0, *)) {
   [[Branch getInstance] passPasteItemProviders:itemProviders]
}
// 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, configuration: pcConfig)

// Add BranchPasteControl button to superview
view.addSubview(bc)
// Setup UIPasteControlConfiguration
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 our testing there are undeclared restrictions as to the width and height for UIPasteControl corresponding to the declared DisplayMode. We found the minimum height for all display modes is 40, while the minimum width are as followed:

  • .iconOnly: 40
  • .labelOnly: 60
  • .iconAndLabel: 80

The BranchPasteControl only accepts UTType.url as an acceptable type identifier for its UIPasteConfiguration, if the main purpose is to support NativeLink, we strongly suggest to do the same.

If utilizing your own UIPasteControl, we recommend to clear the pasteboard after accessing it.

When there is not an acceptable type copied to the Pasteboard, the BranchPasteControl and UIPasteControl UI will be greyed out.

Create QR Code

  • Create a BranchQRCode object and set the properties
  • Create a BranchUniversalObject and BranchLinkProperties
  • Use getQRCodeAsImage() or getQRCodeAsData() to create a QR code
  • Use showShareSheetWithQRCodeFromViewController() to create a QR code and share it via the Share Sheet.
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()
let lp = BranchLinkProperties()

qrCode.getAsImage(buo, linkProperties: lp) { qrCodeImage, error in
    //Do something with your QR code here...
}

//Or display the QR code directly in a share sheet
qrCode.showShareSheetWithQRCode(from: self, anchor: nil, universalObject: buo, linkProperties: lp) { error in
    //Showing 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 new];
BranchLinkProperties *lp = [BranchLinkProperties new];

[qrCode getQRCodeAsImage:buo linkProperties:lp completion:^(UIImage * _Nonnull qrCode, NSError * _Nonnull error) {
    //Do something with the 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 QR code
}];

前往内容

  • 在此方法中处理 Branch.initSession()
// 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];
  }
}];

展示

buo.automaticallyListOnSpotlight = true
buo.automaticallyListOnSpotlight = YES;

追踪 ATT 选择加入和选择退出

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];
      }];
   }
}

📘

Second install

  • After we see user opt-in via ATT, we are tracking an additional analytics event we call a “second install” for ad-driven installs, which will be deduped from "first install" on our Dashboard.
  • All conversion events will be attributed to that "second install".
  • More information

追踪内容

BranchEvent.standardEvent(.viewItem, withContentItem: buo).logEvent()
[[BranchEvent standardEvent:BranchStandardEventViewItem withContentItem:buo] logEvent];

追踪事件

  • 与客户购买有关的所有事件都会归类到数据项的 “Commerce” 类别中
  • 与用户与应用中内容交互相关的所有事件都会归类到数据项的 “Content” 类别中。
  • 与用户在应用中的进展相关的所有事件都会归类到数据项的 “Lifecycle” 类别中。
  • To track custom events - not found in the table below - please see Track Custom Events
  • Validate with the Branch Dashboard

使用下表快速找到您要追踪的事件。

Event 名称

事件类别

iOS

添加到购物车

Commerce Event

BranchStandardEventAddToCart

加到收藏夹

Commerce Event

BranchStandardEventAddToWishlist

查看购物车

Commerce Event

BranchStandardEventViewCart

发起购买

Commerce Event

BranchStandardEventInitiatePurchase

添加付款信息

Commerce Event

BranchStandardEventAddPaymentInfo

购买

Commerce Event

BranchStandardEventPurchase

消费积分

Commerce Event

BranchStandardEventSpendCredits

搜索

Content 事件

BranchStandardEventSearch

查看商品

Content 事件

BranchStandardEventViewItem

查看商品

Content 事件

BranchStandardEventViewItems

频率

Content 事件

BranchStandardEventRate

分享

Content 事件

BranchStandardEventShare

完成注册

Lifecycle Event

BranchStandardEventCompleteRegistration

完成教程

Lifecycle Event

BranchStandardEventCompleteTutorial

达标级别

Lifecycle Event

BranchStandardEventAchieveLevel

解锁成就

Lifecycle Event

BranchStandardEventUnlockAchievement

Handle Branch Links when using Branch & Firebase SDK

There is a known issue with Firebase where it will call the following Instance Methods:

To account for this, you must check the link first to determine if it should be handled by the Branch SDK:

func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
  //check for link_click_id
  if url.absoluteString.contains("link_click_id") == true{
    return Branch.getInstance().application(app, open: url, options: options)
  }
}

func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
  //check for app.link or appropriate Branch custom domain
  if userActivity.webpageURL?.absoluteString.contains("app.link"){
    return Branch.getInstance().continue(userActivity)
  }
}
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
  if ([url.absoluteString containsString:@"link_click_id"])  {
    return [[Branch getInstance] application:app openURL:url options:options];
  }
}

- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler {
  if ([userActivity.webpageURL.absoluteString containsString:@"app.link"]) {
    return [[Branch getInstance] continueUserActivity:userActivity];
  }
}

处理推送通知

  • 可让您在推送通知中追踪 Branch 深度链接
  • Include the Branch push notification handler in Initialize Branch
  • 在您的推送通知中添加 Branch 深度链接 payload
    • 更换 https://example.app.link/u3fzDwyyjF with your deep link
{
  "aps": {
    "alert": "Push notification with a Branch deep link",
    "badge": "1"
  },
  "branch": "https://example.app.link/u3fzDwyyjF"
}

处理应用中的链接

  • 可让您从应用内深度链接到应用本身
Branch.getInstance().handleDeepLink(withNewSession: URL(string: "https://example.app.link/u3fzDwyyjF"))
[[Branch getInstance] handleDeepLinkWithNewSession:[NSURL URLWithString:@"https://example.app.link/u3fzDwyyjF"]];

❗️

在您的应用中处理新的深度链接

在应用中处理新的深度链接将清除当前会话数据,并将新引用的 “open” 归因于此。

延迟 Branch 初始化

延迟 Install 的 Branch 初始化,以向用户请求追踪许可。

  1. 创建一个表示 Install session 的布尔值标记并将其设置为 true (例如firstOpen)
  2. didFinishLaunchingWithOptions 初始化 Branch 之前
    a. 如果为 false,则继续 Branch SDK 初始化
    b. 如果为 true
    i. 当 firstOpen 为 true 时,在整个用户引导流程中坚持使用 launchOptions 或在本地存储
    ii. 继续用户引导流程
  3. After determining User's tracking preference
    a. Set tracking in Branch SDK per User's preference
    b. Initilialize the Branch SDK utilizing the persisted launchOptions
  4. 将 Install boolean ( firstOpen) 设置为 false

启用100%匹配

To enable 100% Matching on iOS through Installs, please utilize our NativeLink™ feature.

启用/禁用用户追踪

如果您需要按照 GDPR 的目的遵循用户不被追踪的请求,或者认为用户不应该被追踪,请利用此字段来防止 Branch 发送网络请求。此设置也可以在所有用户的特定链接或 Branch Link 中被启用。

Branch.setTrackingDisabled(true)
[Branch setTrackingDisabled:YES];

您可以选择在应用的整个生命周期中调用它。调用后,网络请求将不会从 SDK发送。链接生成将继续起作用,但是不会包含有关用户的标识信息。此外,深度链接将继续起作用,但不会为用户追踪分析。

分享到电子邮件选项

  • 更改当分享到电子邮件时深度链接的行为
  • Needs a Share deep link
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")
[lp addControlParam:@"$email_subject" withValue:@"This one weird trick."];
[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"];

动态分享消息

  • 根据用户选择的来源更改您分享的消息
  • Needs a Share deep link
// import delegate
class ViewController: UITableViewController, BranchShareLinkDelegate

func branchShareLinkWillShare(_ shareLink: BranchShareLink) {
  // choose shareSheet.activityType
  shareLink.shareText = "\(shareLink.linkProperties.channel)"
}
// import delegate
@interface ViewController () <BranchShareLinkDelegate>

  - (void) branchShareLinkWillShare:(BranchShareLink*)shareLink {
  // choose shareSheet.activityType
  shareLink.shareText = [NSString stringWithFormat:@"@%", shareLink.linkProperties.channel];
}

返回 YES 继续 continueUserActivity

When users enter your app via a Universal Link, we check to see to see if the link URL contains app.link. If so, Branch.getInstance().continue(userActivity) will return YES. If not, Branch.getInstance().continue(userActivity) will return NO. This allows us to explicitly confirm the incoming link is from Branch without making a server call.

For most implementations this will never be an issue, since your deep links will be routed correctly either way. However, if you use a custom link domain and you rely on Branch.getInstance().continue(userActivity) to return YES for every incoming Branch-generated Universal Link, you can inform the Branch SDK by following these steps:

  1. In your Info.plist file, create a new key called branch_universal_link_domains
  2. 将您的自定义域添加为 string。 图片图片
  3. 保存文件。

📘

多个自定义域

If you have an unusual situation with multiple custom link domains, you may also configure branch_universal_link_domains as an array of strings. 图片图片

处理 web-only 内容的链接

🚧

仅通用电子邮件

If you have links to content that exists only on the web and not in the app (for example, a temporary marketing webpage that isn't in the app), then this code snippet will ensure all links that have not had the deep linking script applied will open in a browser.

You should add this code snippet inside the deep link handler code block.

📘

注意

This uses query parameter $web_only=true. This should match the query parameter on the web URL you enter in the email.

[branch initSessionWithLaunchOptions:launchOptions andRegisterDeepLinkHandler:^(NSDictionary *params, NSError *error) {
  // params are the deep linked params associated with the link that the user clicked before showing up.
  if (params[@"$3p"] && params[@"$web_only"]) {
            NSURL *url = [NSURL URLWithString:params[@"$original_url"]];
            if (url) {
                [application openURL:url]; // check to make sure your existing deep linking logic, if any, is not executed, perhaps by returning early
            }
  } else {
    // it is a deep link
    GDLog(@"branch deep link: %@", [params description]);
    [self handleBranchDeeplink:params];
  }
}];
branch.initSession(launchOptions: launchOptions, andRegisterDeepLinkHandler: { (params, error) in
            if (params?["$3p"] != nil && params?["$web_only"] != nil) {
                if let urlString = params?["$original_url"] as? String {
                    if let url = URL(string: urlString) {
                        application.openURL(url)
                    }
                }
            } else {
                self.handleBranchDeeplink(params)
            }
        })

Universal Links with Web-Only Content

Web-only Branch links that redirect to a site that hosts its own AASA file where Universal Links (UL) is enabled will cause unexpected behavior. Since Branch does not have a way to bypass UL (via JavaScript, delays, etc.), you must add a query param 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 their own 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. ex. https://myhomepage.com/?$web_only=true
This link with the query parameter can now be used as the fallback of a web-only Branch link and persist the behavior all the way to myhomepage.com.

设置初始化 metadata

🚧

仅限数据集成

If you are using a 3rd Party Data Integration Partner that requires setting certain identifiers before initializing the Branch SDK, you should add this code snippet:

//Inside *didFinishLaunchingWithOptions*
[[Branch getInstance] setRequestMetadataKey:@"{ANALYTICS_ID}" value: […]];

更换 {ANALYTICS_ID} with your Data Integration Partner's key.

App Clip

👍

App Clip 分析

我们将自动为 App Clip 触点(例如 QR 码扫描)和会话进行归因。
触点:

  • 事件名称:Click
  • last_attributed_touch_data_tilde_customer_placement: APP_CLIP
  • last_attributed_touch_data_tilde_creative_name: Set as $app_clip_id value if it is present in the App Clip link.

会话:

  • 事件名称:Install/Open
  • user_data_environment: APP_CLIP
  • last_attributed_touch_data_tilde_creative_name: Set as $app_clip_id value if it is present.

An App Clip is a lightweight version of your app that offers users some of its functionality when and where they need it.

Follow Apple's developer documentation on creating an App Clip with Xcode

📘

Important to note

  • The Associated Domains entitlement has a new appclips type, which is required if you’re implementing app clips.
    • 必须更新 AASA 文件以支持 app clip;通过 Branch 数据库更新。
      • Please Submit a Ticket to make this request. Make sure to include your App Clip bundle ID and team ID in your request.

The Branch iOS SDK must be integrated into an App Clip in the same way as the Full App; with the following caveats:

  • You do not need the applinks setting in the App Clip's Associated Domains entitlement.
  • Cocoapods 不会将 Branch SDK 安装到您的 App Clip 中。

如何将 App Clip 安装数据持久保存到后续 Full App Install 中

  1. 添加 App Groups 权利。
  2. 选择一个组,它将用于在 App Clip 和后续 Full App Install 之间分享数据。
25602560
  1. In both your Full App and App Clip, inform the Branch SDK of the App Group name prior to calling initSession. See Apple's developer doc for more information.
[[Branch getInstance] setAppClipAppGroup:@"group.io.branch"];
Branch.getInstance().setAppClipAppGroup("group.io.branch")

将 Branch Link 作为 App Clip Invocation URL

You can configure Branch links to be associated with App Clips. When creating a link, you specify which App Clip the Branch link should open. You do this via a Branch link parameter called $app_clip_id

比方说您有两个 App Clip,一个用于 Store,一个用于 Product。

在 iTunesConnect 操作后台 (Dashboard)上,您需要将以下两项注册为高级 App Clip Experience:

  • your.app.link/ac/s/*-- 用于 Store 链接
  • your.app.link/ac/p/* -- 用于 Product 链接

Then when creating a Branch link, you set $app_clip_ids, as seen below:

14681468

Then Branch will automatically create a 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 links. If you set $app_clip_url = s and alias to 12345, you'll get the following link: https://your.app.link/ac/s/12345. This would be a great way to create a link to Store with ID 12345!

📘

注意

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.

🚧

App Clip Code invocation URL 的字符长度限制较短

与大多数 App Clip 不同,App Clip 代码对 URL 长度限制较短。长度限制有所不同,但大约为35个字符。您的 Branch Link 可能太长,无法在这种情况下使用。尽可能使用最短的展示位置标识符(placement identifier)来增加生成足够短的链接的几率。我们建议指定一个简短的 $app_clip_id 和别名。

https://developer.apple.com/documentation/app_clips/creating_app_clip_codes

在 iOS 渠道上调用 App Clip

Once you have registered your Branch App Clip with Apple, Apple allows you to invoke App Clips on a few channels. Here's an example: https://branchster.app.link/6ZfIMUrDzbb#appclip

iMessage

200200

默认情况下,如果 Branch Links 被注册为 App Clip Invocation URL,它们将自动在 iMessage 上注册并显示您的 App Clip CTA。

Safari 广告横幅

200200

您也可以自己在网站上显示 App Clip 广告横幅。为此,您需要将标准的 Apple 元标签添加到您的网站:

<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 documentation.

包括 Apple 的 ATTrackingManager

🚧

Requires the inclusion of AdSupport Framework

In order for the ATTrackingManager to function, you must also ensure you've added the AdSupport framework in your iOS SDK implementation.

By default, the Branch 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.

如果您想使用 IDFA,则需要在您应用程序流中的适当时间显示 ATTrackingManager 提示符。此示例代码演示了如何显示提示符并记录 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);
    }
}

从 Branch iOS SDK 1.39.1 开始,在最终用户授予的情况下,SDK 将看到授权状态。您无需再进行其他额外操作来通知 Branch SDK。

在较早版本的 SDK 上,服务器会通过是否存在 IDFA 来推断授权状态。同样,您无需再进行其他额外操作来通知 Branch SDK。

Set Hashed Information for Facebook Advanced Matching

You can pass additional hashed information to the SDK before initSession() for Facebook Advanced Matching.

...
//set hash parameters for Facebook Advanced Matching
Branch.getInstance().addFacebookPartnerParameter(withName: "em", value: "11234e56af071e9c79927651156bd7a10bca8ac34672aba121056e2698ee7088")
...
//initialize Branch session
Branch.getInstance().initSession(...)