欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

前言
后端工程师扔给你一个 Swagger (OpenAPI) 文档地址,你会怎么做?
这是重复劳动的地狱。
swagger_dart_code_generator 可以将 Swagger (JSON/YAML) 文件直接转换为高质量的 Dart 代码,包括:
- Model 类:支持 json_serializable,带 fromJson/toJson。
- Service 类:基于 chopper 或 dio 的请求方法。
- Enum:枚举类型的自动映射。
对于 OpenHarmony 应用开发,这种自动化工具能极大减少与后端对接的沟通成本和代码错误率。
一、核心工作流
该插件作为 build_runner 的一部分运行。
#mermaid-svg-YGcty5AViSlaFeyB{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-YGcty5AViSlaFeyB .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-YGcty5AViSlaFeyB .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-YGcty5AViSlaFeyB .error-icon{fill:#552222;}#mermaid-svg-YGcty5AViSlaFeyB .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-YGcty5AViSlaFeyB .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-YGcty5AViSlaFeyB .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-YGcty5AViSlaFeyB .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-YGcty5AViSlaFeyB .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-YGcty5AViSlaFeyB .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-YGcty5AViSlaFeyB .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-YGcty5AViSlaFeyB .marker{fill:#333333;stroke:#333333;}#mermaid-svg-YGcty5AViSlaFeyB .marker.cross{stroke:#333333;}#mermaid-svg-YGcty5AViSlaFeyB svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-YGcty5AViSlaFeyB p{margin:0;}#mermaid-svg-YGcty5AViSlaFeyB .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-YGcty5AViSlaFeyB .cluster-label text{fill:#333;}#mermaid-svg-YGcty5AViSlaFeyB .cluster-label span{color:#333;}#mermaid-svg-YGcty5AViSlaFeyB .cluster-label span p{background-color:transparent;}#mermaid-svg-YGcty5AViSlaFeyB .label text,#mermaid-svg-YGcty5AViSlaFeyB span{fill:#333;color:#333;}#mermaid-svg-YGcty5AViSlaFeyB .node rect,#mermaid-svg-YGcty5AViSlaFeyB .node circle,#mermaid-svg-YGcty5AViSlaFeyB .node ellipse,#mermaid-svg-YGcty5AViSlaFeyB .node polygon,#mermaid-svg-YGcty5AViSlaFeyB .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-YGcty5AViSlaFeyB .rough-node .label text,#mermaid-svg-YGcty5AViSlaFeyB .node .label text,#mermaid-svg-YGcty5AViSlaFeyB .image-shape .label,#mermaid-svg-YGcty5AViSlaFeyB .icon-shape .label{text-anchor:middle;}#mermaid-svg-YGcty5AViSlaFeyB .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-YGcty5AViSlaFeyB .rough-node .label,#mermaid-svg-YGcty5AViSlaFeyB .node .label,#mermaid-svg-YGcty5AViSlaFeyB .image-shape .label,#mermaid-svg-YGcty5AViSlaFeyB .icon-shape .label{text-align:center;}#mermaid-svg-YGcty5AViSlaFeyB .node.clickable{cursor:pointer;}#mermaid-svg-YGcty5AViSlaFeyB .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-YGcty5AViSlaFeyB .arrowheadPath{fill:#333333;}#mermaid-svg-YGcty5AViSlaFeyB .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-YGcty5AViSlaFeyB .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-YGcty5AViSlaFeyB .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-YGcty5AViSlaFeyB .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-YGcty5AViSlaFeyB .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-YGcty5AViSlaFeyB .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-YGcty5AViSlaFeyB .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-YGcty5AViSlaFeyB .cluster text{fill:#333;}#mermaid-svg-YGcty5AViSlaFeyB .cluster span{color:#333;}#mermaid-svg-YGcty5AViSlaFeyB div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-YGcty5AViSlaFeyB .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-YGcty5AViSlaFeyB rect.text{fill:none;stroke-width:0;}#mermaid-svg-YGcty5AViSlaFeyB .icon-shape,#mermaid-svg-YGcty5AViSlaFeyB .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-YGcty5AViSlaFeyB .icon-shape p,#mermaid-svg-YGcty5AViSlaFeyB .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-YGcty5AViSlaFeyB .icon-shape rect,#mermaid-svg-YGcty5AViSlaFeyB .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-YGcty5AViSlaFeyB .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-YGcty5AViSlaFeyB .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-YGcty5AViSlaFeyB :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
输入
生成
生成
生成
调用
Http 请求
swagger.json
swagger_dart_code_generator
User, Product 模型
RestClient (Dio/Chopper)
Status枚举
OpenHarmony 应用
Server
二、集成与用法详解
2.1 添加依赖
我们需要生成器和运行时库。
dependencies:
flutter:
sdk: flutter
json_annotation: ^4.8.0
chopper: ^7.0.0 # 或者 dio
dev_dependencies:
build_runner: ^2.4.0
swagger_dart_code_generator: ^4.1.1
json_serializable: ^6.7.0
chopper_generator: ^7.0.0
2.2 配置 build.yaml
在项目根目录创建 build.yaml,告诉生成器去哪里找 Swagger 文件。
targets:
$default:
builders:
swagger_dart_code_generator:
options:
input_folder: "lib/api_docs/" # 存放 json 的目录
output_folder: "lib/api_gen/" # 生成代码的目录
# 使用 chopper 还是 dio? 默认是 chopper,dio 需要额外配置
use_generator: chopper
2.3 下载 Swagger 文件
将后端的 swagger.json 下载到 lib/api_docs/myservice.swagger.json。
2.4 运行生成
flutter pub run build_runner build
生成完毕后,你会在 lib/api_gen/ 下看到 myservice.swagger.dart 等文件。
2.5 使用生成的代码
import 'package:chopper/chopper.dart';
import 'lib/api_gen/myservice.swagger.dart';
void main() async {
// 1. 创建 Service
final service = Myservice.create(ChopperClient(
baseUrl: Uri.parse('https://api.example.com'),
converter: $JsonSerializableConverter(),
));
// 2. 调用 API
final response = await service.getUser(id: 123);
if (response.isSuccessful) {
// 3. 直接获得强类型的 User 对象
final User? user = response.body;
print(user?.name);
}
}

