Android 高级功能
创建内容引用 (Content Reference)
- Branch Universal Object封装了您要分享的内容(内容或用户)
- Uses the Universal Object Properties
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"))
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"));
创建深度链接
- 创建带有封装数据的深度链接 URL
- Needs a Branch Universal Object
- Uses Deep Link Properties
- Validate with the Branch Dashboard
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", "https://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);
}
}
});
分享深度链接
- 生成 Branch 深度链接,并通过用户选择的渠道对其进行标签
- Needs a Branch Universal Object
- Uses Deep Link Properties
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) {}
})
LinkProperties lp = new LinkProperties()
.setChannel("facebook")
.setFeature("sharing")
.setCampaign("content 123 launch")
.setStage("new user")
.addControlParameter("$desktop_url", "https://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) {
}
});
读取深度链接
- 从深度链接中提取 Branch 数据
- 最佳做法是从
listener
(to prevent a race condition) - Returns deep link properties
// 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
// 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();
Create QR Code
- Create a BranchQRCode object and set the properties
- Create a BranchUniversalObject and BranchLinkProperties
- Use getQRCodeAsImage() or getQRCodeAsData() to get your QR code
val qrCode = BranchQRCode()
.setCodeColor("#a4c639")
.setBackgroundColor(Color.WHITE)
.setMargin(1)
.setWidth(512)
.setImageFormat(BranchQRCode.BranchImageFormat.JPEG)
.setCenterLogo("https://cdn.branch.io/branch-assets/1598575682753-og_image.png")
val buo = BranchUniversalObject()
.setCanonicalIdentifier("content/12345")
.setTitle("My Content Title")
.setContentDescription("My Content Description")
.setContentImageUrl("https://lorempixel.com/400/400")
val lp = LinkProperties()
.setChannel("facebook")
.setFeature("sharing")
.setCampaign("content 123 launch")
.setStage("new user")
qrCode.getQRCodeAsImage([email protected], buo, lp, object : BranchQRCodeImageHandler<Any?> {
override fun onSuccess(qrCodeImage: Bitmap) {
//Do something with your QR code here.
}
override fun onFailure(e: Exception) {
Log.d("Failed to get QR code", e.toString())
}
})
BranchQRCode qrCode = new BranchQRCode() //All QR code settings are optional
.setCodeColor("#a4c639")
.setBackgroundColor(Color.WHITE)
.setMargin(1)
.setWidth(512)
.setImageFormat(BranchQRCode.BranchImageFormat.PNG)
.setCenterLogo("https://cdn.branch.io/branch-assets/1598575682753-og_image.png");
BranchUniversalObject buo = new BranchUniversalObject()
.setCanonicalIdentifier("content/12345")
.setTitle("My QR Code");
LinkProperties lp = new LinkProperties()
.setChannel("facebook")
.setFeature("qrCode")
.setCampaign("content 123 launch");
qrCode.getQRCodeAsImage(MainActivity.this, buo, lp, new BranchQRCode.BranchQRCodeImageHandler() {
@Override
public void onSuccess(Bitmap qrCodeImage) {
//Do something with the QR code here.
}
@Override
public void onFailure(Exception e) {
Log.d("Failed to get QR code", String.valueOf(e));
}
});
前往内容
- 用 Branch 深度链接数据工作
// 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()
// 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();
- Needs a Branch Universal Object
- 需要
build.gradle
library
追踪内容
- 追踪一段内容的查看次数
- Needs a Branch Universal Object
- Uses Track content properties
- Validate with the Branch Dashboard
BranchEvent(BRANCH_STANDARD_EVENT.VIEW_ITEM).addContentItems(buo).logEvent(context)
new BranchEvent(BRANCH_STANDARD_EVENT.VIEW_ITEM).addContentItems(buo).logEvent(context);
追踪用户
Sending PII
Be sure to not send any PII through this method. For additional details, please view our guide on Best Practices to Avoid Sending PII to Branch
- Sets the identity of a user (ID, UUID, etc) for events, deep links, and referrals
127
用户 ID 的字符数上限- Validate with the 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” 类别中。
- To track custom events - not found in the table below - please see Track Custom Events
- Validate with the Branch Dashboard
使用下表快速找到您要追踪的事件。
Event 名称 | 事件类别 | Android |
---|---|---|
添加到购物车 | Commerce Event | BRANCH_STANDARD_EVENT.ADD_TO_CART |
加到收藏夹 | Commerce Event | BRANCH_STANDARD_EVENT.ADD_TO_WISHLIST |
查看购物车 | Commerce Event | BRANCH_STANDARD_EVENT.VIEW_CART |
发起购买 | Commerce Event | BRANCH_STANDARD_EVENT.INITIATE_PURCHASE |
添加付款信息 | Commerce Event | BRANCH_STANDARD_EVENT.ADD_PAYMENT_INFO |
购买 | Commerce Event | BRANCH_STANDARD_EVENT.PURCHASE |
消费积分 | Commerce Event | BRANCH_STANDARD_EVENT.SPEND_CREDITS |
搜索 | Content 事件 | BRANCH_STANDARD_EVENT.SEARCH |
查看商品 | Content 事件 | BRANCH_STANDARD_EVENT.VIEW_ITEM |
查看商品 | Content 事件 | BRANCH_STANDARD_EVENT.VIEW_ITEMS |
频率 | Content 事件 | BRANCH_STANDARD_EVENT.RATE |
分享 | Content 事件 | BRANCH_STANDARD_EVENT.SHARE |
完成注册 | Lifecycle Event | BRANCH_STANDARD_EVENT.COMPLETE_REGISTRATION |
完成教程 | Lifecycle Event | BRANCH_STANDARD_EVENT.COMPLETE_TUTORIAL |
达标级别 | Lifecycle Event | BRANCH_STANDARD_EVENT.ACHIEVE_LEVEL |
解锁成就 | Lifecycle Event | BRANCH_STANDARD_EVENT.UNLOCK_ACHIEVEMENT |
处理推送通知
- Deep link to content from push notifications just by adding a Branch link to your result intent
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)
Intent resultIntent = new Intent(this, TargetActivity.class);
resultIntent.putExtra("branch","https://xxxx.app.link/testlink");
resultIntent.putExtra("branch_force_new_session",true);
PendingIntent resultPendingIntent = PendingIntent.getActivity(this, 0, resultIntent, PendingIntent.FLAG_UPDATE_CURRENT);
- 要处理
TargetActivity
is in the foreground when push notification is clicked, don't forget to callsessionBuilder()...reInit()
fromonNewIntent
insideTargetActivity
:
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).withCallback(branchListener).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 reInitSession
if (intent != null &&
intent.hasExtra("branch_force_new_session") &&
intent.getBooleanExtra("branch_force_new_session")) {
Branch.sessionBuilder(this).withCallback(branchReferralInitListener).reInit();
}
}
Handling a new deep link via sessionBuilder()....reInit()
处理新的深度链接
sessionBuilder()....reInit()
will clear the current session data, if there is any, and a new referred ""open"" will be attributed.
处理应用中的链接
- 允许您通过启动 Chrome 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)
Intent intent = new Intent(this, ActivityToLaunch.class);
intent.putExtra("branch","https://xxxx.app.link/testlink");
intent.putExtra("branch_force_new_session",true);
startActivity(intent);
- Replace "https://xxxx.app.link/testlink" with your own link URL
处理新的深度链接
在应用中处理新的深度链接将清除当前会话数据,并将新引用的 “open” 归因于此。
链接到当前打开的 activity
与处理推送通知类似,链接到当前打开的 activity 或在后堆栈中且部分可见的 activity 必须通过
sessionBuilder()....reInit()
。
启用100%匹配
- Uses Chrome Tabs to increase attribute matching success.
- 添加
implementation 'androidx.browser:browser:1.5.0'
to yourbuild.gradle
。 - 如果您需要自定义标签库,但不希望启用100%匹配,则可以在会话初始化之前调用
Branch.enableCookieBasedMatching(null)
prior to session initialization.
延迟会话初始化
有时,用户可能需要延迟会话初始化,例如进行异步调用以获得一些需要作为请求 metadata传递给 Branch 的数据。
在这种情况下,您可能会遇到 “SDK 已初始化”错误,这是由于 Activity 进入 RESUMED 状态时 Branch 会自行初始化会话而发生的。为避免这种情况,您可以手动禁用自动会话初始化,并在异步调用完成后自行初始化会话。
注意: expectDelayedSessionInitialization()
must be called before establishing the Branch singleton within your application class onCreate()
。
package com.eneff.branch.example.android
import android.app.Application
import io.branch.referral.Branch
class CustomApplicationClass : Application() {
override fun onCreate() {
super.onCreate()
// Delay Session Initialization
Branch.expectDelayedSessionInitialization()
// Branch object initialization
Branch.getAutoInstance(this)
}
}
package com.eneff.branch.example.android;
import android.app.Application;
import io.branch.referral.Branch;
public class CustomApplicationClass extends Application {
@Override
public void onCreate() {
super.onCreate();
// Delay Session Initialization
Branch.expectDelayedSessionInitialization();
// Branch object initialization
Branch.getAutoInstance(this);
}
}
启用/禁用用户追踪
如果您需要按照 GDPR 的目的遵循用户不被追踪的请求,或者认为用户不应该被追踪,请利用此字段来防止 Branch 发送网络请求。此设置也可以在所有用户的特定链接或 Branch Link 中被启用。
Branch.getInstance().disableTracking(true)
Branch.getInstance().disableTracking(true);
您可以选择在应用的整个生命周期中调用它。调用后,网络请求将不会从 SDK发送。链接生成将继续起作用,但是不会包含有关用户的标识信息。此外,深度链接将继续起作用,但不会为用户追踪分析。
设置初始化 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:
//Before you initialize the session.
Branch.getInstance().setRequestMetadata("{ANALYTICS_ID}", […]);
更换 {ANALYTICS_ID}
with your Data Integration Partner's key.
控制 Branch 如何处理网络请求
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(remoteInterface: BranchRemoteInterface)
setBranchRemoteInterface(@NonNull BranchRemoteInterface remoteInterface)
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);
}
}
}
}
Set Hashed Information for Facebook Advanced Matching
You can pass additional hashed information to the SDK before init()
for Facebook Advanced Matching.
Branch branch = Branch.getAutoInstance(getApplicationContext())
branch.addFacebookPartnerParameterWithName("em", "194b86d986ad041666822dad7602f1a7bac1d9e286273e86141666ffb4b1909b")
Branch branch = Branch.getAutoInstance(getApplicationContext());
branch.addFacebookPartnerParameterWithName("em", "194b86d986ad041666822dad7602f1a7bac1d9e286273e86141666ffb4b1909b");
Updated about 2 months ago