Flutter for OpenHarmony:dio 网络请求库鸿蒙化适配与实战指南

欢迎加入开源鸿蒙跨平台社区:→https://openharmonycrossplatform.csdn.net
摘要
本文基于 Flutter for OpenHarmony 技术栈,以跨平台网络请求场景为核心,详细介绍了主流网络库 dio 在鸿蒙平台的适配流程、权限配置、代码封装与实战验证。通过完整可运行的示例,解决了三方库兼容、网络权限配置、跨平台请求稳定性等常见问题,为开发者提供可直接落地的实践方案。
一、前言:为什么选择 dio 作为鸿蒙 Flutter 网络方案
在 Flutter 生态中,dio 是目前最主流、功能最完善的网络请求库之一,它支持拦截器、FormData、Cookie 管理、全局配置等企业级开发能力,能满足绝大多数业务场景的网络需求。对于 OpenHarmony 平台来说,dio 已完成适配并被纳入官方兼容三方库清单,具备以下优势:
成熟的生态支持,社区资料丰富,开发成本低
强大的拦截器机制,便于统一处理请求、响应和错误
支持 FormData、文件上传下载、取消请求等复杂场景
跨平台稳定性经过大量项目验证,适配鸿蒙无额外适配成本
本文将从项目配置、权限声明、代码封装到设备运行验证,带你完整实现鸿蒙 Flutter 网络请求功能。
二、项目环境与依赖配置
2.1 环境准备
DevEco Studio 已安装 OpenHarmony SDK 与 Flutter for OpenHarmony 插件
已创建 Flutter for OpenHarmony 项目
鸿蒙模拟器 / 真机设备已连接并可正常运行
2.2 pubspec.yaml 依赖配置
打开项目根目录下的 pubspec.yaml 文件,添加 dio 依赖:

name: oh_flutter_network_demo
description: Flutter for OpenHarmony dio 网络请求示例
version: 1.0.0+1

environment:
  sdk: '>=3.0.0 <4.0.0'
  flutter: ">=3.10.0"

dependencies:
  flutter:
    sdk: flutter
  dio: ^5.5.0 # 适配 OpenHarmony 的 dio 稳定版本

dev_dependencies:
  flutter_test:
    sdk: flutter
  flutter_lints: ^3.0.0

配置完成后,执行以下命令拉取依赖:

flutter pub get

等待依赖安装完成,确保终端输出无报错,项目根目录生成 pubspec.lock 文件即表示依赖配置成功。
三、鸿蒙平台网络权限配置
OpenHarmony 对网络访问有严格的权限管控,必须在 module.json5 中声明网络权限,否则请求会被系统拦截。
3.1 找到权限配置文件
在项目目录中打开:entry/src/main/module.json5
3.2 添加网络权限
在文件中添加 requestPermissions 节点,声明网络访问权限:

{
  "module": {
    "name": "entry",
    "type": "entry",
    "description": "$string:module_desc",
    "mainElement": "EntryAbility",
    "deviceTypes": ["phone", "tablet"],
    "deliveryWithInstall": true,
    "installationFree": false,
    "pages": "$profile:main_pages",
    "abilities": [
      {
        "name": "EntryAbility",
        "srcEntry": "./ets/entryability/EntryAbility.ets",
        "description": "$string:EntryAbility_desc",
        "label": "$string:EntryAbility_label",
        "startWindowIcon": "$media:startIcon",
        "startWindowBackground": "$color:start_window_background",
        "exported": true,
        "skills": [
          {
            "entities": ["entity.system.home"],
            "actions": ["action.system.home"]
          }
        ]
      }
    ],
    "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET",
        "reason": "用于访问网络数据,实现跨平台网络请求功能",
        "usedScene": {
          "abilities": ["EntryAbility"],
          "when": "inuse"
        }
      }
    ]
  }
}

⚠️ 注意:权限声明后需同步项目配置,确保鸿蒙设备能正常识别权限配置。
四、dio 网络请求工具封装
为了便于项目维护,我们将 dio 进行全局封装,统一管理请求配置、拦截器和错误处理。
4.1 创建 HttpUtils 工具类
新建 lib/utils/http_utils.dart 文件,编写以下代码:

import 'package:dio/dio.dart';

class HttpUtils {
  // 单例模式
  static final HttpUtils _instance = HttpUtils._internal();
  factory HttpUtils() => _instance;
  late Dio dio;

  HttpUtils._internal() {
    // 基础配置
    BaseOptions options = BaseOptions(
      baseUrl: "https://jsonplaceholder.typicode.com", // 测试接口地址
      connectTimeout: const Duration(seconds: 10),
      receiveTimeout: const Duration(seconds: 10),
      headers: {
        'Content-Type': 'application/json; charset=utf-8',
      },
    );
    dio = Dio(options);

    // 添加请求拦截器
    dio.interceptors.add(InterceptorsWrapper(
      onRequest: (options, handler) {
        print("请求地址:${options.uri}");
        return handler.next(options);
      },
      onResponse: (response, handler) {
        print("响应数据:${response.data}");
        return handler.next(response);
      },
      onError: (DioException e, handler) {
        print("请求错误:${e.message}");
        return handler.next(e);
      },
    ));
  }

