React Native 接入
这页只说明 React Native 的差异。先按浏览器应用接入完成 xapiforge.config.ts 和客户端生成,初始化时再换成 React Native TokenStore。
1. 安装依赖
使用系统 Keychain / Keystore:
bash
pnpm add @xapiforge/core @xapiforge/adapter-react-native react-native-keychain
pnpm add -D @xapiforge/genapiencryptedStorageStore 只用于兼容已经依赖 react-native-encrypted-storage 的旧项目。它的上游仓库已经归档,新项目优先使用 react-native-keychain:
bash
pnpm add @xapiforge/core @xapiforge/adapter-react-native react-native-encrypted-storage
pnpm add -D @xapiforge/genapi参考:react-native-keychain 文档、react-native-encrypted-storage 归档仓库。安装后按 React Native 项目的原生依赖流程重新安装 Pods 或重新构建应用。
2. 初始化生成客户端
以下代码使用两个 Keychain service,分别保存 access token 和 refresh token:
typescript
// src/api-client.ts
import { keychainStore } from "@xapiforge/adapter-react-native";
import { AuthService } from "@xapiforge/core";
import { createMyappClient } from "./api/gen/myapp/index.js";
const BASE_URL = "https://api.example.com";
const accessTokenStore = keychainStore({ service: "myapp.access-token" });
const refreshTokenStore = keychainStore({ service: "myapp.refresh-token" });
interface RefreshResponse {
access_token: string;
refresh_token?: string;
}
const authService = new AuthService({
tokenStore: accessTokenStore,
authRefresher: {
async refresh() {
const refreshToken = await refreshTokenStore.get();
if (!refreshToken) throw new Error("refresh token is missing");
const response = await fetch(`${BASE_URL}/oauth/token`, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
grant_type: "refresh_token",
refresh_token: refreshToken
}).toString()
});
if (!response.ok) throw new Error(`refresh failed: HTTP ${response.status}`);
const token = (await response.json()) as RefreshResponse;
if (token.refresh_token) await refreshTokenStore.set(token.refresh_token);
return token.access_token;
}
},
onAuthFailed() {
// 通过应用自己的 navigation ref 返回登录页。
}
});
export const api = createMyappClient({
baseURL: BASE_URL,
authService
});刷新端点、字段名和请求格式必须按实际后端修改。登录成功后,把两个 Token 分别写入对应的 store。
旧项目使用 encryptedStorageStore("myapp.access-token") 时,其他初始化代码不变;迁移计划应由应用维护者决定。
3. 在页面中调用
tsx
import { useEffect, useState } from "react";
import { Text, View } from "react-native";
import { api } from "../api-client";
export function HealthScreen() {
const [result, setResult] = useState("loading");
useEffect(() => {
api.base
.GET("/api/health")
.then(({ data }) => setResult(JSON.stringify(data)))
.catch(error => setResult(error instanceof Error ? error.message : String(error)));
}, []);
return (
<View>
<Text>{result}</Text>
</View>
);
}base 和 /api/health 来自示例配置。接入真实项目时,编辑器会根据生成类型提示可用 service 和 path。
需要注意
- React Native 提供全局
fetch,一般无需额外注入。老版本或需要流式响应时,再评估 fetch polyfill。 - 不要用同一个 Keychain service 同时保存 access token 和 refresh token,后写入的值会覆盖前一个。
- 大文件下载由应用选择
react-native-fs、Expo FileSystem 等原生方案;adapter-react-native当前只负责 TokenStore。 - 原生依赖变更必须在 iOS 和 Android 上分别验证,单独通过 TypeScript 编译不代表原生链接成功。