---
title: "@xid-kit/expo"
description: "适用于 @xid-kit/react-native 的 Expo SecureStore 和 WebBrowser 适配器，以及 Expo Router 路由守卫 hook。"
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.

# @xid-kit/expo

## 状态

包状态为 **当前包**。Expo SecureStore 和 WebBrowser 适配器、XidProvider 及 Expo Router 路由守卫 hook 已实现。在真实生产基础设施上的 IdP 往返验证仍待人工核实。

所有 PKCE 逻辑、token 交换和会话管理均在 [@xid-kit/react-native](/zh-hans/sdks/react-native) 中；此包仅提供适配器和 Expo Router 集成。

## Provider 配置

将 `createSecureStoreAdapter` 和 `createExpoWebBrowserAdapter` 注入 `XidProvider`。无需顶层 Expo 模块导入；适配器接受模块实例，因此即使未安装 Expo peer 依赖，CI 类型检查也能保持干净。

```tsx
import * as SecureStore from 'expo-secure-store'
import * as WebBrowser from 'expo-web-browser'
import { XidProvider, createSecureStoreAdapter, createExpoWebBrowserAdapter } from '@xid-kit/expo'

const tokenCache = createSecureStoreAdapter({ secureStore: SecureStore })
const browser = createExpoWebBrowserAdapter({ webBrowser: WebBrowser })

export default function App() {
  return (
<XidProvider
  publishableKey="pk_live_..."
  issuer="https://xid.dev"
  clientId="your_client_id"
  redirectUri="myapp://auth/callback"
  tokenCache={tokenCache}
  browser={browser}
>
  <RootLayout />
</XidProvider>
  )
}
```

## 登录与登出

```tsx
import { useSignIn, useSignOut } from '@xid-kit/expo'
import { Button } from 'react-native'

function SignInScreen() {
  const { signIn, signInState } = useSignIn()
  return (
<Button
  title={signInState.status === 'pending' ? 'Signing in...' : 'Sign In'}
  onPress={() => void signIn()}
/>
  )
}

function SignOutScreen() {
  const { signOut } = useSignOut()
  return <Button title="Sign Out" onPress={() => void signOut()} />
}
```

## Expo Router 路由守卫

在布局组件中调用 `useProtectedRoute`。它从 `useAuth` 读取 `isLoaded`/`isSignedIn`，并在 `useEffect` 内调用 Expo Router 的 `replace`。

```tsx
import { useProtectedRoute } from '@xid-kit/expo'
import { useRouter, usePathname } from 'expo-router'

export default function RootLayout() {
  const router = useRouter()
  const pathname = usePathname()

  useProtectedRoute({
signInRoute: '/sign-in',
protectedRoute: '/(app)',
pathname,
replace: router.replace,
  })

  return <Slot />
}
```

## SecureStore 密钥命名空间

使用 `keyPrefix` 为密钥添加自定义前缀命名空间。分隔符为 `.`（点号），在 `expo-secure-store` 允许的字符集范围内。

```ts
const tokenCache = createSecureStoreAdapter({
  secureStore: SecureStore,
  keyPrefix: 'myapp',
  // keys: 'myapp.xid.access_token', 'myapp.xid.refresh_token', etc.
})
```

## 导出的 API

| 导出 | 类型 | 用途 |
| --- | --- | --- |
| `XidProvider` | 组件 | 重导出接受 tokenCache 和浏览器适配器的 @xid-kit/react-native XidProvider |
| `createSecureStoreAdapter` | function | 由 expo-secure-store 支持的 TokenCache 适配器；接受 secureStore 实例和可选的 keyPrefix |
| `createExpoWebBrowserAdapter` | function | 由 expo-web-browser 支持的 BrowserInterface 适配器 |
| `useSignIn` | hook | 来自 @xid-kit/react-native 的重导出：signIn、handleRedirect、signInState |
| `useSignOut` | hook | 来自 @xid-kit/react-native 的重导出：signOut、signOutState |
| `useProtectedRoute` | hook | 读取 isLoaded/isSignedIn 并调用 Expo Router replace 进行路由保护 |

## 已知限制

- `useAuth().isSignedIn` 反映的是 `XidClient` Web cookie 会话状态，token 交换后不会自动从本地 SecureStore token 填充。登录成功后请显式重新加载客户端状态。
- 此包仅提供适配器和 Expo Router 集成。基础 React Native PKCE 流程请参见 [@xid-kit/react-native](/zh-hans/sdks/react-native)。

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