在这里插入图片描述

前言

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

在Flutter开发中,Dio是最受欢迎的HTTP客户端库之一。它提供了强大的功能,包括拦截器全局配置文件上传下载请求取消超时控制等。本文将详细介绍如何使用Dio三方库进行Flutter网络开发。

提示:Dio支持全局配置、拦截器、FormData、请求取消、文件上传下载、超时控制、自定义适配器等强大功能。

一、Dio三方库简介

1.1 什么是Dio

Dio是一个强大的Dart/Flutter HTTP网络库,由中国Flutter社区(CFUG)维护。它提供了简洁的API和丰富的功能,是Flutter开发中最常用的网络请求库。

特性 说明 优势
全局配置 统一管理baseUrl、超时等 减少重复配置
拦截器 请求/响应拦截处理 统一认证、日志
文件操作 上传下载文件 支持进度监听
请求取消 取消正在进行的请求 避免资源浪费
错误处理 统一的异常处理机制 简化错误处理
转换器 自定义数据转换 灵活处理数据

官方文档:https://pub.dev/packages/dio

GitHub仓库:https://github.com/cfug/dio

1.2 Dio核心概念

Dio包含以下核心组件:

  1. Dio实例:HTTP客户端核心对象
  2. BaseOptions:全局配置选项
  3. Interceptor:拦截器(请求/响应/错误)
  4. Transformer:数据转换器
  5. HttpClientAdapter:HTTP客户端适配器
  6. CancelToken:请求取消令牌

提示:建议在项目中使用单例模式管理Dio实例,统一配置和管理网络请求。

1.3 Dio vs 其他HTTP库

库名 功能丰富度 易用性 性能 社区活跃度
Dio ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐
Http ⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐
Chopper ⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐

二、环境配置与依赖安装

2.1 添加依赖

pubspec.yaml文件中添加Dio依赖:

dependencies:
  dio: ^5.4.0

2.2 安装依赖

执行以下命令安装依赖:

flutter pub get

相关资源链接:

  • Dio Package:https://pub.dev/packages/dio
  • 官方文档:https://pub.dev/documentation/dio/latest/
  • GitHub仓库:https://github.com/cfug/dio

2.3 导入包

在Dart文件中导入Dio:

import 'package:dio/dio.dart';

三、基础使用

3.1 创建Dio实例

最简单的使用方式:

final dio = Dio();

void getHttp() async {
  final response = await dio.get('https://dart.dev');
  print(response.data);
}

3.2 配置BaseOptions

创建带配置的Dio实例:

final dio = Dio(
  BaseOptions(
    baseUrl: 'https://api.example.com',
    connectTimeout: Duration(seconds: 5),
    receiveTimeout: Duration(seconds: 3),
    headers: {
      'Content-Type': 'application/json',
      'Accept': 'application/json',
    },
  ),
);

BaseOptions配置项:

配置项 类型 说明 默认值
baseUrl Uri 基础URL -
connectTimeout Duration 连接超时 null
receiveTimeout Duration 接收超时 null
sendTimeout Duration 发送超时 null
headers Map 请求头 {}
responseType ResponseType 响应类型 json
contentType String 内容类型 application/json

3.3 修改配置

可以随时修改Dio实例的配置:

dio.options.baseUrl = 'https://api.example.com';
dio.options.connectTimeout = Duration(seconds: 5);
dio.options.receiveTimeout = Duration(seconds: 3);

四、发起请求

4.1 GET请求

基础GET请求:

// 方式1:直接传递查询参数
final response = await dio.get('/test?id=12&name=dio');
print(response.data);

// 方式2:使用queryParameters
final response = await dio.get(
  '/test',
  queryParameters: {'id': 12, 'name': 'dio'},
);
print(response.data);

4.2 POST请求

发送POST请求:

final response = await dio.post(
  '/test',
  data: {'id': 12, 'name': 'dio'},
);
print(response.data);

4.3 其他HTTP方法

Dio支持所有HTTP方法:

// PUT请求
await dio.put('/user/12', data: {'name': 'dio'});

// DELETE请求
await dio.delete('/user/12');

// PATCH请求
await dio.patch('/user/12', data: {'name': 'dio'});

