---
title: Android
description: 使用 Custom Tabs 将 Human Token Journey 集成到您的 Android 应用中 — 轻量、安全，无需 WebView。
canonical: https://developer.unico.io/zh-CN/human-token/integrations/app/android/link-integration
locale: zh-CN
generated_by: markdown-export
---

# Android

使用 Custom Tabs 将 Human Token Journey 集成到您的 Android 应用中。

Custom Tabs 在您应用内的浏览器标签页中启动 Human Token Journey。当旅程完成时，浏览器会重定向到您的自定义 URL scheme，您的应用会拦截它。

### 前提条件

- Android 8 (API 26) 或更高版本
- `androidx.browser:browser:1.5.0`
- 您应用的唯一 URL scheme（例如 `myapp`）

### 步骤 1: 添加依赖

在您的 `build.gradle`:

```groovy
implementation("androidx.browser:browser:1.5.0")
```

### 步骤 2: 定义 URL scheme

选择一个唯一的 scheme（例如 `myapp`）。创建流程时将其用作 `callbackUri`：

```
callbackUri: myapp://callback
```

### 步骤 3: 创建 Activity

```kotlin
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.browser.customtabs.CustomTabsIntent

class HumanTokenActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val url = intent.getStringExtra(EXTRA_PROCESS_URL) ?: return finish()

        CustomTabsIntent.Builder()
            .build()
            .launchUrl(this, Uri.parse(url))
    }

    override fun onNewIntent(intent: Intent) {
        super.onNewIntent(intent)
        intent.data?.let { uri ->
            if (uri.scheme == "myapp") {
                // Journey completed — send processId to your backend
                val processId = uri.getQueryParameter("id")
                handleResult(processId)
            }
        }
    }

    private fun handleResult(processId: String?) {
        // Fetch the result from your backend via Get Process
        finish()
    }

    companion object {
        const val EXTRA_PROCESS_URL = "process_url"
    }
}
```

### 步骤 4: 配置 AndroidManifest.xml

```xml
<uses-feature android:name="android.hardware.camera" android:required="false" />
<uses-permission android:name="android.permission.CAMERA" />

<activity
    android:name=".HumanTokenActivity"
    android:launchMode="singleTop"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="myapp" android:host="callback" />
    </intent-filter>
</activity>
```

`singleTop` 确保 Android 在现有 Activity 上调用 `onNewIntent()`，而不是创建新的。

### 步骤 5: 启动旅程

```kotlin
val intent = Intent(this, HumanTokenActivity::class.java)
    .putExtra(HumanTokenActivity.EXTRA_PROCESS_URL, processLink)
startActivity(intent)
```

### 文件概览

| 文件 | 用途 |
|---|---|
| `build.gradle` | `androidx.browser` 依赖 |
| `HumanTokenActivity.kt` | Custom Tabs 启动 + 重定向处理 |
| `AndroidManifest.xml` | URL scheme 的 Intent 过滤器 |

---

### 使用 WebView 代替 Custom Tabs

> **警告:** Custom Tabs 是推荐的方式。它更安全，原生处理重定向，且需要的配置更少。仅在项目中无法使用 Custom Tabs 时才使用 WebView。

如果您必须使用 `WebView`，journey 需要明确授予 JavaScript、DOM 存储、自动播放媒体以及摄像头/地理位置权限。如果没有这些设置，捕获框架将无法加载或摄像头将无法激活。

```kotlin
webView.settings.javaScriptEnabled = true
webView.settings.domStorageEnabled = true
webView.settings.mediaPlaybackRequiresUserGesture = false
webView.settings.setGeolocationEnabled(true)

webView.webChromeClient = object : WebChromeClient() {
    override fun onPermissionRequest(request: PermissionRequest) {
        if (PermissionRequest.RESOURCE_VIDEO_CAPTURE in request.resources) {
            request.grant(arrayOf(PermissionRequest.RESOURCE_VIDEO_CAPTURE))
        } else {
            request.deny()
        }
    }

    override fun onGeolocationPermissionsShowPrompt(
        origin: String,
        callback: GeolocationPermissions.Callback
    ) {
        callback.invoke(origin, true, false)
    }
}
```

您还必须在 `AndroidManifest.xml` 中声明 `CAMERA`、`INTERNET` 和 `ACCESS_FINE_LOCATION` 权限，并在加载旅程 URL 之前在运行时请求相机和位置权限。

```xml
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
```