Android 问题排查

使用 bnc.lt 或自定义链接域

  • bnc.lt 链接域
<activity android:name="com.yourapp.your_activity">
    <!-- App Link your activity to Branch links-->
    <intent-filter android:autoVerify="true">
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
         <data android:scheme="https" android:host="bnc.lt" />
         <data android:scheme="http" android:host="bnc.lt" />
    </intent-filter>
</activity>
  • 自定义链接域
<activity android:name="com.yourapp.your_activity">
    <!-- App Link your activity to Branch links-->
    <intent-filter android:autoVerify="true">
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
         <data android:scheme="https" android:host="your.app.com" />
         <data android:scheme="http" android:host="your.app.com" />
    </intent-filter>
</activity>

深度链接路由

  • 加载特定的 URI Scheme 路径,例如
    • $deeplink_path="content/123"
    • $android_deeplink_path="content/123"
  • Recommend to use Navigate to content instead
<meta-data android:name="io.branch.sdk.auto_link_path" android:value="content/123/, another/path/, another/path/*" />

应用中的深度链接路由

  • 用于 WebView and ChromeTab within the app to render HTML normally
  • Branch links within the WebView will route internally within your app, while other contents will continue to route externally
  • 启动 Branch 深度链接 Web View
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    val webView = findViewById(R.id.webView) as WebView
    webView!!.webViewClient = BranchWebViewController("appname.app.link", MainActivity2::class.java)
    webView!!.loadUrl(URL_TO_LOAD)
}

inner class BranchWebViewController internal constructor(private val myDomain_: String, private val activityToLaunch_: Class<*>) : WebViewClient() {

    override fun onLoadResource(view: WebView, url: String) {
        super.onLoadResource(view, url)
    }

    override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {
        val url = request.url.toString()

        if (url.contains(myDomain_)) {
            val i = Intent(view.context, activityToLaunch_)
            i.putExtra("branch", url)
            i.putExtra("branch_force_new_session", true)
      //finish(); if launching same activity
            startActivity(i)
        } else {
            view.loadUrl(url)
        }

        return true
    }
}
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    WebView webView = (WebView) findViewById(R.id.webView);
    webView.setWebViewClient(new BranchWebViewController(YOUR_DOMAIN, MainActivity.class)); //YOUR_DOMAIN example: appname.app.link
    webView.loadUrl(URL_TO_LOAD);
}

public class BranchWebViewController extends WebViewClient {

    private String myDomain_;
    private Class activityToLaunch_;

    BranchWebViewController(@NonNull String myDomain, Class activityToLaunch) {
        myDomain_ = myDomain;
        activityToLaunch_ = activityToLaunch;
    }

    @Override
    public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
        String url = request.getUrl().toString();

        if (url.contains(myDomain_)) {
            Intent i = new Intent(view.getContext(), activityToLaunch_);
            i.putExtra("branch", url);
            i.putExtra("branch_force_new_session", true);
            startActivity(i);
            //finish(); if launching same activity
        } else {
            view.loadUrl(url);
        }

        return true;
  • 启动 Branch 深度链接 Chrome Tabs
val builder = CustomTabsIntent.Builder()
val customTabsIntent = builder.build()
customTabsIntent.intent.putExtra("branch", BRANCH_LINK_TO_LOAD)
customTabsIntent.intent.putExtra("branch_force_new_session", true)
customTabsIntent.launchUrl([email protected], Uri.parse(BRANCH_LINK_TO_LOAD))
//finish() if launching same activity
CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
CustomTabsIntent customTabsIntent = builder.build();
customTabsIntent.intent.putExtra("branch", BRANCH_LINK_TO_LOAD);
customTabsIntent.intent.putExtra("branch_force_new_session", true);
customTabsIntent.launchUrl(MainActivity.this, Uri.parse(BRANCH_LINK_TO_LOAD));
//finish(); if launching same activity

深度链接 Activity 完成

  • 在深度链接 activity 结束时收到通知
<meta-data android:name="io.branch.sdk.auto_link_request_code" android:value="@integer/AutoDeeplinkRequestCode" />
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)

    // Checking if the previous activity is launched on branch Auto deep link.
    if (requestCode == resources.getInteger(R.integer.AutoDeeplinkRequestCode)) {
        //Decide here where  to navigate  when an auto deep linked activity finishes.
        //For e.g. Go to HomeActivity or a  SignUp Activity.
        val i = Intent(applicationContext, CreditHistoryActivity::class.java)
        startActivity(i)
    }
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    // Checking if the previous activity is launched on branch Auto deep link.
    if(requestCode == getResources().getInteger(R.integer.AutoDeeplinkRequestCode)){
        //Decide here where  to navigate  when an auto deep linked activity finishes.
        //For e.g. Go to HomeActivity or a  SignUp Activity.
        Intent i = new Intent(getApplicationContext(), CreditHistoryActivity.class);
        startActivity(i);
    }
}

测试 Branch Link 的深度链接路由

Append ?bnc_validate=true to any of your app's Branch links and click it on your mobile device (not the Simulator!) to start the test.

For instance, to validate a link like: "https://<yourapp\>.app.link/NdJ6nFzRbK" click on: "https://<yourapp\>.app.link/NdJ6nFzRbK?bnc_validate=true"

Pre Android API 15 Support

  • 使用 Branch SDK 1.14.5
  • Add to onStart() and onStop()
