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 示例。接下来,您将使用返回的链接,并帮助用户将其发布到 Facebook(在此示例中)。

指定共享的电子邮件主题

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

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

读取深度链接

  • 从深度链接中提取 Branch 数据

  • listener 接收数据的最佳实践(以防止出现 race condition)

  • 返回深度链接属性

// 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 let currentIOSVersion = Int(UIDevice.current.systemVersion), currentIOSVersion >= 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 ([[[UIDevice currentDevice] systemVersion] compare:@"15.0" options:NSNumericSearch] != NSOrderedAscending)
        [[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  
    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
        [[Branch getInstance] checkPasteboardOnInstall];
  
    // check if pasteboard toast will show
    if ([Branch 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;
}

前往内容

  • 在此方法中处理 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 (ATTrackingManager.trackingAuthorizationStatus == .notDetermined) {
    ATTrackingManager.requestTrackingAuthorization { (status) in
        Branch.getInstance().handleATTAuthorizationStatus(status.rawValue)
    }
}
if (ATTrackingManager.trackingAuthorizationStatus == ATTrackingManagerAuthorizationStatusNotDetermined) {
    [ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {
        [[Branch getInstance] handleATTAuthorizationStatus:status];
    }];
}

追踪内容

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

追踪事件

  • 与客户购买有关的所有事件都会归类到数据项的 “Commerce” 类别中

  • 与用户与应用中内容交互相关的所有事件都会归类到数据项的 “Content” 类别中。

  • 与用户在应用中的进展相关的所有事件都会归类到数据项的 “Lifecycle” 类别中。

  • 要跟踪自定义事件(在下表中没有的),请参见追踪自定义事件

  • 通过 Branch 操作后台 (Dashboard)进行验证

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

Event 名称事件类别iOS
Add To CartCommerce EventBranchStandardEventAddToCart
Add To WishlistCommerce EventBranchStandardEventAddToWishlist
View CartCommerce EventBranchStandardEventViewCart
Initiate PurchaseCommerce EventBranchStandardEventInitiatePurchase
Add Payment InfoCommerce EventBranchStandardEventAddPaymentInfo
PurchaseCommerce EventBranchStandardEventPurchase
Spend CreditsCommerce EventBranchStandardEventSpendCredits
SearchContent 事件BranchStandardEventSearch
View ItemContent 事件BranchStandardEventViewItem
View ItemsContent 事件BranchStandardEventViewItems
RateContent 事件BranchStandardEventRate
ShareContent 事件BranchStandardEventShare
Complete RegistrationLifecycle EventBranchStandardEventCompleteRegistration
Complete TutorialLifecycle EventBranchStandardEventCompleteTutorial
Achieve LevelLifecycle EventBranchStandardEventAchieveLevel
Unlock AchievementLifecycle EventBranchStandardEventUnlockAchievement

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)
  }
}

