Flutter 跨平台实战:鸿蒙 6.0 (API20) 集成三方库开发天气查询应用

前言

对于鸿蒙开发者入门 Flutter 跨平台开发,借助成熟三方库可以快速实现复杂功能。本文以跨平台天气查询应用为案例,在鸿蒙 6.0 (API20) 环境下,集成网络请求、JSON 解析、位置获取、UI 美化三方库,完成可落地的跨端应用。

一、环境配置要求

  1. Flutter 3.16 及以上版本

  2. DevEco Studio 搭载鸿蒙 6.0 (API20) 模拟器 / 真机

  3. 开启网络权限、定位权限

  4. 代码编辑器:Android Studio / VS Code

二、项目创建与鸿蒙适配配置

1. 创建 Flutter 项目

flutter create flutter\_harmony\_weather

cd flutter\_harmony\_weather

2. 鸿蒙 6.0 适配配置

修改android/app/build.gradle,匹配鸿蒙底层适配要求

android {

    compileSdkVersion 33

    defaultConfig {

        applicationId "com.example.flutter\_harmony\_weather"

        minSdkVersion 21

        targetSdkVersion 33

        versionCode 1

        versionName "1.0"

    }

}

3. 权限配置

打开android/app/src/main/AndroidManifest.xml,添加权限

\<!-- 网络权限 -->

\<uses-permission android:name="android.permission.INTERNET"/>

\<!-- 定位权限 -->

\<uses-permission android:name="android.permission.ACCESS\_FINE\_LOCATION"/>

\<uses-permission android:name="android.permission.ACCESS\_COARSE\_LOCATION"/>

三、引入兼容鸿蒙的三方库

本次选用在鸿蒙 6.0 上运行稳定的常用库,在pubspec.yaml中添加依赖

dependencies:

&#x20; flutter:

&#x20;   sdk: flutter

&#x20; \# 网络请求三方库

&#x20; dio: ^5.4.0

&#x20; \# 定位获取三方库

&#x20; geolocator: ^10.1.0

&#x20; \# 加载状态提示库

&#x20; flutter\_easyloading: ^3.0.5

&#x20; \# 图标美化库

&#x20; font\_awesome\_flutter: ^10.6.0

执行依赖安装命令

flutter pub get

四、项目结构规划

lib/

├── main.dart                 # 应用入口

├── models/weather\_model.dart # 天气数据模型

├── utils/api\_util.dart       # 网络请求工具

├── pages/weather\_page.dart   # 主页面

五、代码实现

1. 天气数据模型:models/weather_model.dart

解析接口返回的 JSON 数据,结构化存储天气信息

/// 天气数据模型

class WeatherModel {

&#x20; final String city; // 城市

&#x20; final String temp; // 温度

&#x20; final String weather; // 天气状况

&#x20; final String wind; // 风力

&#x20; final String humidity; // 湿度

&#x20; WeatherModel({

&#x20;   required this.city,

&#x20;   required this.temp,

&#x20;   required this.weather,

&#x20;   required this.wind,

&#x20;   required this.humidity,

&#x20; });

&#x20; // 解析JSON数据,此处适配简易天气接口

&#x20; factory WeatherModel.fromJson(Map\<String, dynamic> json) {

&#x20;   return WeatherModel(

&#x20;     city: json\['city'] ?? '未知城市',

&#x20;     temp: json\['temp'] ?? 'N/A',

&#x20;     weather: json\['weather'] ?? '未知天气',

&#x20;     wind: json\['wind'] ?? 'N/A',

&#x20;     humidity: json\['humidity'] ?? 'N/A',

&#x20;   );

&#x20; }

}

2. 网络请求工具:utils/api_util.dart

基于 dio 三方库实现网络请求,封装获取天气方法

import 'package:dio/dio.dart';

import '../models/weather\_model.dart';

class ApiUtil {

&#x20; final Dio \_dio = Dio();

&#x20; /// 获取指定城市天气

&#x20; Future\<WeatherModel> getWeather(String city) async {

&#x20;   try {

&#x20;     // 免费天气接口,可自行替换为正规天气API

&#x20;     final response = await \_dio.get(

&#x20;       'https://api.example.com/weather',

&#x20;       queryParameters: {'city': city},

&#x20;     );

&#x20;     return WeatherModel.fromJson(response.data);

&#x20;   } catch (e) {

&#x20;     rethrow;

&#x20;   }

&#x20; }

}

