Android 高级功能

创建内容引用 (Content Reference)

BranchUniversalObject buo = new BranchUniversalObject()
        .setCanonicalIdentifier("content/12345")
        .setTitle("My Content Title")
        .setContentDescription("My Content Description")
        .setContentImageUrl("https://lorempixel.com/400/400")
        .setContentIndexingMode(BranchUniversalObject.CONTENT_INDEX_MODE.PUBLIC)
        .setLocalIndexMode(BranchUniversalObject.CONTENT_INDEX_MODE.PUBLIC)
        .setContentMetadata(new ContentMetadata().addCustomMetadata("key1", "value1"));
val buo = BranchUniversalObject()
        .setCanonicalIdentifier("content/12345")
        .setTitle("My Content Title")
        .setContentDescription("My Content Description")
        .setContentImageUrl("https://lorempixel.com/400/400")
        .setContentIndexingMode(BranchUniversalObject.CONTENT_INDEX_MODE.PUBLIC)
        .setLocalIndexMode(BranchUniversalObject.CONTENT_INDEX_MODE.PUBLIC)
        .setContentMetadata(ContentMetadata().addCustomMetadata("key1", "value1"))

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

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

branchUniversalObject.generateShortUrl(this, linkProperties, new BranchLinkCreateListener() {
        @Override
        public void onLinkCreate(String url, BranchError error) {
            if (error == null) {
                Log.i("MyApp", "got my Branch link to share: " + url);
            }
        }
    });

您可以在上面找到 linkProperties 示例。接下来,您将使用返回的链接,并帮助用户将其发布到 Facebook(在此示例中)。

指定共享的电子邮件主题

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

ShareSheetStyle shareSheetStyle = new ShareSheetStyle(MainActivity.this, "Your Awesome Deal", "You will never believe what happened next!")
                            .setCopyUrlStyle(getResources().getDrawable(android.R.drawable.ic_menu_send), "Copy", "Added to clipboard")
                            .setMoreOptionStyle(getResources().getDrawable(android.R.drawable.ic_menu_search), "Show more")
                            .addPreferredSharingOption(SharingHelper.SHARE_WITH.FACEBOOK)
                            .addPreferredSharingOption(SharingHelper.SHARE_WITH.EMAIL)
                            .setAsFullWidthStyle(true)
                            .setSharingTitle("Share With");

创建深度链接

LinkProperties lp = new LinkProperties()
        .setChannel("facebook")
        .setFeature("sharing")
        .setCampaign("content 123 launch")
        .setStage("new user")
        .addControlParameter("$desktop_url", "http://example.com/home")
        .addControlParameter("custom", "data")
        .addControlParameter("custom_random", Long.toString(Calendar.getInstance().getTimeInMillis()));

    buo.generateShortUrl(this, lp, new Branch.BranchLinkCreateListener() {
        @Override
        public void onLinkCreate(String url, BranchError error) {
            if (error == null) {
                Log.i("BRANCH SDK", "got my Branch link to share: " + url);
            }
        }
    });
val lp = LinkProperties()
        .setChannel("facebook")
        .setFeature("sharing")
        .setCampaign("content 123 launch")
        .setStage("new user")
        .addControlParameter("$desktop_url", "http://example.com/home")
        .addControlParameter("custom", "data")
        .addControlParameter("custom_random", Long.toString(Calendar.getInstance().getTimeInMillis()))

    buo.generateShortUrl(this, lp, BranchLinkCreateListener { url?, error? ->
        if (error == null) {
            Log.i("BRANCH SDK", "got my Branch link to share: " + url)
        }
    })

分享深度链接