处理推送通知

  • 可让您在推送通知中追踪 Branch 深度链接

  • 将 Branch 推送通知处理代码包括在Branch 初始化中

  • 在您的推送通知中添加 Branch 深度链接 payload

    • 用您的深度链接替换https://example.app.link/u3fzDwyyjF
{
  "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. 确定用户的追踪首选项后
    a. 根据用户的首选项在 Branch SDK 中设置追踪
    b. 使用持久化的 launchOptions 初始化 Branch SDK
  4. 将 Install boolean ( firstOpen) 设置为 false

追踪 Apple Search Ads

  • 允许 Branch 追踪 Apple Search Ads 深度链接分析

  • Apple API 的分析速度很慢,这会使我们的分析水平降低。此外,Apple 的 API 不会每次都向我们发送广告的所有数据,这会使我们追踪的广告有时会显示一般的 campaign。

  • initSession Branch 初始化之前添加

Branch.getInstance().delayInitToCheckForSearchAds()
[[Branch getInstance] delayInitToCheckForSearchAds];

启用100%匹配

  • 使用SFSafariViewController来提高归因匹配成功率

  • 说100%匹配有些不妥,因为只有当用户在 Safari 浏览器进行点击时才会有100%匹配。根据我们的分析,通过 Safari 浏览器点击的概率大约有50-75%,具体取决于用例。例如,从 Facebook 或 Chrome 浏览器点击不会触发100%的匹配。但是,它仍然对匹配准确度有利,因此我们建议采用它。

  • 使用自定义域时,请在 Info.plist 中添加一个带有定义域的branch_app_domain string key
    以启用100%匹配。

  • 默认情况下,如果SafariServices.framework
    包含在应用的依赖项中,则基于 cookie 的匹配会在 iOS 9和10中启用,并且该应用使用 app.link 子域或在 Info.plist 设置branch_app_domain
    。它可以通过调用 SDK 来禁用。

  • initSession Branch 初始化之前添加

Branch.getInstance().disableCookieBasedMatching()
[[Branch getInstance] disableCookieBasedMatching];

启用/禁用用户追踪

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

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

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

分享到电子邮件选项

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

动态分享消息

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

当用户通过 Universal Link 进入您的应用时,我们将检查链接 URL 是否包含 app.link 。如果是这样,则 Branch.getInstance().continue(userActivity) 将返回 YES 。如果不是,则 Branch.getInstance().continue(userActivity) 将返回 NO 。这使我们可以明确确认传入的链接来自 Branch,而无需进行服务器调用。

对于大多数实现而言,这不会造成问题,因为您的深度链接将在任一情况下都将正确路由。但是,如果您使用自定义 Link Domain, 依靠 Branch.getInstance().continue(userActivity) 为每个传入的 Branch Universal Link 返回 YES ,您可以按照以下步骤通知 Branch SDK:

  1. 在您的 Info.plist 文件中,创建一个名为 branch_universal_link_domains 的新 Key。
  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 内容的链接

🚧

仅通用电子邮件

如果您具有仅存在于网页而非应用中的内容的链接(例如,不在应用中的临时营销网页),则此代码片段将确保所有未应用深度链接脚本的链接在浏览器中打开。

您应该在深度链接处理程序代码块内添加此代码段。请注意,这使用查询参数$web_only=true 。这应该与您在电子邮件中输入的Web URL上的查询参数匹配。

[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

🚧

仅限数据集成

如果您使用第三方数据集成伙伴,在初始化 Branch SDK 前需要设置特定标识符,您则应该添加此代码片段:

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

{ANALYTICS_ID}替换为您的数据集成伙伴的 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:如果在 App Clip 链接内,则设置为$app_clip_id

会话:

  • 事件名称:Install/Open
  • user_data_environment: APP_CLIP
  • last_attributed_touch_data_tilde_creative_name :设置为$app_clip_id值(如果存在)。

App Clip 是应用的轻量级版本,可在需要的时间和地点向用户提供其某些功能。

遵循 Apple 开发人员文档以使用 Xcode 创建 App Clip

重要注意事项:

  • 关联域 (Associated Domains)权利具有新的appclips类型,如果要实现 app clip,则必须使用它。
  • 必须更新 AASA 文件以支持 app clip;通过 Branch 数据库更新。
    • 提交工单以提出此请求。请确保在您的请求中包含您的 App Clip Bundle ID 团队 ID

Branch iOS SDK 必须以与 Full App 相同的方式集成到 App Clip 中;有以下警告:

  • 您不需要 App Clip 的关联域 (Associated Domains)权利中的applinks设置。
  • Cocoapods 不会将 Branch SDK 安装到您的 App Clip 中。

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

  1. 添加 App Groups 权利。
  2. 选择一个组,它将用于在 App Clip 和后续 Full App Install 之间分享数据。
  1. 在 Full App 和 App Clip 中,调用initSession之前将 App Group 名称告知 Branch SDK。有关更多信息,请参阅 Apple 开发人员文档
[[Branch getInstance] setAppClipAppGroup:@"group.io.branch"];
Branch.getInstance().setAppClipAppGroup("group.io.branch")

将 Branch Link 作为 App Clip Invocation URL

您可以配置 App Clip 相关 Branch Link。创建链接时,您可以指定 Branch Link 需要打开的 App Clip。您可以通过叫做$app_clip_id的 Branch Link 参数来执行此操作。

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

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

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

然后,在创建 Branch Link 时,您设置$app_clip_id: s,如下所示:

接着,Branch 将自动创建一个 App Clip ID 的链接,并将其作为路径的一部分: https://your.app.link/ac/s/QfJ2H7c7jcb

此外,您可以为这些链接指定别名。如果把 $app_clip_url = s和别名设置为12345 ,您将获得以下链接: https://your.app.link/ac/s/12345。这将是一个很好的方法来创建一个 ID 12345的 Store 的链接!

注意,https://your.app.link/ac/s/12345返回与https://your.app.link/12345相同的有效负载。路径元素只是为了简化注册 App Clip 的体验。

🚧

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

在 Apple 中注册 Branch App Clip 后,Apple 允许您在一些渠道上调用 App Clip。这是一个示例: https://branchster.app.link/6ZfIMUrDzbb#appclip

iMessage

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

Safari 广告横幅

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

<meta name="apple-itunes-app" content="app-id=myAppStoreID, app-clip-bundle-id=appClipBundleID>

如果要在 Branch Deepview 中显示广告横幅,请将其添加到 Branch 操作后台 Deepview Manager 中的 HTML 代码中。

有关更多信息,请参阅 Apple 的文档

包括 Apple 的 ATTrackingManager

🚧

需要包含 AdSupport 框架

为了使 ATTrackingManager 起作用,您还必须确保在 iOS SDK 实现 AdSupport

默认情况下,Branch SDK 不包含 ATTrackingManager ,如果您想收集 IDFA 以进行归因这是必须项。

详细了解 Apple 的App 透明度追踪管理

如果您想使用 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。

24 天前更新


iOS 高级功能


建议的编辑仅限于 API 参考页

您只能建议对 Markdown 正文内容进行修改,而不能建议对 API 说明进行修改。