三、OpenHarmony 适配与实战:解决构建与兼容性
3.1 鸿蒙网络库选择
生成的代码通常依赖 chopper 或 dio。
- Chopper: 基于 http 包。在纯 Dart 环境和 Flutter Mobile 上表现良好。
- Dio: 功能更强大(拦截器、下载进度)。
适配建议: 在 OpenHarmony 上,两者都能工作。但如果你需要利用鸿蒙特有的网络配置(如安全证书锁定),推荐使用 Dio 模式,因为你可以更方便地拿到底层的 HttpClientAdapter 进行定制(如替换为 dio_http2_adapter 或自定义 adapter)。
修改 build.yaml 切换到 Dio:
swagger_dart_code_generator:
options:
use_generator: dio
3.2 解决文件名冲突
有时后端的 Swagger 定义里会有 Page、List 这种通用类名,与 Flutter 冲突。 可以在配置中进行重命名映射。
options:
replacement_rules:
– pattern: "^Page$"
replacement: "ApiPage"
3.3 CI/CD 集成
在鸿蒙工程的 CI 流水线中,建议:
四、功能详解:自定义模版
如果默认生成的代码风格不符合团队规范,该插件支持自定义模板。但这通常比较复杂。更简单的方式是利用 include_if_null 等选项微调 JSON 序列化行为。
五、总结
swagger_dart_code_generator 是“契约优先”开发模式的最佳实践工具。它让 API 接口定义成为真理来源(Source of Truth)。
对于 OpenHarmony 开发者:
- 减少手写:让你从繁琐的 JSON 解析中解放出来,专注于鸿蒙 UI 和交互逻辑。
- 类型安全:所有字段都是类型安全的,再也不用担心 String 传成 int。
最佳实践:
六、完整实战示例
import 'package:chopper/chopper.dart';
// 假设这是 build_runner 生成的文件
// import 'lib/api_gen/my_service.swagger.dart';
/*
假定生成的 Service 类定义如下 (由库自动生成):
@ChopperApi()
abstract class MyService extends ChopperService {
@Get(path: '/users/{id}')
Future<Response<User>> getUser(@Path('id') int id);
static MyService create([ChopperClient? client]) => _$MyService(client);
}
*/
class ApiManager {
late final MyService _service; // 使用 dynamic 或生成的类型
// 单例模式
static final ApiManager _instance = ApiManager._internal();
factory ApiManager() => _instance;
ApiManager._internal() {
// 初始化 Chopper 客户端
final chopper = ChopperClient(
baseUrl: Uri.parse('https://api.example.com'),
converter: JsonConverter(), // 这里通常用 generated $JsonSerializableConverter
errorConverter: JsonConverter(),
services: [
// 注册生成的服务
// MyService.create(),
],
interceptors: [
// HttpLoggingInterceptor(), // 日志拦截器
]
);
// 获取服务实例
// _service = chopper.getService<MyService>();
}
Future<void> fetchUser(int id) async {
try {
/*
// 业务调用非常清爽,完全感知不到 HTTP 细节
final response = await _service.getUser(id: id);
if (response.isSuccessful) {
// body 是强类型的 User 对象
print('User Name: ${response.body?.name}');
} else {
print('API Error: ${response.error}');
}
*/
print('API Call (Simulated)');
} catch (e) {
print('Network Exception: $e');
}
}
}
void main() {
ApiManager().fetchUser(1001);
}