override fun onStart() {
    super.onStart()
    Branch.getInstance().initSession()
}

override fun onStop() {
    super.onStop()
    Branch.getInstance().closeSession()
}
@Override
protected void onStart() {
    super.onStart();
    Branch.getInstance(getApplicationContext()).initSession();
}

@Override
protected void onStop() {
    super.onStop();
    branch.closeSession();
}

使用默认的 application class

  • 如果您的应用没有 application class
<application android:name="io.branch.referral.BranchApp">

生成签名证书

  • 用于 Android App Link 深度链接
  • 前往密钥库文件
  • 运行 keytool -list -v -keystore my-release-key.keystore
  • 将生成如下的值: AA:C9:D9:A5:E9:76:3E:51:1B:FB:35:00:06:9B:56:AC:FB:A6:28:CE:F3:D6:65:38:18:E3:9C:63:94:FB:D2:C1
  • Copy this value to your Branch Dashboard

通过 Install Listener 进行匹配

  • Enable the ability to pass link_click_id from Google Play to Branch
  • 这将增加归因以及延迟深度链接的准确性
  • Branch default is 1.5 seconds to wait for Google Play analytics
  • You can optimize the performance based on needs (e.g. 0500010000
  • Add to your application class before getAutoInstance (Load Branch
Branch.setPlayStoreReferrerCheckTimeout(5_000)
Branch.setPlayStoreReferrerCheckTimeout(5000);
  • 测试
adb shell am broadcast -a com.android.vending.INSTALL_REFERRER -n io.branch.androidexampledemo/io.branch.referral.InstallListener --es "referrer" "link_click_id=123"

启用 Multidexing

  • Adding additional dependencies may overrun the dex limit and lead to NoClassDefFoundError or ClassNotFoundException
  • 添加到 build.gradle
defaultConfig {
    multiDexEnabled true
}
  • 添加到 Application class and make sure it extends MultiDexApplication
override fun attachBaseContext(base: Context?) {
    super.attachBaseContext(base)
    MultiDex.install(this)
}
@Override
protected void attachBaseContext(Context base) {
    super.attachBaseContext(base);
    MultiDex.install(this);
}

InvalidClassException,ClassLoadingError 或 VerificationError

  • Often caused by a Proguard bug. Try the latest Proguard version or disable Proguard optimization by setting -dontoptimize

Answers-shim 模块的 Proguard 警告或错误

  • Often caused when you exclude the answers-shim. Try adding -dontwarn com.crashlytics.android.answers.shim.** to your Proguard file

AppIndexing 模块的 Proguard 警告或错误

  • Branch SDK 对 Firebase App Indexing 具有可选的依赖性,以提供新的 Firebase 内容列表功能。根据您的 proguard 设置,这可能会导致 proguard 警告。请将以下内容添加到您的 proguard 文件中以解决此问题: -dontwarn com.google.firebase.appindexing.

没有 Play Services Ads 模块的 Proguard 规则

  • Branch SDK 对Play Services Ads 的 GAID 匹配具有可选的依赖性。当创建 Branch 会话和事件时,不使用此库而使用 Proguard 可能会在获取 GAID 时产生问题。

请将以下内容添加到您的 proguard 文件中以解决此问题:

-keep class com.google.android.gms.ads.identifier.AdvertisingIdClient {
com.google.android.gms.ads.identifier.AdvertisingIdClient$Info getAdvertisingIdInfo(android.content.Context);
}

-keep class com.google.android.gms.ads.identifier.AdvertisingIdClient$Info {
java.lang.String getId();
boolean isLimitAdTrackingEnabled();
}

无法打开链接错误

  • URI scheme 重定向失败时发生。
  • Make sure you do not have $deeplink_path or you have a $deeplink_path which your AndroidManifest.xml can accept

卡在 initState_ == SESSION_STATE.INITIALISING

  • 通常是由于 Branch 没有从您的活动中获得正确的应用上下文而引起的。要解决此问题,请在访问 Branch 实例时传递单例类:
Branch.getInstance(getApplicationContext());

Handle the Error - BranchError.ERR_BRANCH_ALREADY_INITIALIZED

Why do you see the error?

The Branch Android SDK will automatically initialize when the app comes to the foreground, and the first activity to show enters the RESUMED lifecycle state. This is done as a failsafe not to miss tracking sessions.

Therefore, if you

  • Delay or never attempt to initialize, or
  • Have the app open to activities other than the launcher activity (where you attempt to initialize the session)

The Branch SDK will automatically initialize.

What is the Branch SDK doing?
The SDK will automatically initialize under the above conditions. Then if the app's code later tries to initialize the SDK (again), the SDK will throw an error. This prevents initializing over and over again or other potentially unexpected states.

What can you do to handle the error?
If you want to delay initialization without having the SDK self-initialize, you can do so using this method: Branch.expectDelayedSessionInitialization()

Alternatively, you can ignore the error and add the following code snippet to your callback:

if(error.getErrorCode() == BranchError.ERR_BRANCH_ALREADY_INITIALIZED) {
   branchReferringParams_ = Branch.getLatestReferringParams();
}

最低版本

如果您想在 Android 上支持 API 版本9,请固定到1.14.5版本。如果您想支持 API 级别15,请固定到2.x版本。我们支持3.x的最低版本是 Android 版本16。


后续步骤推荐