状态
包状态为已在本地实现并验证。JVM 单元测试套件已通过,覆盖 PKCE、state 和 nonce 处理、Guest 能力及存储契约。EncryptedSharedPreferences、Chrome Custom Tabs、App Links 和真实 IdP 往返仍需设备或模拟器。本页记录的是已实现行为,不代表已具备生产就绪状态。
Registry 状态:UNPUBLISHED。此 SDK 只能从仓库源码 checkout 安装;不要使用外部 package registry。
要求
- Android API 26+(Android 8.0)
- Kotlin 1.9+ 和 AndroidX
安装
在应用模块的 build.gradle.kts 中添加依赖:
// settings.gradle.kts
includeBuild("../xid/sdk/android")
// app/build.gradle.kts
dependencies {
implementation("dev.xid:xid-android:0.1.0-alpha.0")
}清单配置
注册带 intent-filter 的 callback Activity。生产环境推荐使用 App Links(带 autoVerify 的 HTTPS scheme)而非自定义 scheme:
<!-- 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>快速开始
import dev.xid.sdk.Xid
import dev.xid.sdk.model.XidConfig
// 1. Initialize in Application.onCreate. offline_access is rejected until DPoP is implemented.
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"),
)
)
// 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. Read the current unexpired session. Expiry requires reauthorization.
val session = Xid.getSession()
// 5. Get the current unexpired access token.
val token = Xid.getAccessToken()
// 6. Clear local state and optionally open end_session.
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 端点返回了错误 |
TokenValidationFailed |
ID token signature 或 claims 验证失败 |
NoSession |
在已登出状态下调用会话方法 |
安全
- 公共客户端——不存储或传输客户端密钥。
- 仅 PKCE S256。服务器拒绝 plain challenge 方式。
- 由 Android Keystore(AES-256-GCM)支持的 EncryptedSharedPreferences 保护静态 token 存储。
- 每次请求生成随机 OAuth state;在重定向时验证以防 CSRF。
已知限制
- 基于 JWKS 的 ID token 验签已实现并完成本地单元测试。Android 设备或模拟器和真实 IdP 验证前仍不具备 L4 支持。
- 没有机制检测用户在未完成授权时关闭 Custom Tabs。
- 仅支持单账户——存储层使用固定密钥。