Flutter 集成三方库开发鸿蒙 6.0+(API 20+)跨端天气应用

欢迎访问开源鸿蒙 PC 开发者社区(https://harmonypc.csdn.net/)。


摘要

本文面向初学者,完整演示如何使用 Flutter + 三方库dioprovider)在 鸿蒙 6.0+(API 20+) 跨端开发一个天气查询应用:输入城市 → 请求 HTTPS 接口 → 展示当前温度、天气、湿度;说明环境变量配置、AtomGit 托管规范、可复现的截图。***

强烈建议先看我这篇环境配置文章再来做!https://blog.csdn.net/2401_83346278/article/details/160399376?sharetype=blogdetail&sharerId=160399376&sharerefer=PC&sharesource=2401_83346278&spm=1011.2480.3001.8118


关键词:Flutter;鸿蒙;HarmonyOS 6;dio;Provider;跨端;天气

以我本人本机环境为例!注意把文中出现的文件地址都换成你自己的文件地址!!!

一、成品预览(你将完成什么)

启动 App 后:

  • 输入一个城市名(或默认 “Beijing”)
  • 点击查询,展示:城市、温度、天气文字、湿度
  • 请求中显示 Loading,失败显示错误文案
  • UI 使用 Material 3,适配鸿蒙侧运行

「HarmonyOS 真机 Flutter 天气应用首页」(爆红是因为没用真实的api)

在这里插入图片描述


二、先决条件(环境准备)

  • Windows 10/11(64 位)
  • DevEco Studio(新版)
  • HarmonyOS SDK(API 12+,本文目标 20+)
  • Flutter for OpenHarmony 仓库(已 clone)
  • 真机或模拟器
  • 稳定网络(拉依赖、请求天气接口)

三、环境配置(一步步做)

3.1 确认 Flutter 路径

以你当前机器示例,仓库根目录:D:\code_flutter

在 PowerShell 执行:

where flutter
flutter --version
flutter doctor -v

判断标准:

  • where flutter 第一条必须是 D:\code_flutter\bin\flutter.bat或者D:\code_flutter\bin\flutter
  • 否则调整 Path 优先级

3.2 配置用户环境变量

新增/编辑:

  • FLUTTER_HOME = D:\code_flutter
  • Path 追加:%FLUTTER_HOME%\bin
  • 重开终端再验证

3.3 鸿蒙 SDK(DevEco 内安装)

在 DevEco 的 SDK 管理中勾选并安装:

  • API 20+
  • ArkTS 工具链
  • Build Tools / Command Line Tools
  • Emulator(需要模拟器时)

3.4 设备与签名

  • 真机:开启开发者模式 + USB 调试
  • 模拟器:Device Manager 创建并启动
  • 签名:首次 Run 到真机前,先在 DevEco 做一次 Debug 签名配置(任意项目都需要)

四、创建 Flutter 工程

flutter create weather_ohos
cd weather_ohos

若该分支提供 flutter create --template=ohos 或等价指令,请以仓库 README 为准。

目录关键点:

  • lib/main.dart
  • pubspec.yaml
  • ohos/(Flutter-OHOS 集成目录,部分分支存在)

五、添加依赖(三方库)

编辑 pubspec.yaml

dependencies:
  flutter:
    sdk: flutter
  dio: ^5.4.0
  provider: ^6.1.2

然后:

flutter pub get

六、目录结构

建议:

lib/
  models/weather.dart
  service/weather_service.dart
  store/weather_store.dart
  pages/home_page.dart
  main.dart

七、核心代码

7.1 模型 lib/models/weather.dart

class Weather {
  final String city;
  final double tempC;
  final String text;
  final int humidity;

  Weather({
    required this.city,
    required this.tempC,
    required this.text,
    required this.humidity,
  });
}

7.2 服务层 lib/service/weather_service.dart

import 'package:dio/dio.dart';
import '../models/weather.dart';

class WeatherService {
  final Dio _dio = Dio(BaseOptions(
    connectTimeout: const Duration(seconds: 10),
    receiveTimeout: const Duration(seconds: 10),
  ));

  // 演示用:请用你自己的免费天气 HTTPS 接口替换
  static const _base = 'https://example.com/api/weather';

  Future<Weather> fetch(String city) async {
    final resp = await _dio.get('$_base', queryParameters: {'city': city});
    final data = resp.data as Map<String, dynamic>;
    return Weather(
      city: (data['city'] ?? city) as String,
      tempC: (data['tempC'] as num).toDouble(),
      text: data['text'] as String,
      humidity: (data['humidity'] as num).toInt(),
    );
  }
}

7.3 状态 lib/store/weather_store.dart

import 'package:flutter/foundation.dart';
import '../models/weather.dart';
import '../service/weather_service.dart';

class WeatherStore extends ChangeNotifier {
  final WeatherService _svc = WeatherService();
  Weather? weather;
  bool loading = false;
  String error = '';

