---
title: "sdk/flutter"
description: "适用于 iOS、Android 和桌面端的 Dart / Flutter SDK，使用 flutter_web_auth_2、PKCE S256 授权码流程和 flutter_secure_storage 进行 token 持久化。"
locale: "zh-Hans"
---

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

# sdk/flutter

## 状态

包状态为**已在本地实现并验证**。Dart 和 Flutter 单元测试套件已通过，覆盖 PKCE、nonce 和 ID token 验证、Guest 能力、session 过期及存储契约。Platform channel 路径和真实 IdP 往返仍需设备或模拟器。本页记录的是已实现行为，不代表已具备生产就绪状态。

Registry 状态:UNPUBLISHED。此 SDK 只能从仓库源码 checkout 安装；不要使用外部 package registry。

## 安装

添加到 pubspec.yaml 并运行 flutter pub get：

```yaml
# pubspec.yaml
dependencies:
  vonvon:
git:
  url: https://github.com/StringKe/vonvon
  path: sdk/flutter
  ref: main
```

## 平台配置

在每个平台上注册 callback URI scheme。

```xml
<!-- Android: AndroidManifest.xml (main Activity) -->
<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="com.example.myapp" android:host="auth" />
</intent-filter>

<!-- iOS: Info.plist -->
<key>CFBundleURLTypes</key>
<array>
  <dict>
<key>CFBundleURLSchemes</key>
<array><string>com.example.myapp</string></array>
  </dict>
</array>
```

## 快速开始

```dart
import 'package:vonvon/vonvon.dart';

final client = VonvonClient();

// 1. Initialize (fetches OIDC discovery). offline_access is rejected until DPoP is implemented.
await client.configure(
  const VonvonOptions(
issuer: 'https://vonvon.id',
clientId: 'YOUR_CLIENT_ID',
redirectUri: 'com.example.myapp://auth/callback',
scopes: ['openid', 'profile', 'email'],
  ),
);

// 2. Sign in (opens system browser, PKCE S256)
final session = await client.signIn();
print(session.user.email);

// 3. Get the current unexpired access token. Expiry requires reauthorization.
final token = await client.getAccessToken();

// 4. Get the current unexpired session.
final current = await client.getSession();

// 5. Clear secure storage and optionally open end_session. No revoke request is sent.
await client.signOut();
```

## 核心 API

| 方式 | 描述 |
| --- | --- |
| `configure(VonvonOptions, {storageAdapter?})` | 初始化 SDK 并获取 OIDC discovery。必须在所有其他方法之前调用。 |
| `signIn({}additionalParameters?, audience?})` | 以 PKCE S256 授权 URL 打开系统浏览器；交换 code 并返回 VonvonSession。 |
| `handleRedirect(String url)` | 处理 App Link 或自定义 scheme callback。由 signIn 内部调用；跨进程重定向恢复时手动调用。 |
| `getSession()` | 返回当前未过期的 VonvonSession；如果已过期，则清除本地状态并返回 null。 |
| `getAccessToken({}bool forceRefresh})` | 返回当前未过期的 access token。forceRefresh: true 会清除会话并要求重新授权。 |
| `signOut({}bool openLogoutUrl})` | 清除 secure storage，并可选择在系统浏览器中打开 end\_session\_endpoint；不会发送 revoke request。 |
| `setTokenStorage(TokenStorageAdapter)` | 用自定义实现替换默认的 SecureStorageAdapter（flutter\_secure\_storage）。 |

## 依赖项

| 包 | 版本 | 用途 |
| --- | --- | --- |
| `flutter_web_auth_2` | ^4.0.0 | 系统浏览器授权会话和 callback 接收 |
| `flutter_secure_storage` | ^9.2.4 | 平台安全存储（Keychain / Keystore / DPAPI） |
| `crypto` | ^3.0.3 | 用于 PKCE S256 challenge 计算的 SHA-256 |
| `http` | ^1.2.2 | 用于 discovery 和 token 端点的 HTTP 客户端 |

## 安全

- 公共客户端——不存储或传输客户端密钥。
- 仅 PKCE S256。不支持 implicit 流程或 password grant。
- 每次请求生成 OAuth state；在 handleRedirect 中验证以防 CSRF。
- 新会话将 access token 和 ID token 存入平台 secure storage。refreshToken compatibility field 保持为 null，并且在实现 DPoP 之前会拒绝 offline\_access。

## 已知限制

- 已实现并在本地测试基于 JWKS 的 ES256 ID token 验证、nonce 验证和持久化的 state-keyed PKCE。在达到 L4 支持之前，仍需完成真实设备和 IdP 验证。
- 在 SDK 实现 DPoP sender binding 之前会拒绝 offline\_access；access-token 到期后需要重新授权。

Source: https://vonvon.id/zh-hans/sdks/flutter/index.mdx
