---
title: "sdk/android"
description: "适用于 Android 的 Kotlin SDK，使用 Chrome Custom Tabs、PKCE S256 授权码流程和 Keystore 支持的 EncryptedSharedPreferences token 存储。"
locale: "zh-Hans"
---

> Documentation Index
> Fetch the locale documentation index at: https://xid.dev/zh-hans/llms.txt
> Use this file to discover all available pages before exploring further.

# sdk/android

## 状态

包状态为 **已实现 · 本地已验证**。JVM 单元测试（24 个通过）覆盖 PKCE 生成、OAuth state 和内存存储。EncryptedSharedPreferences（Keystore AES-256-GCM）、Chrome Custom Tabs 和 App Links 行为需要真实 Android 设备或模拟器验证。IdP 往返验证待人工核实。本页面记录已实现的行为，不代表生产就绪声明。

## 要求

- Android API 26+（Android 8.0）
- Kotlin 1.9+ 和 AndroidX

## 安装

在应用模块的 build.gradle.kts 中添加依赖：

```kotlin
dependencies {
implementation("dev.xid:xid-android:0.1.0-alpha")
}

// Local development: add to settings.gradle.kts
includeBuild("../sdk/android")
```

## 清单配置

注册带 intent-filter 的 callback Activity。生产环境推荐使用 App Links（带 autoVerify 的 HTTPS scheme）而非自定义 scheme：

```xml
<!-- AndroidManifest.xml -->
<activity android:name=".AuthCallbackActivity" android:exported="true">
<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="yourapp.example.com"
          android:pathPrefix="/auth/callback" />
</intent-filter>
</activity>
```

## 快速开始

```kotlin
import dev.xid.sdk.Xid
import dev.xid.sdk.model.XidConfig

// 1. Initialize in Application.onCreate
Xid.configure(
context = this,
config = XidConfig(
    issuer = "https://xid.dev",
    clientId = "your_client_id",
    redirectUri = "https://yourapp.example.com/auth/callback",
    scopes = listOf("openid", "profile", "email", "offline_access"),
)
)

// 2. Sign in (opens Chrome Custom Tabs)
lifecycleScope.launch { Xid.signIn(requireContext()) }

// 3. Handle redirect in AuthCallbackActivity
val session = Xid.handleRedirect(intent.data.toString())

// 4. Get current session (auto-refreshes near expiry)
val session = Xid.getSession()

// 5. Get access token
val token = Xid.getAccessToken()

// 6. Sign out
Xid.signOut(context = this, openEndSession = true)
```

## 核心 API

| 方式 | 签名 |
| --- | --- |
| `configure` | `fun configure(context: Context, config: XidConfig)` |
| `signIn` | `suspend fun signIn(context: Context, options: SignInOptions? = null)` |
| `handleRedirect` | `suspend fun handleRedirect(url: String): XidSession` |
| `getSession` | `suspend fun getSession(): XidSession?` |
| `getAccessToken` | `suspend fun getAccessToken(options: GetAccessTokenOptions? = null): String` |
| `signOut` | `suspend fun signOut(context: Context? = null, openEndSession: Boolean = false)` |
| `setTokenStorage` | `fun setTokenStorage(adapter: TokenStorageAdapter)` |

## 错误类型

所有 SDK 错误均为 sealed class XidException 的子类型：

| 子类 | 触发 |
| --- | --- |
| `NotConfigured` | configure() 未被调用 |
| `UserCancelled` | 用户在未完成时关闭了 Custom Tabs |
| `StateMismatch` | OAuth state 不匹配——可能存在 CSRF |
| `TokenExchangeFailed` | Token 端点返回了错误 |
| `TokenRefreshFailed` | refresh token 已过期或被吊销 |
| `NoSession` | 在已登出状态下调用会话方法 |

## 安全

- 公共客户端——不存储或传输客户端密钥。
- 仅 PKCE S256。服务器拒绝 plain challenge 方式。
- 由 Android Keystore（AES-256-GCM）支持的 EncryptedSharedPreferences 保护静态 token 存储。
- 每次请求生成随机 OAuth state；在重定向时验证以防 CSRF。

## 已知限制

- 基于 JWKS 的 ID token 验签已实现并完成本地单元测试。Android 设备或模拟器和真实 IdP 验证前仍不具备 L4 支持。
- 没有机制检测用户在未完成授权时关闭 Custom Tabs。
- 仅支持单账户——存储层使用固定密钥。

Source: https://xid.dev/zh-hans/sdks/android/index.mdx
