使用文员
学习如何在你的 Expo 和 React Native 项目中添加 Clerk 身份验证和用户管理。
For the complete documentation index, see llms.txt. Use this file to discover all available pages.
Clerk 是一个身份验证和用户管理平台,提供注册、登录、多因素身份验证、社交登录、组织管理以及托管用户数据库。@clerk/expo SDK 为你提供 React 钩子、控制组件以及预构建的原生 UI 组件,这些组件可以在 Android 上使用 Jetpack Compose,在 iOS 上使用 SwiftUI 渲染。
本指南向你展示如何安装 @clerk/expo、将你的应用封装在 <ClerkProvider> 中,以及选择适合你项目的集成方式。它针对 @clerk/expo Core 3(3.x 版本系列),支持 Expo SDK 53、54 和 55。
🌐 This guide shows you how to install @clerk/expo, wrap your app in <ClerkProvider>, and choose the integration approach that fits your project. It targets @clerk/expo Core 3 (the 3.x release line), which supports Expo SDK 53, 54, and 55.
选择你的整合方法
🌐 Choose your integration approach
@clerk/expo 支持三种方法。选择最符合你需求的一种 —— 以后可以更改,无需重写你的应用。
| 方法 | 你构建的内容 | 在 Expo Go 中运行 | 最适合 |
|---|---|---|---|
| 仅 JavaScript | 你自己的 React Native 屏幕,调用 useSignIn() 和 useSignUp() | 最大化 UI 控制,在 Expo Go 中进行原型设计 | |
| 使用原生登录的 JavaScript | 你自己的屏幕加上原生的 Google 登录和 Apple 登录按钮 | 想要自定义外观但使用原生社交登录的应用 | |
| 原生 UI 组件 | 从 @clerk/expo/native 中直接使用 <AuthView />、<UserButton /> 和 <UserProfileView /> | 最快实现完整登录和账户管理 UI 的路径 |
信息
@clerk/expo/native中的原生 UI 组件目前处于测试阶段。它们在 Android 上使用 Jetpack Compose 渲染,在 iOS 上使用 SwiftUI 渲染,并将登录会话同步回 JavaScript SDK,因此所有@clerk/expo钩子(例如useAuth()和useUser())都保持同步。
先决条件
🌐 Prerequisites
4 requirements
4 requirements
1.
在Clerk Dashboard注册并创建一个应用。
2.
在Clerk Dashboard中打开本地应用页面,并确保启用Native API。这是任何使用@clerk/expo的Expo集成所必需的。
3.
@clerk/expo Core 3 有一个expo: >=53 <56的同伴依赖。
4.
本地登录和本地UI组件方法需要开发构建。仅使用JavaScript的方法也适用于Expo Go。
安装并配置 Clerk
🌐 Install and configure Clerk
1
安装 @clerk/expo 和 expo-secure-store
🌐 Install @clerk/expo and expo-secure-store
使用 npx expo install 以使版本与你的 Expo SDK 匹配:
🌐 Use npx expo install so versions match your Expo SDK:
- npx expo install @clerk/expo expo-secure-storeexpo-secure-store 是一个同级依赖。Clerk 通过 @clerk/expo/token-cache 使用它来使用 iOS 密钥串和 Android 密钥库加密会话令牌。
如果你计划使用原生的使用 Google 登录功能,也请安装 expo-crypto:
🌐 If you plan to use native Sign in with Google, also install expo-crypto:
- npx expo install expo-crypto对于原生的使用 Apple 登录,请同时安装 expo-apple-authentication 和 expo-crypto:
🌐 For native Sign in with Apple, install both expo-apple-authentication and expo-crypto:
- npx expo install expo-apple-authentication expo-crypto如果你只使用 @clerk/expo/native 中的 <AuthView />,你不需要任何这些额外的包,因为该组件会在内部处理社交登录流程。
🌐 You do not need any of these extra packages if you only use <AuthView /> from @clerk/expo/native, since the component handles social sign-in flows internally.
2
添加 Clerk 配置插件
🌐 Add the Clerk config plugin
在你的 应用配置 中将 @clerk/expo 添加到 plugins 数组:
🌐 Add @clerk/expo to the plugins array in your app config:
{ "expo": { "plugins": ["@clerk/expo"] } }
该插件配置 iOS URL 方案以支持原生使用 Google 登录(当 EXPO_PUBLIC_CLERK_GOOGLE_IOS_URL_SCHEME 被设置时),并应用由底层 clerk-android SDK 所需的 Android 打包修复。该插件会从 expo-apple-authentication 库中添加 Apple 登录权限,如果你安装了它。
🌐 The plugin configures the iOS URL scheme for native Sign in with Google (when EXPO_PUBLIC_CLERK_GOOGLE_IOS_URL_SCHEME is set) and applies the Android packaging fixes required by the underlying clerk-android SDK. The Apple Sign In entitlement is added by the plugin from expo-apple-authentication library, if you install it.
3
添加你的 Clerk 可发布密钥
🌐 Add your Clerk Publishable Key
从 Clerk 仪表板的 API keys 页面复制你的可发布密钥,然后将其添加到项目根目录下的 .env 文件中:
🌐 Copy your Publishable Key from the API keys page in the Clerk Dashboard, then add it to a .env file in the root of your project:
EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_your-key-here
EXPO_PUBLIC_ 前缀是必需的,因为 Expo 会在构建时内联这些值,以便它们可以在你的 JavaScript 包中使用。Clerk 的可发布密钥是可以安全公开的。不要 将密钥放在 EXPO_PUBLIC_ 前缀下。
🌐 The EXPO_PUBLIC_ prefix is required because Expo inlines these values at build time so they are available in your JavaScript bundle. Clerk's Publishable Key is safe to expose. Do not put Secret Keys behind the EXPO_PUBLIC_ prefix.
4
将你的应用封装在 <ClerkProvider> 中
🌐 Wrap your app in <ClerkProvider>
在你的根布局文件(使用 Expo Router 的 src/app/_layout.tsx)中,将你的应用封装在 <ClerkProvider> 中并传入 Publishable Key。建议显式传入 tokenCache:
🌐 In your root layout file (src/app/_layout.tsx with Expo Router), wrap your app in <ClerkProvider> and pass the Publishable Key. Passing tokenCache explicitly is recommended:
import { ClerkProvider } from '@clerk/expo'; import { tokenCache } from '@clerk/expo/token-cache'; import { Slot } from 'expo-router'; const publishableKey = process.env.EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY!; if (!publishableKey) { throw new Error('Add your Clerk Publishable Key to the .env file'); } export default function RootLayout() { return ( <ClerkProvider publishableKey={publishableKey} tokenCache={tokenCache}> <Slot /> </ClerkProvider> ); }
在 Core 3 中,对于 Expo 应用,<ClerkProvider> 上需要 publishableKey。在生产环境的 React Native 构建中,node_modules 内的环境变量不会被内联,因此必须明确传递该属性。
🌐 In Core 3, publishableKey is required on <ClerkProvider> for Expo apps. Environment variables inside node_modules are not inlined during production React Native builds, so the prop must be passed explicitly.
@clerk/expo/token-cache 的 tokenCache 使用 expo-secure-store 在应用重启时保持用户会话。显式传递它可以使依赖更加清晰,并允许你以后替换自定义缓存实现。
构建你的登录屏幕
🌐 Build your sign-in screen
下一步取决于你选择了哪种方法。下面的选项卡显示了每种方法的最少代码。
🌐 The next step depends on which approach you chose. The tabs below show the minimum code for each.
将 <AuthView /> 放入一个屏幕中。它渲染一个完整的原生登录和注册界面,处理电子邮件、电话、密码密钥、多因素身份验证,以及 Clerk 仪表板中启用的任何社交连接:
🌐 Drop <AuthView /> into a screen. It renders a complete native sign-in and sign-up interface that handles email, phone, passkeys, multi-factor authentication, and any social connection enabled in the Clerk Dashboard:
import { AuthView } from '@clerk/expo/native'; import { useAuth } from '@clerk/expo'; import { useRouter } from 'expo-router'; import { useEffect } from 'react'; export default function SignInScreen() { const { isSignedIn } = useAuth({ treatPendingAsSignedOut: false }); const router = useRouter(); useEffect(() => { if (isSignedIn) { router.replace('/(home)'); } }, [isSignedIn]); return <AuthView mode="signInOrUp" />; }
用户登录后,本地会话会同步回 JavaScript SDK,因此 useAuth() 和 useUser() 会反映已登录状态。将 treatPendingAsSignedOut: false 传递给 useAuth(),以防简短的本地到 JS 会话同步被报告为未登录状态,否则可能会在以 isSignedIn 为导航关键的页面上导致重定向循环。
🌐 After the user signs in, the native session is synchronized back to the JavaScript SDK, so useAuth() and useUser() reflect the signed-in state. Pass treatPendingAsSignedOut: false to useAuth() so the brief native-to-JS session sync isn't reported as a signed-out state, which can otherwise cause redirect loops on screens that key navigation off isSignedIn.
<AuthView /> 接受 mode="signIn" | "signUp" | "signInOrUp" 和一个可选的 isDismissable 布尔值。
要在应用的其他地方显示用户的头像和个人资料模态框,请使用 <UserButton />:
🌐 To show the user's avatar and a profile modal elsewhere in your app, use <UserButton />:
import { UserButton } from '@clerk/expo/native'; import { Show } from '@clerk/expo'; import { View } from 'react-native'; export function Header() { return ( <Show when="signed-in"> <View style={{ width: 36, height: 36, borderRadius: 18, overflow: 'hidden' }}> <UserButton /> </View> </Show> ); }
<UserButton /> 填满其父元素,因此父元素控制大小和形状。要从任何其他界面打开原生个人资料模态框,请使用 useUserProfileModal() 钩子:
import { useUserProfileModal } from '@clerk/expo'; import { Pressable, Text } from 'react-native'; export function ProfileLink() { const { presentUserProfile, isAvailable } = useUserProfileModal(); return ( <Pressable onPress={presentUserProfile} disabled={!isAvailable}> <Text>Manage profile</Text> </Pressable> ); }
这种方法需要开发构建,因为这些组件由原生模块支持:
🌐 This approach requires a development build because the components are backed by native modules:
# Run a development build locally- npx expo run:android- npx expo run:ios# Or build with EAS- eas build --platform ios --profile development将 useSignInWithGoogle() 和 useSignInWithApple() 钩子与你自己的 React Native UI 一起使用:
🌐 Use the useSignInWithGoogle() and useSignInWithApple() hooks alongside your own React Native UI:
import { useSignInWithGoogle } from '@clerk/expo/google'; import { useRouter } from 'expo-router'; import { Platform, Text, TouchableOpacity } from 'react-native'; export function GoogleSignInButton() { const { startGoogleAuthenticationFlow } = useSignInWithGoogle(); const router = useRouter(); if (Platform.OS !== 'ios' && Platform.OS !== 'android') return null; const onPress = async () => { try { const { createdSessionId, setActive } = await startGoogleAuthenticationFlow(); if (createdSessionId && setActive) { await setActive({ session: createdSessionId }); router.replace('/'); } } catch (err) { console.error('Google sign-in error', err); } }; return ( <TouchableOpacity onPress={onPress}> <Text>Continue with Google</Text> </TouchableOpacity> ); }
在 Android 上,这会使用凭证管理器,并且从不打开浏览器。在 iOS 上,当配置了 EXPO_PUBLIC_CLERK_GOOGLE_IOS_URL_SCHEME 时,该流程会使用 ASAuthorization(系统凭证选择器)——如果未配置,则 iOS 会回退到系统浏览器页。请按照本页底部链接的 Clerk 指南,在 Clerk 仪表板和 Google Cloud 控制台中注册你的 Android 包名、iOS 包 ID 以及 SHA-256 指纹。
🌐 On Android, this uses Credential Manager and never opens a browser. On iOS, the flow uses ASAuthorization (the system credential picker) when EXPO_PUBLIC_CLERK_GOOGLE_IOS_URL_SCHEME is configured — without it, iOS falls back to a system browser sheet. Follow the Clerk guides linked at the bottom of this page to register your Android package name, iOS bundle ID, and SHA-256 fingerprints in the Clerk Dashboard and the Google Cloud Console.
@clerk/expo/apple 的 useSignInWithApple() 遵循相同的模式(startAppleAuthenticationFlow() 返回 { createdSessionId, setActive }),并且仅限 iOS。App Store 指南 4.8 要求,任何提供第三方社交登录的应用在 iOS 上也必须提供使用 Apple 登录的选项。
这种方法需要开发版本,因为它使用原生模块。useSignInWithGoogle() 需要 expo-crypto。useSignInWithApple() 需要 expo-apple-authentication 和 expo-crypto。
🌐 This approach requires a development build because it uses native modules. useSignInWithGoogle() requires expo-crypto. The useSignInWithApple() requires both expo-apple-authentication and expo-crypto.
使用 Core 3 钩子构建自定义登录表单。这在 Expo Go 中可用。
🌐 Build a custom sign-in form using the Core 3 hooks. This works in Expo Go.
import { useSignIn } from '@clerk/expo'; import { useRouter, type Href } from 'expo-router'; import { useState } from 'react'; import { Text, TextInput, TouchableOpacity, View } from 'react-native'; export default function SignInScreen() { const { signIn, fetchStatus, errors } = useSignIn(); const router = useRouter(); const [emailAddress, setEmailAddress] = useState(''); const [password, setPassword] = useState(''); const onSignInPress = async () => { const { error } = await signIn.password({ emailAddress, password }); if (error) { console.error(JSON.stringify(error, null, 2)); return; } if (signIn.status === 'complete') { await signIn.finalize({ navigate: ({ session, decorateUrl }) => { if (session?.currentTask) return; // let the session task layer handle it router.replace(decorateUrl('/') as Href); }, }); } }; return ( <View> <TextInput autoCapitalize="none" value={emailAddress} placeholder="Email" onChangeText={setEmailAddress} /> <TextInput value={password} placeholder="Password" secureTextEntry onChangeText={setPassword} /> <TouchableOpacity onPress={onSignInPress} disabled={fetchStatus === 'fetching'}> <Text>Sign in</Text> </TouchableOpacity> {errors?.fields?.identifier ? <Text>{errors.fields.identifier.message}</Text> : null} {errors?.fields?.password ? <Text>{errors.fields.password.message}</Text> : null} </View> ); }
在 Core 3 中,signIn.password() 在验证错误时返回 { error } 而不是抛出异常,signIn.finalize() 则替代了用于使用 useSignIn() 构建的登录流程的旧有 setActive() 调用。
🌐 In Core 3, signIn.password() returns { error } instead of throwing for validation errors, and signIn.finalize() replaces the legacy setActive() call for sign-in flows built with useSignIn().
具有电子邮件验证的相应注册流程如下:
🌐 The corresponding sign-up flow with email verification looks like:
await signUp.password({ emailAddress, password }); await signUp.verifications.sendEmailCode(); // ... collect the code from the user, then: await signUp.verifications.verifyEmailCode({ code }); if (signUp.status === 'complete') { await signUp.finalize({ navigate: ({ session, decorateUrl }) => { if (session?.currentTask) return; router.replace(decorateUrl('/') as Href); }, }); }
Clerk 的机器人注册保护默认启用,因此在你的注册界面上某处包含 <View nativeID="clerk-captcha" />,这样隐形 CAPTCHA 就可以启动。
🌐 Clerk's bot sign-up protection is enabled by default, so include <View nativeID="clerk-captcha" /> somewhere in your sign-up screen so the invisible CAPTCHA can mount.
读取已登录的用户
🌐 Read the signed-in user
在你的应用中的任何地方,使用 useUser() 和 useAuth() 来读取用户数据,另外使用 <Show> 和 useClerk() 来保护内容并登出:
🌐 Anywhere in your app, use useUser() and useAuth() to read user data, plus <Show> and useClerk() to protect content and sign out:
import { Show, useClerk, useUser } from '@clerk/expo'; import { Link } from 'expo-router'; import { Pressable, Text, View } from 'react-native'; export default function HomeScreen() { const { user } = useUser(); const { signOut } = useClerk(); return ( <View> <Show when="signed-in"> <Text>Hello, {user?.firstName ?? 'friend'}</Text> <Pressable onPress={() => signOut()}> <Text>Sign out</Text> </Pressable> </Show> <Show when="signed-out"> <Link href="/(auth)/sign-in"> <Text>Sign in</Text> </Link> </Show> </View> ); }
<Show> 替代了早期版本 SDK 中的传统 <SignedIn>、<SignedOut> 和 <Protect> 组件。它还接受 when={{ role: '...' }}、when={{ permission: '...' }} 及其他授权谓词。
运行应用
🌐 Run the app
- npx expo run:android- npx expo run:ios对于仅使用 JavaScript 的方法,运行以下命令并在 Expo Go 中打开项目:
🌐 For the JavaScript-only approach, run the following command and open the project in Expo Go:
- npx expo start下一步
🌐 Next steps
为每种三种集成方法提供逐步设置说明,并附有 GitHub 上的配套仓库。
AuthView、UserButton 和 UserProfileView 的 API 参考,包括配置、主题和平台要求。
使用 ASAuthorization 和 Credential Manager 为 Android 和 iOS 设置原生的使用 Google 登录。
设置原生“使用 Apple 登录”以符合 App Store 指南 4.8。
在你的 Expo 应用中使用 Clerk 的 hooks 和 Show 组件来保护路由并访问用户数据。
配置生产凭证,允许列表移动单点登录重定向,并使用 EAS 构建发布。