LinkProperties lp = new LinkProperties()
        .setChannel("facebook")
        .setFeature("sharing")
        .setCampaign("content 123 launch")
        .setStage("new user")
        .addControlParameter("$desktop_url", "http://example.com/home")
        .addControlParameter("custom", "data")
        .addControlParameter("custom_random", Long.toString(Calendar.getInstance().getTimeInMillis()));

    ShareSheetStyle ss = new ShareSheetStyle(MainActivity.this, "Check this out!", "This stuff is awesome: ")
        .setCopyUrlStyle(ContextCompat.getDrawable(this, android.R.drawable.ic_menu_send), "Copy", "Added to clipboard")
        .setMoreOptionStyle(ContextCompat.getDrawable(this, android.R.drawable.ic_menu_search), "Show more")
        .addPreferredSharingOption(SharingHelper.SHARE_WITH.FACEBOOK)
        .addPreferredSharingOption(SharingHelper.SHARE_WITH.EMAIL)
        .addPreferredSharingOption(SharingHelper.SHARE_WITH.MESSAGE)
        .addPreferredSharingOption(SharingHelper.SHARE_WITH.HANGOUT)
        .setAsFullWidthStyle(true)
        .setSharingTitle("Share With");

    buo.showShareSheet(this, lp,  ss,  new Branch.BranchLinkShareListener() {
        @Override
        public void onShareLinkDialogLaunched() {
        }
        @Override
        public void onShareLinkDialogDismissed() {
        }
        @Override
        public void onLinkShareResponse(String sharedLink, String sharedChannel, BranchError error) {
        }
        @Override
        public void onChannelSelected(String channelName) {
        }
    });
var lp = LinkProperties()
        .setChannel("facebook")
        .setFeature("sharing")
        .setCampaign("content 123 launch")
        .setStage("new user")
        .addControlParameter("$desktop_url", "http://example.com/home")
        .addControlParameter("custom", "data")
        .addControlParameter("custom_random", Long.toString(Calendar.getInstance().getTimeInMillis()))

    val ss = ShareSheetStyle([email protected], "Check this out!", "This stuff is awesome: ")
        .setCopyUrlStyle(resources.getDrawable(this, android.R.drawable.ic_menu_send), "Copy", "Added to clipboard")
        .setMoreOptionStyle(resources.getDrawable(this, android.R.drawable.ic_menu_search), "Show more")
        .addPreferredSharingOption(SharingHelper.SHARE_WITH.FACEBOOK)
        .addPreferredSharingOption(SharingHelper.SHARE_WITH.EMAIL)
        .addPreferredSharingOption(SharingHelper.SHARE_WITH.MESSAGE)
        .addPreferredSharingOption(SharingHelper.SHARE_WITH.HANGOUT)
        .setAsFullWidthStyle(true)
        .setSharingTitle("Share With")

    buo.showShareSheet(this, lp, ss, object : Branch.BranchLinkShareListener {
        override fun onShareLinkDialogLaunched() {}
        override fun onShareLinkDialogDismissed() {}
        override fun onLinkShareResponse(sharedLink: String?, sharedChannel: String?, error: BranchError?) {}
        override fun onChannelSelected(channelName: String) {}
    })

读取深度链接

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

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

  • 返回深度链接属性

// listener (within Main Activity's onStart)
    Branch.sessionBuilder(this).withCallback(new Branch.BranchReferralInitListener() {
        @Override
        public void onInitFinished(JSONObject referringParams, BranchError error) {
            if (error == null) {
                Log.i(""BRANCH SDK"", referringParams.toString());
            } else {
                Log.i(""BRANCH SDK"", error.getMessage());
            }
        }
    }).withData(this.getIntent().getData()).init();

    // latest
    JSONObject sessionParams = Branch.getInstance().getLatestReferringParams();

    // first
    JSONObject installParams = Branch.getInstance().getFirstReferringParams();
// listener (within Main Activity's onStart)
    Branch.sessionBuilder(this).withCallback(object : BranchReferralInitListener {
        override fun onInitFinished(referringParams: JSONObject?, error: BranchError?) {
            if (error == null) {
                Log.i(""BRANCH SDK"", referringParams.toString())
            } else {
                Log.e(""BRANCH SDK"", error.message)
            }
        }
    }).withData(this.intent.data).init()

    // latest
    val sessionParams = Branch.getInstance().latestReferringParams

    // first
    val installParams = Branch.getInstance().firstReferringParams

前往内容

  • 用 Branch 深度链接数据工作
// listener (within Main Activity's onStart)
    Branch.sessionBuilder(this).withCallback(new Branch.BranchReferralInitListener() {
        @Override
        public void onInitFinished(JSONObject referringParams, BranchError error) {
            if (error == null) {

              // option 1: log data
              Log.i(""BRANCH SDK"", referringParams.toString());

              // option 2: save data to be used later
              SharedPreferences preferences = MainActivity.this.getSharedPreferences(""MyPreferences"", Context.MODE_PRIVATE);
              preferences.edit().putString(""branchData"", referringParams.toString()).apply();

              // option 3: navigate to page
              Intent intent = new Intent(MainActivity.this, OtherActivity.class);
              startActivity(intent);

              // option 4: display data
              Toast.makeText(MainActivity.this, referringParams.toString(), Toast.LENGTH_LONG).show();

            } else {
                Log.i(""BRANCH SDK"", error.getMessage());
            }
          }
        }).withData(this.getIntent().getData()).init();