// HEAD请求
await dio.head('/test');

4.4 并发请求

使用Future.wait执行多个并发请求:

final responses = await Future.wait([
  dio.post('/info'),
  dio.get('/token'),
  dio.get('/user'),
]);

print(responses[0].data);
print(responses[1].data);
print(responses[2].data);

五、Response对象

5.1 Response属性

Response对象包含以下属性:

final response = await dio.get('https://api.example.com/data');

// 响应数据
print(response.data);

// 状态码
print(response.statusCode); // 200

// 状态消息
print(response.statusMessage); // OK

// 响应头
print(response.headers);

// 请求配置
print(response.requestOptions);

// 是否重定向
print(response.isRedirect);

// 重定向记录
print(response.redirects);

5.2 响应类型

Dio支持多种响应类型:

响应类型 说明 使用场景
ResponseType.json JSON数据 API接口
ResponseType.plain 纯文本 HTML页面
ResponseType.bytes 字节数组 图片、文件
ResponseType.stream 流式数据 大文件下载
// 获取字节数据
final rs = await dio.get<List<int>>(
  url,
  options: Options(responseType: ResponseType.bytes),
);
print(rs.data); // List<int>

// 获取流数据
final rs = await dio.get(
  url,
  options: Options(responseType: ResponseType.stream),
);
print(rs.data.stream); // Stream

5.3 泛型支持

使用泛型指定响应数据类型:

final response = await dio.get<Map<String, dynamic>>('/user');
final userData = response.data; // Map<String, dynamic>

final response = await dio.get<List<int>>(
  '/image',
  options: Options(responseType: ResponseType.bytes),
);
final imageBytes = response.data; // List<int>

六、拦截器详解

6.1 拦截器概念

拦截器可以在请求发送前、响应接收后、错误发生时进行拦截处理。

![拦截器工作流程占位图 - 展示请求、响应、错误三个拦截点]

拦截器执行顺序:

  1. 请求拦截器(onRequest)
  2. 发送HTTP请求
  3. 响应拦截器(onResponse)或错误拦截器(onError)

6.2 添加拦截器

使用InterceptorsWrapper添加拦截器:

dio.interceptors.add(
  InterceptorsWrapper(
    onRequest: (options, handler) {
      // 请求前处理
      print('REQUEST[${options.method}] => PATH: ${options.path}');
      return handler.next(options);
    },
    onResponse: (response, handler) {
      // 响应后处理
      print('RESPONSE[${response.statusCode}] => DATA: ${response.data}');
      return handler.next(response);
    },
    onError: (error, handler) {
      // 错误处理
      print('ERROR[${error.response?.statusCode}] => MESSAGE: ${error.message}');
      return handler.next(error);
    },
  ),
);

6.3 自定义拦截器

继承Interceptor类创建自定义拦截器:

class CustomInterceptor extends Interceptor {
  
  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
    print('REQUEST[${options.method}] => PATH: ${options.path}');
    super.onRequest(options, handler);
  }

  
  void onResponse(Response response, ResponseInterceptorHandler handler) {
    print('RESPONSE[${response.statusCode}] => PATH: ${response.requestOptions.path}');
    super.onResponse(response, handler);
  }

  
  void onError(DioException err, ErrorInterceptorHandler handler) {
    print('ERROR[${err.response?.statusCode}] => PATH: ${err.requestOptions.path}');
    super.onError(err, handler);
  }
}

// 使用自定义拦截器
dio.interceptors.add(CustomInterceptor());

6.4 认证拦截器

实现自动添加Token的拦截器:

class AuthInterceptor extends Interceptor {
  final String token;

  AuthInterceptor(this.token);

  
  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
    options.headers['Authorization'] = 'Bearer $token';
    super.onRequest(options, handler);
  }
}

dio.interceptors.add(AuthInterceptor('your_token_here'));

6.5 LogInterceptor

使用内置的日志拦截器:

dio.interceptors.add(
  LogInterceptor(
    request: true,
    requestHeader: true,
    requestBody: true,
    responseHeader: true,
    responseBody: true,
    error: true,
    logPrint: (o) => print(o),
  ),
);

6.6 QueuedInterceptor

顺序执行的拦截器(适用于需要异步操作的场景):