3. 主页面实现:pages/weather_page.dart

集成定位、网络请求、加载提示三方库,实现核心交互

import 'package:flutter/material.dart';

import 'package:geolocator/geolocator.dart';

import 'package:flutter\_easyloading/flutter\_easyloading.dart';

import 'package:font\_awesome\_flutter/font\_awesome\_flutter.dart';

import '../utils/api\_util.dart';

import '../models/weather\_model.dart';

class WeatherPage extends StatefulWidget {

&#x20; const WeatherPage({super.key});

&#x20; @override

&#x20; State\<WeatherPage> createState() => \_WeatherPageState();

}

class \_WeatherPageState extends State\<WeatherPage> {

&#x20; final ApiUtil \_apiUtil = ApiUtil();

&#x20; WeatherModel? \_weatherModel;

&#x20; final TextEditingController \_cityController = TextEditingController();

&#x20; @override

&#x20; void initState() {

&#x20;   super.initState();

&#x20;   // 初始化加载提示组件

&#x20;   EasyLoading.init();

&#x20; }

&#x20; /// 获取定位权限并定位当前城市

&#x20; Future\<void> getLocationWeather() async {

&#x20;   EasyLoading.show(status: '获取定位中...');

&#x20;   // 检查定位权限

&#x20;   bool serviceEnabled = await Geolocator.isLocationServiceEnabled();

&#x20;   if (!serviceEnabled) {

&#x20;     EasyLoading.showError('定位服务未开启');

&#x20;     return;

&#x20;   }

&#x20;   LocationPermission permission = await Geolocator.checkPermission();

&#x20;   if (permission == LocationPermission.denied) {

&#x20;     permission = await Geolocator.requestPermission();

&#x20;     if (permission == LocationPermission.denied) {

&#x20;       EasyLoading.showError('定位权限被拒绝');

&#x20;       return;

&#x20;     }

&#x20;   }

&#x20;   if (permission == LocationPermission.deniedForever) {

&#x20;     EasyLoading.showError('权限永久拒绝,无法定位');

&#x20;     return;

&#x20;   }

&#x20;   // 获取定位坐标,实际开发可通过经纬度获取城市

&#x20;   Position position = await Geolocator.getCurrentPosition();

&#x20;   await getWeatherData('北京');

&#x20; }

&#x20; /// 获取天气数据

&#x20; Future\<void> getWeatherData(String city) async {

&#x20;   if (city.isEmpty) {

&#x20;     EasyLoading.showInfo('请输入城市名称');

&#x20;     return;

&#x20;   }

&#x20;   EasyLoading.show(status: '加载天气中...');

&#x20;   try {

&#x20;     final data = await \_apiUtil.getWeather(city);

&#x20;     setState(() {

&#x20;       \_weatherModel = data;

&#x20;     });

&#x20;     EasyLoading.showSuccess('加载成功');

&#x20;   } catch (e) {

&#x20;     EasyLoading.showError('获取天气失败:\${e.toString()}');

&#x20;   }

&#x20; }

&#x20; @override

&#x20; Widget build(BuildContext context) {

&#x20;   return Scaffold(

&#x20;     appBar: AppBar(

&#x20;       title: const Text('Flutter鸿蒙天气查询'),

&#x20;       centerTitle: true,

&#x20;     ),

&#x20;     body: SingleChildScrollView(

&#x20;       padding: const EdgeInsets.all(20),

&#x20;       child: Column(

&#x20;         children: \[

&#x20;           // 城市输入框

&#x20;           TextField(

&#x20;             controller: \_cityController,

&#x20;             decoration: InputDecoration(

&#x20;               hintText: '请输入城市名称',

&#x20;               suffixIcon: IconButton(

&#x20;                 icon: const Icon(Icons.search),

&#x20;                 onPressed: () {

&#x20;                   getWeatherData(\_cityController.text.trim());

&#x20;                 },

&#x20;               ),

&#x20;               border: const OutlineInputBorder(),

&#x20;             ),

&#x20;           ),

&#x20;           const SizedBox(height: 15),

&#x20;           // 定位获取天气按钮

&#x20;           ElevatedButton.icon(

&#x20;             onPressed: getLocationWeather,

&#x20;             icon: const FaIcon(FontAwesomeIcons.locationCrosshairs),

&#x20;             label: const Text('定位获取当前天气'),

&#x20;           ),

&#x20;           const SizedBox(height: 30),

&#x20;           // 天气信息展示区域

&#x20;           if (\_weatherModel != null)

&#x20;             Card(

&#x20;               elevation: 5,

&#x20;               shape: RoundedRectangleBorder(

&#x20;                 borderRadius: BorderRadius.circular(15),

&#x20;               ),

&#x20;               child: Padding(

&#x20;                 padding: const EdgeInsets.all(25),

&#x20;                 child: Column(

&#x20;                   children: \[

&#x20;                     Text(

&#x20;                       \_weatherModel!.city,

&#x20;                       style: const TextStyle(

&#x20;                         fontSize: 24, fontWeight: FontWeight.bold),

&#x20;                     ),

&#x20;                     const SizedBox(height: 20),

&#x20;                     Text(

&#x20;                       '\${\_weatherModel!.temp}℃',

&#x20;                       style: const TextStyle(fontSize: 40),

&#x20;                     ),

&#x20;                     const SizedBox(height: 10),

&#x20;                     Text(

&#x20;                       \_weatherModel!.weather,

&#x20;                       style: const TextStyle(fontSize: 20),

&#x20;                     ),

&#x20;                     const Divider(height: 30),

&#x20;                     Row(

&#x20;                       mainAxisAlignment: MainAxisAlignment.spaceAround,

&#x20;                       children: \[

&#x20;                         \_weatherItem(

&#x20;                           FontAwesomeIcons.wind,

&#x20;                           '风力',

&#x20;                           \_weatherModel!.wind,

&#x20;                         ),

&#x20;                         \_weatherItem(

&#x20;                           FontAwesomeIcons.droplet,

&#x20;                           '湿度',

&#x20;                           \_weatherModel!.humidity,

&#x20;                         ),

&#x20;                       ],

&#x20;                     ),

&#x20;                   ],

&#x20;                 ),

&#x20;               ),

&#x20;             ),

&#x20;         ],

&#x20;       ),

&#x20;     ),

&#x20;   );

&#x20; }

&#x20; /// 天气信息子项

&#x20; Widget \_weatherItem(IconData icon, String title, String value) {

&#x20;   return Column(

&#x20;     children: \[

&#x20;       FaIcon(icon, size: 25),

&#x20;       const SizedBox(height: 5),

&#x20;       Text(title),

&#x20;       Text(value),

&#x20;     ],

&#x20;   );

&#x20; }

}