  /// GET 请求
  Future get(String path, {Map<String, dynamic>? params}) async {
    try {
      Response response = await dio.get(path, queryParameters: params);
      return response.data;
    } catch (e) {
      rethrow;
    }
  }

  /// POST 请求
  Future post(String path, {dynamic data}) async {
    try {
      Response response = await dio.post(path, data: data);
      return response.data;
    } catch (e) {
      rethrow;
    }
  }
}

五、实战:数据列表请求与展示
接下来我们实现一个完整的页面,从网络请求获取数据并渲染成列表,验证功能的可行性。
5.1 编写页面代码
修改 lib/main.dart 文件,替换为以下代码:

import 'package:flutter/material.dart';
import 'utils/http_utils.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter 鸿蒙网络请求示例',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: const DataListPage(),
    );
  }
}

class DataListPage extends StatefulWidget {
  const DataListPage({super.key});

  @override
  State<DataListPage> createState() => _DataListPageState();
}

class _DataListPageState extends State<DataListPage> {
  List<dynamic> dataList = [];
  bool isLoading = true;
  String errorMsg = "";

  @override
  void initState() {
    super.initState();
    fetchData();
  }

  /// 发起网络请求获取数据
  Future<void> fetchData() async {
    try {
      setState(() {
        isLoading = true;
        errorMsg = "";
      });
      // 调用 GET 请求获取测试数据
      var data = await HttpUtils().get("/posts");
      setState(() {
        dataList = data;
        isLoading = false;
      });
    } catch (e) {
      setState(() {
        isLoading = false;
        errorMsg = "请求失败:${e.toString()}";
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("鸿蒙 Flutter 数据列表")),
      body: buildBody(),
    );
  }

  Widget buildBody() {
    if (isLoading) {
      return const Center(child: CircularProgressIndicator());
    }
    if (errorMsg.isNotEmpty) {
      return Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(errorMsg, style: const TextStyle(color: Colors.red)),
            const SizedBox(height: 16),
            ElevatedButton(
              onPressed: fetchData,
              child: const Text("重新请求"),
            ),
          ],
        ),
      );
    }
    return ListView.builder(
      itemCount: dataList.length,
      itemBuilder: (context, index) {
        final item = dataList[index];
        return ListTile(
          title: Text(item["title"], maxLines: 1, overflow: TextOverflow.ellipsis),
          subtitle: Text(item["body"], maxLines: 2, overflow: TextOverflow.ellipsis),
        );
      },
    );
  }
}

六、鸿蒙设备运行与验证
6.1 启动应用
连接鸿蒙模拟器或真机设备,确保设备处于运行状态
在 DevEco Studio 中点击右上角的「运行」按钮,选择目标设备启动应用
6.2 功能验证
应用启动后,会依次执行以下流程:
显示加载动画,正在发起网络请求
请求成功后,渲染 100 条测试数据的列表,每条数据包含标题和内容
若请求失败,显示错误信息并提供「重新请求」按钮,方便排查网络问题
6.3 运行效果截图验证
运行实例
七、常见问题与解决方案
7.1 依赖拉取失败
问题描述:执行 flutter pub get 时,提示 dio 依赖无法找到或版本不兼容
解决方案:
检查 Flutter SDK 版本是否符合 pubspec.yaml 中 environment 的要求
确认 dio 版本为 OpenHarmony 兼容版本,推荐使用 ^5.5.0 稳定版
切换国内镜像源,解决网络问题导致的依赖拉取失败
7.2 网络请求一直失败
问题描述:应用运行后,始终显示请求失败,错误信息为网络异常
解决方案:
检查 module.json5 中是否正确声明了 ohos.permission.INTERNET 权限
验证设备网络是否正常,可通过浏览器访问测试接口确认网络连通性
检查 dio 的 baseUrl 配置是否正确,接口地址是否支持跨域访问
7.3 列表数据不渲染
问题描述:请求成功但列表为空,或数据未显示
解决方案:
确认请求返回的数据格式是否与列表渲染代码匹配
检查 setState 是否正确调用,确保数据更新后 UI 能重新渲染
通过 IDE 日志面板查看请求响应数据,确认数据解析是否正确
八、总结与拓展
本文完整实现了 Flutter for OpenHarmony 平台下,基于 dio 库的网络请求功能,包括依赖配置、权限声明、工具封装、页面实现与设备验证。通过这个示例,我们可以看到:
dio 库在鸿蒙平台具备良好的兼容性和稳定性,可直接用于生产项目
鸿蒙平台的权限声明是网络请求正常运行的关键,需严格按照规范配置
统一的工具封装能大幅提升项目的可维护性,便于后续扩展其他网络功能
后续可以基于此方案,拓展实现文件上传下载、请求重试、缓存处理、错误日志上报等更复杂的业务场景,为鸿蒙 Flutter 应用提供完整的网络解决方案。

Logo

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

更多推荐