class TokenInterceptor extends QueuedInterceptor {
  
  void onRequest(RequestOptions options, RequestInterceptorHandler handler) async {
    // 异步获取token
    final token = await getToken();
    options.headers['Authorization'] = 'Bearer $token';
    handler.next(options);
  }
}

dio.interceptors.add(TokenInterceptor());

七、错误处理

7.1 DioException

Dio将所有错误包装为DioException:

try {
  await dio.get('https://api.example.com/not-exist');
} on DioException catch (e) {
  if (e.response != null) {
    // 服务器返回错误响应
    print('Status: ${e.response?.statusCode}');
    print('Data: ${e.response?.data}');
    print('Headers: ${e.response?.headers}');
  } else {
    // 请求发送失败
    print('Error: ${e.message}');
  }
}

7.2 DioExceptionType

DioException包含多种错误类型:

错误类型 说明 常见原因
connectionTimeout 连接超时 网络不稳定
sendTimeout 发送超时 上传大文件
receiveTimeout 接收超时 服务器响应慢
badResponse 错误响应 4xx/5xx状态码
cancel 请求取消 主动取消
connectionError 连接错误 无网络连接
unknown 未知错误 其他异常
try {
  await dio.get('/test');
} on DioException catch (e) {
  switch (e.type) {
    case DioExceptionType.connectionTimeout:
      print('连接超时');
      break;
    case DioExceptionType.sendTimeout:
      print('发送超时');
      break;
    case DioExceptionType.receiveTimeout:
      print('接收超时');
      break;
    case DioExceptionType.badResponse:
      print('错误响应: ${e.response?.statusCode}');
      break;
    case DioExceptionType.cancel:
      print('请求取消');
      break;
    case DioExceptionType.connectionError:
      print('连接错误');
      break;
    case DioExceptionType.unknown:
      print('未知错误: ${e.message}');
      break;
  }
}

7.3 统一错误处理

创建错误处理拦截器:

class ErrorInterceptor extends Interceptor {
  
  void onError(DioException err, ErrorInterceptorHandler handler) {
    switch (err.type) {
      case DioExceptionType.connectionTimeout:
      case DioExceptionType.sendTimeout:
      case DioExceptionType.receiveTimeout:
        // 显示超时提示
        showToast('请求超时,请稍后重试');
        break;
      case DioExceptionType.badResponse:
        // 根据状态码处理
        handleStatusCode(err.response?.statusCode);
        break;
      case DioExceptionType.cancel:
        // 请求取消,不做处理
        break;
      default:
        showToast('网络错误,请检查网络连接');
    }
    super.onError(err, handler);
  }

  void handleStatusCode(int? statusCode) {
    switch (statusCode) {
      case 400:
        showToast('请求参数错误');
        break;
      case 401:
        showToast('未授权,请重新登录');
        // 跳转到登录页
        break;
      case 403:
        showToast('禁止访问');
        break;
      case 404:
        showToast('请求的资源不存在');
        break;
      case 500:
        showToast('服务器错误');
        break;
      default:
        showToast('未知错误');
    }
  }
}

八、文件上传下载

8.1 FormData上传

使用FormData上传文件:

final formData = FormData.fromMap({
  'name': 'dio',
  'date': DateTime.now().toIso8601String(),
  'file': await MultipartFile.fromFile(
    './text.txt',
    filename: 'upload.txt',
  ),
});

final response = await dio.post('/upload', data: formData);

8.2 多文件上传

上传多个文件:

final formData = FormData.fromMap({
  'name': 'dio',
  'files': [
    await MultipartFile.fromFile('./text1.txt', filename: 'text1.txt'),
    await MultipartFile.fromFile('./text2.txt', filename: 'text2.txt'),
  ],
});

final response = await dio.post('/upload', data: formData);

8.3 上传进度监听

监听文件上传进度:

final response = await dio.post(
  '/upload',
  data: formData,
  onSendProgress: (sent, total) {
    final progress = (sent / total * 100).toStringAsFixed(0);
    print('上传进度: $progress%');
  },
);

8.4 文件下载

下载文件到本地:

await dio.download(
  'https://example.com/file.zip',
  '/path/to/save/file.zip',
  onReceiveProgress: (received, total) {
    if (total != -1) {
      final progress = (received / total * 100).toStringAsFixed(0);
      print('下载进度: $progress%');
    }
  },
);

8.5 断点续传

实现断点续传功能:

final savePath = '/path/to/save/file.zip';
final file = File(savePath);
int downloadedBytes = 0;

// 如果文件已存在,获取已下载的字节数
if (await file.exists()) {
  downloadedBytes = await file.length();
}

await dio.download(
  'https://example.com/file.zip',
  savePath,
  options: Options(
    headers: {
      'Range': 'bytes=$downloadedBytes-',
    },
  ),
  onReceiveProgress: (received, total) {
    final progress = ((downloadedBytes + received) / total * 100).toStringAsFixed(0);
    print('下载进度: $progress%');
  },
);

九、请求取消

9.1 使用CancelToken

创建CancelToken取消请求:

final cancelToken = CancelToken();

// 发起请求
dio.get('/test', cancelToken: cancelToken).catchError((error) {
  if (CancelToken.isCancel(error)) {
    print('请求已取消: ${error.message}');
  } else {
    print('请求错误: $error');
  }
});

// 取消请求
cancelToken.cancel('用户取消');

9.2 共享CancelToken

一个CancelToken可以用于多个请求:

final cancelToken = CancelToken();

// 多个请求共享同一个token
final request1 = dio.get('/api1', cancelToken: cancelToken);
final request2 = dio.get('/api2', cancelToken: cancelToken);
final request3 = dio.get('/api3', cancelToken: cancelToken);

// 取消所有请求
cancelToken.cancel('批量取消');

9.3 实际应用场景

在Flutter中取消页面销毁时的请求:

class MyPage extends StatefulWidget {
  
  _MyPageState createState() => _MyPageState();
}

class _MyPageState extends State<MyPage> {
  final cancelToken = CancelToken();

  
  void initState() {
    super.initState();
    loadData();
  }

  void loadData() async {
    try {
      final response = await dio.get('/data', cancelToken: cancelToken);
      // 处理数据
    } on DioException catch (e) {
      if (!CancelToken.isCancel(e)) {
        // 处理错误
      }
    }
  }

  
  void dispose() {
    cancelToken.cancel('页面已销毁');
    super.dispose();
  }

  
  Widget build(BuildContext context) {
    return Container();
  }
}

十、Transformer数据转换

10.1 默认Transformer

Dio默认使用BackgroundTransformer,在响应数据大于50KB时会在isolate中解析JSON:

final dio = Dio();
// 默认已经配置了BackgroundTransformer

10.2 自定义Transformer

创建自定义Transformer:

class CustomTransformer extends BackgroundTransformer {
  
  Future<String> transformRequest(RequestOptions options) async {
    // 自定义请求数据转换
    if (options.data is Map) {
      return jsonEncode(options.data);
    }
    return super.transformRequest(options);
  }

  
  Future transformResponse(
    RequestOptions options,
    ResponseBody responseBody,
  ) async {
    // 自定义响应数据转换
    final data = await super.transformResponse(options, responseBody);
    // 可以在这里添加数据解密、格式转换等逻辑
    return data;
  }
}

// 使用自定义Transformer
dio.transformer = CustomTransformer();

10.3 Transformer应用场景

常见应用场景:

  • 数据加密/解密
  • 数据格式转换
  • 添加通用字段
  • 数据校验
class EncryptTransformer extends BackgroundTransformer {
  
  Future<String> transformRequest(RequestOptions options) async {
    final data = await super.transformRequest(options);
    // 加密请求数据
    return encrypt(data);
  }

  
  Future transformResponse(
    RequestOptions options,
    ResponseBody responseBody,
  ) async {
    final data = await super.transformResponse(options, responseBody);
    // 解密响应数据
    return decrypt(data);
  }
}

十一、HttpClientAdapter适配器

11.1 默认适配器

Dio在不同平台使用不同的适配器:

  • Native平台:IOHttpClientAdapter
  • Web平台:BrowserHttpClientAdapter
import 'package:dio/io.dart';

dio.httpClientAdapter = IOHttpClientAdapter();

11.2 配置代理