// listener (within Main Activity's onStart)
    Branch.sessionBuilder(this).withCallback(object : BranchReferralInitListener {
        override fun onInitFinished(referringParams: JSONObject?, error: BranchError?) {
            if (error == null) {
                // option 1: log data
                Log.i(""BRANCH SDK"", referringParams.toString())

                // option 2: save data to be used later
                val preferences =  getSharedPreferences(""MyPreferences"", Context.MODE_PRIVATE)
                preferences.edit().putString(""branchData"", referringParams.toString()).apply();

                // option 3: navigate to page
                val intent = Intent([email protected], MainActivity2::class.java)
                intent.putExtra(""branchData"", referringParams.toString())
                startActivity(intent)

                // option 4: display data
                Toast.makeText([email protected], referringParams.toString(), Toast.LENGTH_SHORT).show()
            } else {
                Log.e(""BRANCH SDK"", error.message)
            }
        }
    }).withData(this.intent.data).init()

展示内容

implementation 'com.google.firebase:firebase-appindexing:19.0.0' // App indexing
buo.listOnGoogleSearch(this);
buo.listOnGoogleSearch(this);

追踪内容

new BranchEvent(BRANCH_STANDARD_EVENT.VIEW_ITEM).addContentItems(buo).logEvent(context);
BranchEvent(BRANCH_STANDARD_EVENT.VIEW_ITEM).addContentItems(buo).logEvent(context)

追踪用户

  • 设置事件,深度链接和推荐的用户身份(电子邮件,ID,UUID 等)

  • 127 用户 ID 的字符数上限

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

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

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

// logout
Branch.getInstance().logout();

追踪事件

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

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

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

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

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

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

Event 名称事件类别Android
Add To CartCommerce EventBRANCH_STANDARD_EVENT.ADD_TO_CART
Add To WishlistCommerce EventBRANCH_STANDARD_EVENT.ADD_TO_WISHLIST
View CartCommerce EventBRANCH_STANDARD_EVENT.VIEW_CART
Initiate PurchaseCommerce EventBRANCH_STANDARD_EVENT.INITIATE_PURCHASE
Add Payment InfoCommerce EventBRANCH_STANDARD_EVENT.ADD_PAYMENT_INFO
PurchaseCommerce EventBRANCH_STANDARD_EVENT.PURCHASE
Spend CreditsCommerce EventBRANCH_STANDARD_EVENT.SPEND_CREDITS
SearchContent 事件BRANCH_STANDARD_EVENT.SEARCH
View ItemContent 事件BRANCH_STANDARD_EVENT.VIEW_ITEM
View ItemsContent 事件BRANCH_STANDARD_EVENT.VIEW_ITEMS
RateContent 事件BRANCH_STANDARD_EVENT.RATE
ShareContent 事件BRANCH_STANDARD_EVENT.SHARE
Complete RegistrationLifecycle EventBRANCH_STANDARD_EVENT.COMPLETE_REGISTRATION
Complete TutorialLifecycle EventBRANCH_STANDARD_EVENT.COMPLETE_TUTORIAL
Achieve LevelLifecycle EventBRANCH_STANDARD_EVENT.ACHIEVE_LEVEL
Unlock AchievementLifecycle EventBRANCH_STANDARD_EVENT.UNLOCK_ACHIEVEMENT

处理推送通知

  • 只需将 Branch Link 添加到 result intent 中,即可深度链接到 GCM 推送通知中的内容
Intent resultIntent = new Intent(this, TargetActivity.class);
resultIntent.putExtra("branch","http://xxxx.app.link/testlink");
resultIntent.putExtra("branch_force_new_session",true);
PendingIntent resultPendingIntent =  PendingIntent.getActivity(this, 0, resultIntent, PendingIntent.FLAG_UPDATE_CURRENT);
val resultIntent = Intent(this, TargetClass::class.java)
resultIntent.putExtra("branch", "http://xxxx.app.link/testlink")
resultIntent.putExtra("branch_force_new_session", true)
val resultPendingIntent = PendingIntent.getActivity(this, 0, resultIntent, PendingIntent.FLAG_UPDATE_CURRENT)
  • 若要处理点击TargetActivity时推送通知位于前台的情况,请不要忘记从TargetActivity内的onNewIntent调用sessionBuilder()...reInit()
