Android高级功能

创建内容引用

  • 使用 Branch Universal Object 封装您要共享的内容(内容或用户)

  • 使用通用对象属性

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链接或具有另一个用例,则可以通过以下调用直接创建深度链接接:

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 控制面板进行验证

// 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 控制面板进行验证

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

活动名称活动类别安卓
Add To Cart商业活动BRANCH_STANDARD_EVENT.ADD_TO_CART
Add To Wishlist商业活动BRANCH_STANDARD_EVENT.ADD_TO_WISHLIST
View Cart商业活动BRANCH_STANDARD_EVENT.VIEW_CART
Initiate Purchase商业活动BRANCH_STANDARD_EVENT.INITIATE_PURCHASE
Add Payment Info商业活动BRANCH_STANDARD_EVENT.ADD_PAYMENT_INFO
Purchase商业活动BRANCH_STANDARD_EVENT.PURCHASE
Spend Credits商业活动BRANCH_STANDARD_EVENT.SPEND_CREDITS
Search内容事件BRANCH_STANDARD_EVENT.SEARCH
View Item内容事件BRANCH_STANDARD_EVENT.VIEW_ITEM
View Items内容事件BRANCH_STANDARD_EVENT.VIEW_ITEMS
Rate内容事件BRANCH_STANDARD_EVENT.RATE
Share内容事件BRANCH_STANDARD_EVENT.SHARE
Complete Registration生命周期事件BRANCH_STANDARD_EVENT.COMPLETE_REGISTRATION
Complete Tutorial生命周期事件BRANCH_STANDARD_EVENT.COMPLETE_TUTORIAL
Achieve Level生命周期事件BRANCH_STANDARD_EVENT.ACHIEVE_LEVEL
Unlock Achievement生命周期事件BRANCH_STANDARD_EVENT.UNLOCK_ACHIEVEMENT

处理推送通知

  • 只需将Branch链接添加到结果意图中,即可从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 是在被点击的推送通知当前景,不要'忘记调用sessionBuilder()...reInit()onNewIntent 内部TargetActivity
@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 = 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)

❗️

处理新的深层链接

在您的应用程序中处理新的深度链接接将清除当前会话数据,并将新引用的"设为" 。

❗️

链接到当前打开的活动

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

Delay Branch Initialization

Delay the Branch initialization on Installs in order to request tracking permission from the user.

  1. Create a boolean flag to represent an Install session and set it to true (e.g. firstOpen)
  2. Before the Branch init:
    a. if false continue with Branch SDK init
    b. if true:
    i. Call .expectDelayedSessionInitialization()
    ii. Continue with onboarding flow
  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. Set Install boolean (firstOpen) to false

启用100%匹配

  • 使用Chrome Tabs 增加属性匹配成功率

  • Add implementation com.android.support:customtabs:28.0.0 to your build.gradle

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

延迟会话初始化

有时,用户可能需要延迟会话初始化,例如进行异步调用以检索一些需要作为请求元数据传递给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链接中启用此设置。

Branch.getInstance().disableTracking(true);

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

初始化元数据

🚧

仅限数据整合

如果您使用第三方数据整合伙伴,在初始化 Branch SDK 前需要特定标识符设定,您需要添加此代码段:

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

{ANALYTICS_ID}替换为您的数据整合伙伴键钥。

Control How Branch Handles Network Requests

By default, Branch Android SDK uses Java's javax.net.ssl.HttpsURLConnection for network requests. There are known issues with that interface and typically applications use third party networking libraries, such as OkHttp, to customize their networking. Branch SDK provides an interface, BranchRemoteInterface, to apply your networking customization to how Branch handles network requests. Use the below API to set your implementation of BranchRemoteInterface to handle Branch requests.

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

Below is an example of an implementation of BranchRemoteInterface using OkHttp.

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

4 天前更新


推荐的后续步骤

Android SDK常见问题解答

Android高级功能


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

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