使用IOHttpClientAdapter配置代理:

import 'package:dio/io.dart';

dio.httpClientAdapter = IOHttpClientAdapter(
  createHttpClient: () {
    final client = HttpClient();
    client.findProxy = (uri) {
      return 'PROXY localhost:8888';
    };
    return client;
  },
);

11.3 HTTPS证书验证

配置HTTPS证书验证:

import 'dart:io';
import 'package:dio/io.dart';

dio.httpClientAdapter = IOHttpClientAdapter(
  createHttpClient: () {
    final client = HttpClient();
    client.badCertificateCallback = (cert, host, port) {
      // 验证证书
      return cert.pem == expectedPEM;
    };
    return client;
  },
);

11.4 自定义适配器

创建自定义适配器:

class CustomAdapter implements HttpClientAdapter {
  
  Future<ResponseBody> fetch(
    RequestOptions options,
    Stream<Uint8List>? requestStream,
    Future<void>? cancelFuture,
  ) async {
    // 实现自定义的HTTP请求逻辑
    // ...
  }

  
  void close({bool force = false}) {
    // 关闭适配器
  }
}

dio.httpClientAdapter = CustomAdapter();

十二、最佳实践

12.1 单例模式

使用单例模式管理Dio实例:

class DioClient {
  static final DioClient _instance = DioClient._internal();
  late final Dio dio;

  factory DioClient() => _instance;

  DioClient._internal() {
    dio = Dio(
      BaseOptions(
        baseUrl: 'https://api.example.com',
        connectTimeout: Duration(seconds: 5),
        receiveTimeout: Duration(seconds: 3),
      ),
    );

    // 添加拦截器
    dio.interceptors.add(LogInterceptor());
    dio.interceptors.add(AuthInterceptor());
  }
}

// 使用
final dio = DioClient().dio;

12.2 API封装

封装API请求方法:

class ApiService {
  final Dio _dio = DioClient().dio;

  Future<User> getUser(String id) async {
    try {
      final response = await _dio.get('/user/$id');
      return User.fromJson(response.data);
    } on DioException catch (e) {
      throw _handleError(e);
    }
  }

  Future<List<Post>> getPosts({int page = 1, int limit = 20}) async {
    try {
      final response = await _dio.get(
        '/posts',
        queryParameters: {'page': page, 'limit': limit},
      );
      return (response.data as List)
          .map((json) => Post.fromJson(json))
          .toList();
    } on DioException catch (e) {
      throw _handleError(e);
    }
  }

  Exception _handleError(DioException error) {
    switch (error.type) {
      case DioExceptionType.connectionTimeout:
        return TimeoutException('连接超时');
      case DioExceptionType.badResponse:
        return ServerException('服务器错误: ${error.response?.statusCode}');
      default:
        return NetworkException('网络错误');
    }
  }
}

12.3 项目结构

推荐的项目结构:

lib/
├── core/
│   ├── network/
│   │   ├── dio_client.dart
│   │   ├── api_service.dart
│   │   └── interceptors/
│   │       ├── auth_interceptor.dart
│   │       ├── error_interceptor.dart
│   │       └── log_interceptor.dart
│   └── constants/
│       └── api_constants.dart
├── models/
│   ├── user.dart
│   └── post.dart
└── main.dart

十三、性能优化(第二轮)

第二轮我们把“能用”升级到“好用、快、可观测”。在网络层里,性能优化通常围绕:减少请求次数减少单次请求耗时减少主线程阻塞减少序列化开销

13.1 建议先定义可量化指标

指标 含义 建议采集方式
TTFB 首字节时间 抓包/服务端日志/客户端打点
totalTime 请求总耗时 Interceptor中打点
payloadSize 响应体大小 content-length或字节长度
errorRate 错误率 统一错误上报/日志聚合

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

13.2 通过拦截器做耗时打点(可复用)