@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    setIntent(intent);
    // if activity is in foreground (or in backstack but partially visible) launching the same
    // activity will skip onStart, handle this case with sessionBuilder()...reInit()
    // will re-initialize only if ""branch_force_new_session=true"" intent extra is set
    Branch.sessionBuilder(this).withCallback(branchReferralInitListener).reInit(this);
}
override fun onNewIntent(intent: Intent) {
        super.onNewIntent(intent)
        this.intent = intent
        // Branch reinit (in case Activity is already visible when Branch link is clicked)
        // will re-initialize only if ""branch_force_new_session=true"" intent extra is set
        Branch.sessionBuilder(this).wothCallback(branchListener).reInit()

❗️

Handling a new deep link via sessionBuilder()....reInit()

通过sessionBuilder()....reInit()处理新的深度链接将清除当前会话数据(如果有的话),并将新引用的 “open” 归因于此。

处理应用中的链接

  • 允许您通过启动 Chrome intent 从应用本身深度链接到自己的应用
Intent intent = new Intent(this, ActivityToLaunch.class);
intent.putExtra("branch","http://xxxx.app.link/testlink");
intent.putExtra("branch_force_new_session",true);
startActivity(intent);
val intent = Intent(this, ActivityToLaunch::class.java)
intent.putExtra("branch", "http://xxxx.app.link/testlink")
intent.putExtra("branch_force_new_session", true)
startActivity(intent)

❗️

处理新的深度链接

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

❗️

链接到当前打开的 activity

与处理推送通知类似,链接到当前打开的 activity 或在后堆栈中且部分可见的 activity 必须通过 sessionBuilder()....reInit() 处理。

延迟 Branch 初始化

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

  1. 创建一个表示 Install session 的布尔值标记并将其设置为 true (例如firstOpen)
  2. 在 Branch 初始化之前:
    a. 如果为 false,则继续 Branch SDK 初始化
    b. 如果为 true
    i. 调用 .expectDelayedSessionInitialization()
    ii. 继续用户引导流程
  3. 确定用户的追踪首选项后
    a. 根据用户的首选项在 Branch SDK 中设置追踪
    b. 使用持久化的 launchOptions 初始化 Branch SDK
  4. 将 Install boolean ( firstOpen) 设置为 false

启用100%匹配

  • 使用 Chrome Tabs 提高归因匹配成功率

  • 将 implementation com.android.support:customtabs:28.0.0 添加到您的 build.gradle

  • 如果您需要自定义标签库,但不希望启用100%匹配,则可以在会话初始化之前调用Branch.enableCookieBasedMatching(null)

延迟会话初始化

有时,用户可能需要延迟会话初始化,例如进行异步调用以获得一些需要作为请求 metadata传递给 Branch 的数据。

在这种情况下,您可能会遇到 “SDK 已初始化”错误,这是由于 Activity 进入 RESUMED 状态时 Branch 会自行初始化会话而发生的。为避免这种情况,您可以手动禁用自动会话初始化,并在异步调用完成后自行初始化会话。

LauncherActivity.onStart() {
    ...
    Branch.expectDelayedSessionInitialization()
}
asyncOperationCallback() {
    Branch.sessionBuilder(activity).withCallback(callback)...init();
}

请注意,如果没有进行会话初始化,SDK 将无法执行大多数操作,因此应用必须确保自行初始化会话(即使从未调用 asyncOperationCallback)。

另外,应用可以利用如下所示的内置会话延迟机制:

LauncherActivity.onStart() {
    // waits for Branch.getInstance().removeSessionInitializationDelay() or inits after TIMEOUT 
    Branch.sessionBuilder(activity).withCallback(callback).withDelay(TIMEOUT)...init();
}
asyncOperationCallback() {
    // starts session initialization right away
    Branch.getInstance().removeSessionInitializationDelay();
}

启用/禁用用户追踪

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

Branch.getInstance().disableTracking(true);

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

设置初始化 metadata

🚧

仅限数据集成

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

//Before you initialize the session.
Branch.getInstance().setRequestMetadata("{ANALYTICS_ID}", […]);

{ANALYTICS_ID}替换为您的数据集成伙伴的 key。

控制 Branch 如何处理网络请求

默认情况下,Branch Android SDK 使用 Java 的javax.net.ssl.HttpsURLConnection进行网络请求。该接口存在已知问题,通常应用使用第三方网络库 (例如 OkHttp) 来自定义其网络。Branch SDK 提供一个接口BranchRemoteInterface,以将您的网络自定义应用于 Branch 处理网络请求的方式。使用以下 API 来设置BranchRemoteInterface以处理 Branch 的请求。

setBranchRemoteInterface(@NonNull BranchRemoteInterface remoteInterface)
setBranchRemoteInterface(remoteInterface: BranchRemoteInterface)

以下是使用 OkHttp 实现BranchRemoteInterface的示例。

public class OkhttpBranchNetworkInterface extends BranchRemoteInterface {
  private OkHttpClient okHttpClient = new OkHttpClient.Builder().readTimeout(3, TimeUnit.SECONDS).writeTimeout(3, TimeUnit.SECONDS).connectTimeout(3, TimeUnit.SECONDS).build();

  @Override
  public BranchResponse doRestfulGet(String url) throws BranchRemoteException {
    Request request = new Request.Builder().url(url).build();

    return handleNetworkRequest(request);
  }

  @Override
  public BranchResponse doRestfulPost(String url, JSONObject payload) throws BranchRemoteException {
    Request request = new Request.Builder().url(url).post(RequestBody.create(MediaType.parse("application/json"), payload.toString())).build();

    return handleNetworkRequest(request);
  }

  private BranchResponse handleNetworkRequest(Request request) throws BranchRemoteException {
    try {
      Response response = okHttpClient.newCall(request).execute();
      ResponseBody rb = response.body();
      if (rb != null) throw new BranchRemoteException(BranchError.ERR_BRANCH_NO_CONNECTIVITY);
      return new BranchResponse(rb.string(), response.code());
    } catch(Exception exception) {
      if (exception instanceof SocketTimeoutException) {
        // add desired retry logic, then eventually throw BranchError.ERR_BRANCH_REQ_TIMED_OUT
        throw new BranchRemoteException(BranchError.ERR_BRANCH_REQ_TIMED_OUT);
      } else {
        // handle other failures as needed, throw BranchError.ERR_BRANCH_NO_CONNECTIVITY as a default
        throw new BranchRemoteException(BranchError.ERR_BRANCH_NO_CONNECTIVITY);
      }
    }
  }
}
public class OkhttpBranchNetworkInterface extends BranchRemoteInterface {
  private OkHttpClient okHttpClient = new OkHttpClient.Builder().readTimeout(3, TimeUnit.SECONDS).writeTimeout(3, TimeUnit.SECONDS).connectTimeout(3, TimeUnit.SECONDS).build();

  @Override
  public BranchResponse doRestfulGet(String url) throws BranchRemoteException {
    Request request = new Request.Builder().url(url).build();

    return handleNetworkRequest(request);
  }

  @Override
  public BranchResponse doRestfulPost(String url, JSONObject payload) throws BranchRemoteException {
    Request request = new Request.Builder().url(url).post(RequestBody.create(MediaType.parse("application/json"), payload.toString())).build();

    return handleNetworkRequest(request);
  }

  private BranchResponse handleNetworkRequest(Request request) throws BranchRemoteException {
    try {
      Response response = okHttpClient.newCall(request).execute();
      ResponseBody rb = response.body();
      if (rb != null) throw new BranchRemoteException(BranchError.ERR_BRANCH_NO_CONNECTIVITY);
      return new BranchResponse(rb.string(), response.code());
    } catch(Exception exception) {
      if (exception instanceof SocketTimeoutException) {
        // add desired retry logic, then eventually throw BranchError.ERR_BRANCH_REQ_TIMED_OUT
        throw new BranchRemoteException(BranchError.ERR_BRANCH_REQ_TIMED_OUT);
      } else {
        // handle other failures as needed, throw BranchError.ERR_BRANCH_NO_CONNECTIVITY as a default
        throw new BranchRemoteException(BranchError.ERR_BRANCH_NO_CONNECTIVITY);
      }
    }
  }
}

8个月前更新



Android 高级功能


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

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