797 lines
19 KiB
Markdown
797 lines
19 KiB
Markdown
# Client Proxy Framework 使用指南
|
||
|
||
## 1. 框架概述
|
||
|
||
`client_proxy_framework` 是一个通用代理 API 框架,用于 Flutter 移动应用与后端 API 的通信。框架已封装好请求/响应的加密解密、字段映射等逻辑,换皮应用只需配置少量参数即可使用。
|
||
|
||
### 核心特性
|
||
|
||
- **自动加解密**:请求体和响应体自动进行 AES 加密/解密
|
||
- **字段映射**:框架自动将原始字段名转换为 V2 字段名,响应自动转换回来
|
||
- **强类型实体**:返回强类型实体类,开发者直接使用映射后的字段
|
||
- **统一响应**:`EntityResponse<T>` 提供强类型返回值
|
||
|
||
### 换皮应用:从零搭建
|
||
|
||
从零创建一个新的换皮应用(`skin_config.json`、`ClientBootstrap`、`main` 初始化顺序、Android/iOS 要点等),请阅读 **[《创建新换皮应用 — 步骤清单》](create_new_skin_app.md)**。
|
||
|
||
### 功能总览与用法
|
||
|
||
按模块整理的“功能 + 最小调用示例”请见 **[《Framework 功能与用法总览》](framework_feature_usage.md)**。
|
||
|
||
以首款换皮应用 **FunyMee** 为参考的 **视频首页**(`common_info` → 分类 → 按分类拉模板)数据流说明,见 **[《视频首页数据获取流程》](video_home_data_flow.md)**。
|
||
|
||
示例换皮配置文件 [`lib/src/config/skin_config.example.json`](../lib/src/config/skin_config.example.json) 的字段说明,见 **[《skin_config.example.json 字段说明》](skin_config_example.md)**。
|
||
|
||
---
|
||
|
||
## 2. 快速开始
|
||
|
||
### 2.1 添加依赖
|
||
|
||
在 `pubspec.yaml` 中添加:
|
||
|
||
```yaml
|
||
dependencies:
|
||
client_proxy_framework:
|
||
path: ../client_proxy_framework
|
||
```
|
||
|
||
### 2.2 实现配置
|
||
|
||
创建一个类继承 `AppConfig`:
|
||
|
||
```dart
|
||
import 'package:client_proxy_framework/client_proxy_framework.dart';
|
||
|
||
class MyAppConfig extends AppConfig {
|
||
@override
|
||
String get appId => 'YourAppId';
|
||
|
||
@override
|
||
String get packageName => 'com.yourapp.package';
|
||
|
||
@override
|
||
String get aesKey => 'your-16-char-key';
|
||
|
||
@override
|
||
String get preBaseUrl => 'https://pre-api.example.com';
|
||
|
||
@override
|
||
String get prodBaseUrl => 'https://api.example.com';
|
||
|
||
@override
|
||
String get proxyPath => '/quester/defender/summoner';
|
||
}
|
||
```
|
||
|
||
### 2.3 初始化
|
||
|
||
在 `main.dart` 中初始化:
|
||
|
||
```dart
|
||
void main() {
|
||
ApiClient.init(MyAppConfig());
|
||
runApp(const MyApp());
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 3. 设计理念
|
||
|
||
### 3.1 请求流程
|
||
|
||
```
|
||
调用层 (原始字段)
|
||
↓
|
||
ProxyClient.request()(自动加 `pkg`;默认加 `User_token`)
|
||
↓
|
||
字段映射 (原始 → V2)
|
||
↓
|
||
AES 加密
|
||
↓
|
||
发送请求
|
||
```
|
||
|
||
**请求头**:`ProxyClient` 会将 [AppConfig.packageName] 写入映射后的包名字段(原始名 `pkg`);若已设置用户 token,默认还会写入 `User_token`。**`UserApi.fast_login` 等无需登录态接口**内部使用 `includeUserTokenInHeader: false`,避免把旧 token 打进 `filter_type`。其余请求也可在直接调用 `ProxyClient.request` 时传入该参数。
|
||
|
||
**请求体**:各 `*Api` 方法使用与《客户端指南》解密表一致的**原始字段名**(如 `referer`、`deviceId`、`fileUrls` / `contentType` / `content`)。
|
||
|
||
### 3.2 响应流程
|
||
|
||
```
|
||
接收响应
|
||
↓
|
||
AES 解密
|
||
↓
|
||
字段映射 (V2 → 原始)
|
||
↓
|
||
转换为实体类
|
||
↓
|
||
调用层 (实体类)
|
||
```
|
||
|
||
---
|
||
|
||
## 4. 配置项详解
|
||
|
||
### AppConfig 配置
|
||
|
||
| 配置项 | 必填 | 说明 |
|
||
|--------|------|------|
|
||
| `appId` | 是 | 应用标识,对应代理请求的 `hero_class` |
|
||
| `packageName` | 是 | 应用包名,如 `com.example.app` |
|
||
| `aesKey` | 是 | AES 加密密钥,长度需为 16 字符 |
|
||
| `preBaseUrl` | 是 | 预发环境域名 |
|
||
| `prodBaseUrl` | 是 | 生产环境域名 |
|
||
| `proxyPath` | 是 | 代理入口路径 |
|
||
| `debugBaseUrlOverride` | 否 | 调试时本地代理地址 |
|
||
| `fieldMapping` | 否 | 字段映射表,默认使用 `petsHeroAIFieldMapping` |
|
||
|
||
---
|
||
|
||
## 5. API 服务
|
||
|
||
所有 API 方法使用**原始字段名**,返回**强类型实体**。
|
||
|
||
### 5.1 UserApi - 用户相关
|
||
|
||
#### 5.1.1 fastLogin - 设备快速登录
|
||
|
||
```dart
|
||
final res = await UserApi.fastLogin(
|
||
deviceId: '设备ID',
|
||
sign: 'MD5(deviceId)大写',
|
||
app: 'HAndroid', // 必填:HIOS / HAndroid
|
||
referer: '归因来源', // 可选
|
||
ch: '渠道号', // 可选
|
||
type: 'fb', // 可选;未传时默认 fb
|
||
);
|
||
|
||
if (res.isSuccess) {
|
||
final loginInfo = res.data!;
|
||
final token = loginInfo.userToken;
|
||
final credits = loginInfo.credits;
|
||
final userId = loginInfo.userId;
|
||
}
|
||
```
|
||
|
||
宿主需在 `FrameworkAuthService.init` 传入的 `AuthServiceCallbacks` 中实现 `deviceId` 与 `sign`。**FunyMee 采用的获取方式与签名规则**见 [device_id_and_sign.md](./device_id_and_sign.md)。
|
||
|
||
**返回实体**: `FastLoginResponse`
|
||
- `userToken`: 用户 Token
|
||
- `userId`: 用户 ID
|
||
- `credits`: 积分
|
||
- `avatar`: 头像
|
||
- `userName`: 用户名
|
||
- `countryCode`: 国家码
|
||
- `isVip`: 是否 VIP
|
||
- 等等...
|
||
|
||
#### 5.1.2 getCommonInfo - 获取用户通用信息
|
||
|
||
```dart
|
||
final config = ApiClient.instance.config;
|
||
final backendApp = defaultTargetPlatform == TargetPlatform.iOS
|
||
? config.backendAppTypeIOS
|
||
: config.backendAppTypeAndroid;
|
||
|
||
final res = await UserApi.getCommonInfo(
|
||
app: backendApp, // 必填:HIOS / HAndroid 等与后端约定
|
||
pkg: config.packageName, // 必填:包名
|
||
userId: '用户ID', // 可选
|
||
deviceId: '设备ID', // 可选
|
||
// client / ch / inviteBy / clientId 可选
|
||
);
|
||
|
||
if (res.isSuccess) {
|
||
final info = res.data!;
|
||
}
|
||
```
|
||
|
||
**返回实体**: `CommonInfoResponse`
|
||
|
||
#### 5.1.3 getAccount - 获取账户信息
|
||
|
||
```dart
|
||
final res = await UserApi.getAccount(
|
||
app: 'HAndroid',
|
||
userId: '用户ID', // 可选
|
||
);
|
||
|
||
if (res.isSuccess) {
|
||
final account = res.data!;
|
||
final credits = account.credits;
|
||
final isVip = account.isVip;
|
||
}
|
||
```
|
||
|
||
**返回实体**: `AccountResponse`
|
||
- `credits`: 积分
|
||
- `avatar`: 头像
|
||
- `userName`: 用户名
|
||
- `isVip`: 是否 VIP
|
||
- `freeTimes`: 免费次数
|
||
|
||
#### 5.1.4 getAppLanguage - App 语言配置
|
||
|
||
`GET /v1/config/app-language`(需登录)
|
||
|
||
```dart
|
||
final res = await UserApi.getAppLanguage(
|
||
pkg: ApiClient.instance.config.packageName,
|
||
lang: 'en', // 可选
|
||
);
|
||
```
|
||
|
||
**返回实体**: `AppLanguageConfigResponse`(`config` 为语言配置 JSON 字符串)
|
||
|
||
#### 5.1.5 getCreditsPage - 积分分页流水
|
||
|
||
与 `ImageApi.getCreditsPageInfo` 相同,路径 `GET /v1/user/credits-page`。
|
||
|
||
```dart
|
||
final res = await UserApi.getCreditsPage(page: '1', size: '10', type: '1');
|
||
```
|
||
|
||
#### 5.1.6 getUserPayments - 用户支付记录
|
||
|
||
```dart
|
||
final res = await UserApi.getUserPayments(
|
||
app: backendApp,
|
||
userId: '用户ID',
|
||
);
|
||
```
|
||
|
||
**返回实体**: `UserPaymentsListResponse`(`items`: `UserPaymentRecord` 列表)
|
||
|
||
#### 5.1.7 getUnreadMessageCount - 未读消息数
|
||
|
||
```dart
|
||
final res = await UserApi.getUnreadMessageCount(types: '类型列表'); // types 可选
|
||
```
|
||
|
||
**返回实体**: `UnreadMessageCountResponse`
|
||
|
||
---
|
||
|
||
### 5.2 PaymentApi - 支付相关
|
||
|
||
#### 5.2.1 getGooglePayActivities - 获取 Android 商品列表
|
||
|
||
```dart
|
||
final res = await PaymentApi.getGooglePayActivities(
|
||
app: 'HAndroid', // 可选;默认 `AppConfig.backendAppTypeAndroid`
|
||
client: '客户端', // 可选
|
||
country: '国家', // 可选
|
||
);
|
||
|
||
if (res.isSuccess) {
|
||
final products = res.data!.productList;
|
||
for (final product in products ?? []) {
|
||
final id = product.productId;
|
||
final price = product.actualAmount;
|
||
final bonus = product.bonus;
|
||
}
|
||
}
|
||
```
|
||
|
||
**返回实体**: `PaymentProductsResponse`
|
||
- `productList`: 商品列表
|
||
- `productId`: 商品 ID
|
||
- `activityId`: 活动 ID
|
||
- `actualAmount`: 实际金额
|
||
- `originAmount`: 原价
|
||
- `bonus`: 赠送积分
|
||
- `title`: 标题
|
||
|
||
#### 5.2.2 getPaymentMethods - 获取支付方式列表
|
||
|
||
```dart
|
||
final res = await PaymentApi.getPaymentMethods(
|
||
activityId: 12345, // int,与接口一致
|
||
country: '国家', // 可选
|
||
);
|
||
|
||
if (res.isSuccess) {
|
||
final methods = res.data!.paymentMethods;
|
||
for (final method in methods ?? []) {
|
||
final pm = method.paymentMethod;
|
||
final name = method.name;
|
||
final isRecommend = method.recommend;
|
||
}
|
||
}
|
||
```
|
||
|
||
**返回实体**: `PaymentMethodsResponse`
|
||
- `paymentMethods`: 支付方式列表
|
||
- `paymentMethod`: 支付方式
|
||
- `subPaymentMethod`: 子支付方式
|
||
- `name`: 显示名称
|
||
- `icon`: 图标
|
||
- `recommend`: 是否推荐
|
||
|
||
#### 5.2.3 createPayment - 创建支付订单
|
||
|
||
```dart
|
||
final res = await PaymentApi.createPayment(
|
||
app: 'HAndroid', // HIOS / HAndroid
|
||
userId: '用户ID',
|
||
activityId: '活动ID',
|
||
paymentMethod: '支付方式',
|
||
paymentType: '支付子类型', // 可选
|
||
);
|
||
|
||
if (res.isSuccess) {
|
||
final order = res.data!;
|
||
final orderId = order.orderId;
|
||
final payUrl = order.payUrl;
|
||
}
|
||
```
|
||
|
||
**返回实体**: `CreatePaymentResponse`
|
||
- `orderId`: 订单 ID
|
||
- `payUrl`: 支付链接
|
||
- `status`: 状态
|
||
|
||
#### 5.2.4 getPaymentDetailList - 支付订单列表
|
||
|
||
`GET /v1/payment/getPaymentDetailList`
|
||
|
||
```dart
|
||
final res = await PaymentApi.getPaymentDetailList(
|
||
app: 'HAndroid',
|
||
userId: '用户ID',
|
||
paymentMethod: 'GOOGLEPAY', // 可选
|
||
filterStatus: 'SUCCESS', // 可选
|
||
);
|
||
```
|
||
|
||
**返回实体**: `PaymentOrderListResponse`(`orders`: `PaymentOrderSummary` 列表)
|
||
|
||
#### 5.2.5 getOrderDetail - 获取订单详情
|
||
|
||
Query 使用原始字段 `id`(值为订单/支付 ID)。
|
||
|
||
```dart
|
||
final res = await PaymentApi.getOrderDetail(
|
||
userId: '用户ID',
|
||
orderId: '订单ID',
|
||
);
|
||
|
||
if (res.isSuccess) {
|
||
final order = res.data!;
|
||
final status = order.status;
|
||
}
|
||
```
|
||
|
||
**返回实体**: `OrderDetailResponse`
|
||
- `orderId`: 订单 ID
|
||
- `status`: 状态
|
||
- `amount`: 金额
|
||
|
||
#### 5.2.6 googlepay - Google Pay 回调
|
||
|
||
```dart
|
||
final res = await PaymentApi.googlepay(
|
||
signature: '购买签名',
|
||
purchaseData: '购买数据',
|
||
orderId: '订单ID',
|
||
userId: '用户ID',
|
||
);
|
||
|
||
if (res.isSuccess) {
|
||
final result = res.data!;
|
||
final status = result.status;
|
||
}
|
||
```
|
||
|
||
**返回实体**: `GooglePayCallbackResponse`
|
||
- `orderId`: 订单 ID
|
||
- `status`: 状态
|
||
- `creditsAdded`: 是否已加积分
|
||
|
||
---
|
||
|
||
### 5.3 ImageApi - 图片/视频相关
|
||
|
||
#### 5.3.1 getCategoryList - 获取分类列表
|
||
|
||
```dart
|
||
final res = await ImageApi.getCategoryList();
|
||
|
||
if (res.isSuccess) {
|
||
final categories = res.data!.categories;
|
||
}
|
||
```
|
||
|
||
**返回实体**: `CategoryListResponse`
|
||
- `categories`: 分类列表
|
||
- `id`: ID
|
||
- `name`: 名称
|
||
- `icon`: 图标
|
||
|
||
#### 5.3.2 getImg2VideoTasks - 获取任务列表
|
||
|
||
```dart
|
||
final res = await ImageApi.getImg2VideoTasks(
|
||
categoryId: 123, // 可选
|
||
);
|
||
|
||
if (res.isSuccess) {
|
||
final tasks = res.data!.tasks;
|
||
}
|
||
```
|
||
|
||
**返回实体**: `TasksResponse`
|
||
|
||
#### 5.3.3 getProgress - 查询任务进度
|
||
|
||
```dart
|
||
final res = await ImageApi.getProgress(
|
||
app: '应用ID',
|
||
taskId: '任务ID',
|
||
userId: '用户ID', // 可选
|
||
);
|
||
|
||
if (res.isSuccess) {
|
||
final progress = res.data!;
|
||
final status = progress.status;
|
||
final resultUrl = progress.resultUrl;
|
||
}
|
||
```
|
||
|
||
**返回实体**: `ProgressResponse`
|
||
- `taskId`: 任务 ID
|
||
- `status`: 状态
|
||
- `progress`: 进度 (0-100)
|
||
- `resultUrl`: 结果 URL
|
||
|
||
#### 5.3.4 createTask - 创建任务
|
||
|
||
```dart
|
||
final res = await ImageApi.createTask(
|
||
userId: '用户ID',
|
||
prompt: '提示词', // 可选
|
||
resolution: '1024x1024', // 可选
|
||
imgUrl: '图片URL', // 可选
|
||
allowance: false, // 可选
|
||
);
|
||
|
||
if (res.isSuccess) {
|
||
final taskId = res.data!.taskId;
|
||
}
|
||
```
|
||
|
||
**返回实体**: `CreateTaskResponse`
|
||
- `taskId`: 任务 ID
|
||
- `status`: 状态
|
||
|
||
#### 5.3.5 getMyTasks - 获取我的任务列表
|
||
|
||
```dart
|
||
final res = await ImageApi.getMyTasks(
|
||
app: '应用ID',
|
||
page: '1', // 可选
|
||
pageSize: '10', // 可选
|
||
cursor: '游标', // 可选
|
||
);
|
||
|
||
if (res.isSuccess) {
|
||
final tasks = res.data!.tasks;
|
||
final total = res.data!.total;
|
||
}
|
||
```
|
||
|
||
**返回实体**: `MyTasksResponse`
|
||
- `tasks`: 任务列表
|
||
- `total`: 总数
|
||
- `cursor`: 游标
|
||
|
||
#### 5.3.6 getCreditsPageInfo - 获取积分页面信息
|
||
|
||
对应 `GET /v1/user/credits-page`(与 `UserApi.getCreditsPage` 相同)。
|
||
|
||
```dart
|
||
final res = await ImageApi.getCreditsPageInfo(
|
||
page: '1',
|
||
size: '10',
|
||
type: '1',
|
||
);
|
||
|
||
// 或:UserApi.getCreditsPage(page: '1', size: '10', type: '1');
|
||
|
||
if (res.isSuccess) {
|
||
final info = res.data!;
|
||
final total = info.total;
|
||
final records = info.records;
|
||
final credits = info.credits; // 若后端仍返回单屏字段则可用
|
||
}
|
||
```
|
||
|
||
**返回实体**: `CreditsPageInfoResponse`
|
||
- `total` / `current` / `pages` / `size` / `records`: 分页与流水(新接口)
|
||
- `credits` / `freeTimes` / `isVip` / `vipExpireTime`: 兼容旧字段
|
||
- `records` 项见 `CreditRecordItem`
|
||
|
||
---
|
||
|
||
### 5.4 FeedbackApi - 举报/反馈相关
|
||
|
||
#### 5.4.1 getUploadPresignedUrl - 获取上传预签名 URL
|
||
|
||
```dart
|
||
final res = await FeedbackApi.getUploadPresignedUrl(
|
||
fileName: 'image.jpg',
|
||
);
|
||
|
||
if (res.isSuccess) {
|
||
final result = res.data!;
|
||
final uploadUrl = result.uploadUrl;
|
||
final filePath = result.filePath;
|
||
}
|
||
```
|
||
|
||
**返回实体**: `FeedbackUploadPresignedUrlResponse`
|
||
- `uploadUrl`: 上传 URL
|
||
- `filePath`: 文件路径
|
||
|
||
#### 5.4.2 submit - 提交反馈
|
||
|
||
```dart
|
||
final res = await FeedbackApi.submit(
|
||
fileUrls: ['https://...'],
|
||
content: '反馈内容',
|
||
contentType: 'text/plain',
|
||
);
|
||
|
||
if (res.isSuccess) {
|
||
final success = res.data!.success;
|
||
}
|
||
```
|
||
|
||
**返回实体**: `SubmitFeedbackResponse`
|
||
- `success`: 是否成功
|
||
- `feedbackId`: 反馈 ID
|
||
|
||
---
|
||
|
||
## 6. 响应处理
|
||
|
||
### 6.1 EntityResponse
|
||
|
||
所有返回实体类的方法都使用 `EntityResponse<T>`:
|
||
|
||
```dart
|
||
final res = await UserApi.fastLogin(...);
|
||
|
||
// 检查成功
|
||
if (res.isSuccess) {
|
||
// 访问实体
|
||
final data = res.data!;
|
||
final token = data.userToken;
|
||
} else {
|
||
// 处理错误
|
||
print('Error: ${res.msg}');
|
||
}
|
||
```
|
||
|
||
### EntityResponse 属性
|
||
|
||
| 属性 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `code` | int | 响应码,0 表示成功 |
|
||
| `msg` | String | 响应消息 |
|
||
| `data` | T? | 实体数据 |
|
||
| `isSuccess` | bool | 便捷属性,code == 0 时为 true |
|
||
|
||
---
|
||
|
||
## 7. 设置用户 Token
|
||
|
||
登录成功后,调用以下方法设置用户 Token:
|
||
|
||
```dart
|
||
// 登录成功后
|
||
final res = await UserApi.fastLogin(...);
|
||
if (res.isSuccess) {
|
||
ApiClient.instance.setUserToken(res.data!.userToken);
|
||
}
|
||
|
||
// 登出时
|
||
ApiClient.instance.setUserToken(null);
|
||
```
|
||
|
||
---
|
||
|
||
## 8. 调试模式
|
||
|
||
框架会自动根据 `kDebugMode` 选择环境:
|
||
|
||
- **调试模式**:使用 `preBaseUrl`(或 `debugBaseUrlOverride`)
|
||
- **发布模式**:使用 `prodBaseUrl`
|
||
|
||
---
|
||
|
||
## 9. 字段映射
|
||
|
||
框架自动处理字段映射,调用层使用原始字段名。
|
||
|
||
### 请求字段映射(原始 → V2)
|
||
|
||
| 原始字段 | V2 字段 |
|
||
|----------|---------|
|
||
| app | sentinel |
|
||
| userId | asset |
|
||
| deviceId | origin |
|
||
| sign | resolution |
|
||
| referer | digest |
|
||
| activityId | warrior |
|
||
| country | vambrace |
|
||
| paymentMethod | resource |
|
||
| paymentType | ceremony |
|
||
| orderId | federation |
|
||
| signature | sample |
|
||
| purchaseData | merchant |
|
||
| taskId | tree |
|
||
| prompt | ledger |
|
||
| resolution | guild |
|
||
| srcImgUrls | commission |
|
||
| fileName1 | gateway |
|
||
| contentType | pauldron |
|
||
| expectedSize | stronghold |
|
||
|
||
### 响应字段映射(V2 → 原始)
|
||
|
||
| V2 字段 | 原始字段 |
|
||
|---------|----------|
|
||
| helm | code/响应码 |
|
||
| rampart | msg |
|
||
| sidekick | data |
|
||
| summon | productList |
|
||
| renew | paymentMethods |
|
||
| reveal | credits |
|
||
| reevaluate | userToken |
|
||
|
||
---
|
||
|
||
## 10. 代码示例
|
||
|
||
### 完整登录流程
|
||
|
||
```dart
|
||
import 'package:client_proxy_framework/client_proxy_framework.dart';
|
||
|
||
class AuthService {
|
||
static Future<bool> login() async {
|
||
final deviceId = await getDeviceId();
|
||
final sign = md5(deviceId).toUpperCase();
|
||
|
||
final res = await UserApi.fastLogin(
|
||
deviceId: deviceId,
|
||
sign: sign,
|
||
app: 'HAndroid', // 或 AppConfig.backendAppTypeAndroid / IOS
|
||
referer: 'organic',
|
||
);
|
||
|
||
if (res.isSuccess) {
|
||
final loginInfo = res.data!;
|
||
ApiClient.instance.setUserToken(loginInfo.userToken!);
|
||
UserState.setUserId(loginInfo.userId!);
|
||
UserState.setCredits(loginInfo.credits ?? 0);
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
}
|
||
```
|
||
|
||
### 完整支付流程
|
||
|
||
```dart
|
||
class PaymentService {
|
||
// 1. 获取商品列表
|
||
static Future<List<PaymentProductItem>> getProducts() async {
|
||
final res = await PaymentApi.getGooglePayActivities();
|
||
return res.data?.productList ?? [];
|
||
}
|
||
|
||
// 2. 获取支付方式
|
||
static Future<List<PaymentMethodItem>> getPaymentMethods(int activityId) async {
|
||
final res = await PaymentApi.getPaymentMethods(activityId: activityId);
|
||
return res.data?.paymentMethods ?? [];
|
||
}
|
||
|
||
// 3. 创建订单
|
||
static Future<String?> createOrder({
|
||
required String userId,
|
||
required String activityId,
|
||
required String paymentMethod,
|
||
}) async {
|
||
final res = await PaymentApi.createPayment(
|
||
app: ApiClient.instance.config.backendAppTypeAndroid,
|
||
userId: userId,
|
||
activityId: activityId,
|
||
paymentMethod: paymentMethod,
|
||
);
|
||
if (res.isSuccess) {
|
||
return res.data?.orderId;
|
||
}
|
||
return null;
|
||
}
|
||
|
||
// 4. Google Pay 回调
|
||
static Future<bool> verifyGooglePay({
|
||
required String signature,
|
||
required String purchaseData,
|
||
required String orderId,
|
||
required String userId,
|
||
}) async {
|
||
final res = await PaymentApi.googlepay(
|
||
signature: signature,
|
||
purchaseData: purchaseData,
|
||
orderId: orderId,
|
||
userId: userId,
|
||
);
|
||
return res.isSuccess;
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 11. 常见问题
|
||
|
||
### Q: 如何修改字段映射?
|
||
|
||
A: 覆盖 `AppConfig.fieldMapping`:
|
||
|
||
```dart
|
||
@override
|
||
FieldMapping get fieldMapping => const FieldMapping({
|
||
'deviceId': 'origin',
|
||
'userId': 'asset',
|
||
// ... 其他字段
|
||
});
|
||
```
|
||
|
||
### Q: 响应 data 为空怎么办?
|
||
|
||
A: 检查以下几点:
|
||
1. `ApiClient.init()` 是否已调用
|
||
2. 网络是否正常
|
||
3. `appId`、`aesKey` 等配置是否正确
|
||
|
||
---
|
||
|
||
## 12. 文件结构
|
||
|
||
```
|
||
lib/
|
||
├── client_proxy_framework.dart # 入口文件
|
||
└── src/
|
||
├── api/
|
||
│ ├── api_client.dart # 全局客户端
|
||
│ ├── api_crypto.dart # 加解密工具
|
||
│ ├── api_response.dart # 响应对象
|
||
│ └── proxy_client.dart # 代理请求客户端(含实体转换)
|
||
├── config/
|
||
│ ├── app_config.dart # 应用配置抽象类
|
||
│ ├── default_field_mapping.dart # 默认字段映射
|
||
│ └── field_mapping.dart # 字段映射类
|
||
├── entities/
|
||
│ ├── entity.dart # 实体基类
|
||
│ ├── user_entities.dart # 用户相关实体
|
||
│ ├── payment_entities.dart # 支付相关实体
|
||
│ ├── image_entities.dart # 图片/视频实体
|
||
│ └── feedback_entities.dart # 反馈实体
|
||
├── log/
|
||
│ └── app_logger.dart # 日志工具
|
||
└── services/
|
||
├── user_api.dart # 用户 API
|
||
├── payment_api.dart # 支付 API
|
||
├── image_api.dart # 图片/视频 API
|
||
└── feedback_api.dart # 反馈 API
|
||
```
|