class TimingInterceptor extends Interceptor {
  
  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
    options.extra['ts'] = DateTime.now().microsecondsSinceEpoch;
    handler.next(options);
  }

  
  void onResponse(Response response, ResponseInterceptorHandler handler) {
    final ts = response.requestOptions.extra['ts'] as int?;
    if (ts != null) {
      final costUs = DateTime.now().microsecondsSinceEpoch - ts;
      print('DioTiming ${response.requestOptions.method} ${response.requestOptions.uri} cost=${costUs / 1000}ms');
    }
    handler.next(response);
  }

  
  void onError(DioException err, ErrorInterceptorHandler handler) {
    final ts = err.requestOptions.extra['ts'] as int?;
    if (ts != null) {
      final costUs = DateTime.now().microsecondsSinceEpoch - ts;
      print('DioTiming ERROR ${err.requestOptions.method} ${err.requestOptions.uri} cost=${costUs / 1000}ms');
    }
    handler.next(err);
  }
}

13.3 并发与取消:减少无效请求

场景 建议 说明
页面切换频繁 取消旧请求 CancelToken避免浪费
接口高频刷新 节流/合并请求 降低请求次数
多接口并发 控制并发上限 避免瞬时拥塞

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

十四、内存优化(第二轮)

网络层常见的内存问题集中在:大响应体驻留内存bytes处理无上限下载流未关闭回调持有页面引用

14.1 大响应体的处理建议

数据类型 建议 目的
大JSON列表 分页/增量加载 降低峰值内存
大文件下载 ResponseType.stream 避免一次性读入内存
图片bytes 先落盘再展示 减少驻留
final rs = await dio.get(
  url,
  options: Options(responseType: ResponseType.stream),
);
final stream = rs.data.stream;
// TODO: 将stream写入File(示例略),写完及时close

14.2 页面销毁时取消请求,避免“回包更新已销毁页面”

class MyPageState extends State<MyPage> {
  final cancelToken = CancelToken();

  Future<void> load() async {
    await dio.get('/data', cancelToken: cancelToken);
  }

  
  void dispose() {
    cancelToken.cancel('disposed');
    super.dispose();
  }
}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

十五、问题定位与排障(第二轮)

第二轮的目标是“出了问题能快速定位”:建议把定位过程标准化为 打点 -> 抓包 -> 对齐服务端日志 -> 复现与回归

15.1 常见问题定位清单

现象 优先排查 常用手段
接口超时 DNS/网络/服务端耗时 客户端耗时打点 + 抓包
4xx/5xx 参数/鉴权/服务端 打印请求要素 + TraceId
偶现错误 并发/重试/取消 requestId贯穿 + 日志聚合
数据不一致 缓存/重试/多端 比对请求与响应版本

15.2 给每个请求加X-Request-Id

import 'dart:math';

String genRequestId() => '${DateTime.now().millisecondsSinceEpoch}_${Random().nextInt(1 << 20)}';

class TraceIdInterceptor extends Interceptor {
  
  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
    final rid = genRequestId();
    options.extra['rid'] = rid;
    options.headers['X-Request-Id'] = rid;
    handler.next(options);
  }
}

15.3 抓包与代理

  1. 客户端开启代理(IOHttpClientAdapter)
  2. 用抓包工具观察:URL、Header、Body、状态码、耗时
  3. X-Request-Id对齐服务端日志

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

总结

本文详细介绍了Dio三方库的核心功能和使用方法,包括基础请求、拦截器、错误处理、文件上传下载、请求取消等。Dio是Flutter开发中最强大的HTTP客户端库,掌握它能大大提高开发效率。

Dio的主要优势:

  • 功能强大且完善
  • API简洁易用
  • 性能优秀
  • 社区活跃

下一篇文章将继续围绕“网络链路治理”的第二轮主题,结合http/retrofit/pretty_dio_logger/dio_cache_interceptor做性能、内存与定位的体系化对比,敬请期待!

如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!


相关资源:

  • Dio官方文档:https://pub.dev/packages/dio
  • GitHub仓库:https://github.com/cfug/dio
  • Pub.dev主页:https://pub.dev/packages/dio
  • 中文文档:https://github.com/cfug/dio/blob/main/dio/README-ZH.md
  • 开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
  • 迁移指南:https://pub.dev/documentation/dio/latest/topics/Migration%20Guide-topic.html
  • 插件列表:https://pub.dev/documentation/dio/latest/topics/Plugins-topic.html
  • 示例代码:https://github.com/cfug/dio/tree/main/example_dart
Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