4. 应用入口:main.dart

全局配置加载提示,挂载主页面

import 'package:flutter/material.dart';

import 'package:flutter\_easyloading/flutter\_easyloading.dart';

import 'pages/weather\_page.dart';

void main() {

&#x20; runApp(const MyApp());

}

class MyApp extends StatelessWidget {

&#x20; const MyApp({super.key});

&#x20; @override

&#x20; Widget build(BuildContext context) {

&#x20;   return MaterialApp(

&#x20;     title: 'Flutter鸿蒙天气',

&#x20;     theme: ThemeData(primarySwatch: Colors.blue),

&#x20;     home: const WeatherPage(),

&#x20;     // 配置加载提示三方库

&#x20;     builder: EasyLoading.init(),

&#x20;     debugShowCheckedModeBanner: false,

&#x20;   );

&#x20; }

}

六、鸿蒙 6.0 (API20) 运行步骤

  1. 启动 DevEco Studio 中鸿蒙 6.0 API20 模拟器

  2. 连接设备后执行运行命令

flutter run
  1. 授予应用定位、网络权限

  2. 输入城市或使用定位功能获取天气信息

七、三方库在鸿蒙平台的使用说明

  1. dio:网络请求无兼容问题,可正常请求天气接口

  2. geolocator:适配鸿蒙定位服务,可成功获取设备位置

  3. flutter_easyloading:加载弹窗在鸿蒙设备渲染正常

  4. font_awesome_flutter:矢量图标完美展示

八、开发注意事项

  1. 正式开发需替换为合规商用天气 API,替换接口地址即可

  2. 鸿蒙设备需手动开启应用权限,否则定位功能无法使用

  3. 网络请求需处理异常情况,提升应用稳定性

九、总结

本项目完整展示了Flutter 结合三方库开发鸿蒙 6.0 应用的全流程,贴合实际开发场景。借助 Flutter 跨平台特性,一套代码可同时运行在 Android、iOS、鸿蒙设备上,大幅降低鸿蒙应用开发成本。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