  Future<void> query(String city) async {
    loading = true;
    error = '';
    notifyListeners();
    try {
      weather = await _svc.fetch(city);
    } catch (e) {
      error = '查询失败:$e';
    } finally {
      loading = false;
      notifyListeners();
    }
  }
}

7.4 入口 lib/main.dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'store/weather_store.dart';
import 'pages/home_page.dart';

void main() => runApp(const WeatherApp());

class WeatherApp extends StatelessWidget {
  const WeatherApp({super.key});
  
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (_) => WeatherStore(),
      child: MaterialApp(
        title: '天气',
        theme: ThemeData(
          colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
          useMaterial3: true,
        ),
        home: const HomePage(),
      ),
    );
  }
}

7.5 首页 lib/pages/home_page.dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../store/weather_store.dart';

class HomePage extends StatefulWidget {
  const HomePage({super.key});
  
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  final TextEditingController _ctrl = TextEditingController(text: 'Beijing');

  
  Widget build(BuildContext context) {
    final store = context.watch<WeatherStore>();
    final w = store.weather;

    return Scaffold(
      appBar: AppBar(title: const Text('天气查询')),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            TextField(
              controller: _ctrl,
              decoration: const InputDecoration(labelText: '城市'),
            ),
            const SizedBox(height: 12),
            FilledButton(
              onPressed: store.loading
                  ? null
                  : () => context.read<WeatherStore>().query(_ctrl.text.trim()),
              child: const Text('查询'),
            ),
            const SizedBox(height: 24),
            if (store.loading) const Center(child: CircularProgressIndicator()),
            if (!store.loading && store.error.isNotEmpty)
              Text(store.error, style: const TextStyle(color: Colors.red)),
            if (!store.loading && store.error.isEmpty && w != null)
              Card(
                child: Padding(
                  padding: const EdgeInsets.all(16),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Text(w.city,
                          style: const TextStyle(
                              fontSize: 22, fontWeight: FontWeight.bold)),
                      const SizedBox(height: 8),
                      Text('${w.tempC.toStringAsFixed(1)} ℃ · ${w.text}'),
                      const SizedBox(height: 4),
                      Text('湿度 ${w.humidity}%'),
                    ],
                  ),
                ),
              ),
          ],
        ),
      ),
    );
  }
}

八、编译与运行(验收)

flutter pub get
flutter run        # 调试运行到选中的设备
flutter build ohos # 鸿蒙侧构建(具体子命令名以当前 Flutter-OHOS README 为准)

DevEco 打开 ohos/ 目录 → 配置签名 → 连接真机/模拟器 → Run。


九、图例与 ALT(投稿规范)

这是在chrome中运行本flutter项目的图片
在这里插入图片描述
这是在devecostudio中运行的结果(文章开头的图片)在这里插入图片描述


十、常见问题(Flutter + 鸿蒙)

  • flutter 命令指向不是你 clone 的仓库:调整 Path 顺序
  • 真机安装失败:先完成 Debug 签名
  • 请求失败:换为可用 HTTPS 测试接口(不要 HTTP 明文)
  • flutter build ohos 报错:以当前 Flutter-OHOS 分支 README 为准

十一、避免混淆(初学者必看)

现象 实际原因
页面是「数据清单列表」且来自 jsonplaceholder 跑成 ArkTS 网络示例,不是 Flutter 天气工程
页面是天气卡片 正确:Flutter 天气应用

一句话区分:ArkTS 示例入口是 pages/Index.ets,Flutter 工程入口是 lib/main.dart


十二、托管与投稿

  • 代码平台:AtomGit https://atomgit.com
  • 源码地址:(发布后替换为你的 AtomGit 仓库 URL)
  • 必备素材:运行截图、版本信息(DevEco、API、设备型号)

十三、结语

以 Flutter + dio + provider 三件套开发鸿蒙天气应用,步骤清晰、可复现。后续可扩展为多城市收藏、历史查询、图表展示(引入 fl_chart 等库),皆属 三方库 集成范畴。
|
| 页面是天气卡片 | 正确:Flutter 天气应用 |

一句话区分:ArkTS 示例入口是 pages/Index.ets,Flutter 工程入口是 lib/main.dart


十二、托管与投稿

  • 代码平台:AtomGit https://atomgit.com
  • 源码地址:(发布后替换为你的 AtomGit 仓库 URL)
  • 必备素材:运行截图、版本信息(DevEco、API、设备型号)

十三、结语

以 Flutter + dio + provider 三件套开发鸿蒙天气应用,步骤清晰、可复现。后续可扩展为多城市收藏、历史查询、图表展示(引入 fl_chart 等库),皆属 三方库 集成范畴。强烈建议先看我的环境配置文章再来做!https://blog.csdn.net/2401_83346278/article/details/160399376?sharetype=blogdetail&sharerId=160399376&sharerefer=PC&sharesource=2401_83346278&spm=1011.2480.3001.8118

Logo

一站式 AI 云服务平台

更多推荐