Flutter 跨平台实战:鸿蒙 6.0 (API20) 集成三方库开发天气查询应用
Flutter 跨平台实战:鸿蒙 6.0 (API20) 集成三方库开发天气查询应用
前言
对于鸿蒙开发者入门 Flutter 跨平台开发,借助成熟三方库可以快速实现复杂功能。本文以跨平台天气查询应用为案例,在鸿蒙 6.0 (API20) 环境下,集成网络请求、JSON 解析、位置获取、UI 美化三方库,完成可落地的跨端应用。
一、环境配置要求
Flutter 3.16 及以上版本
DevEco Studio 搭载鸿蒙 6.0 (API20) 模拟器 / 真机
开启网络权限、定位权限
代码编辑器:Android Studio / VS Code
二、项目创建与鸿蒙适配配置
1. 创建 Flutter 项目
flutter create flutter\_harmony\_weather cd flutter\_harmony\_weather2. 鸿蒙 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:   flutter:   sdk: flutter   \# 网络请求三方库   dio: ^5.4.0   \# 定位获取三方库   geolocator: ^10.1.0   \# 加载状态提示库   flutter\_easyloading: ^3.0.5   \# 图标美化库   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 {   final String city; // 城市   final String temp; // 温度   final String weather; // 天气状况   final String wind; // 风力   final String humidity; // 湿度   WeatherModel({   required this.city,   required this.temp,   required this.weather,   required this.wind,   required this.humidity,   });   // 解析JSON数据,此处适配简易天气接口   factory WeatherModel.fromJson(Map\<String, dynamic> json) {   return WeatherModel(   city: json\['city'] ?? '未知城市',   temp: json\['temp'] ?? 'N/A',   weather: json\['weather'] ?? '未知天气',   wind: json\['wind'] ?? 'N/A',   humidity: json\['humidity'] ?? 'N/A',   );   } }2. 网络请求工具:utils/api_util.dart
基于 dio 三方库实现网络请求,封装获取天气方法
import 'package:dio/dio.dart'; import '../models/weather\_model.dart'; class ApiUtil {   final Dio \_dio = Dio();   /// 获取指定城市天气   Future\<WeatherModel> getWeather(String city) async {   try {   // 免费天气接口,可自行替换为正规天气API   final response = await \_dio.get(   'https://api.example.com/weather',   queryParameters: {'city': city},   );   return WeatherModel.fromJson(response.data);   } catch (e) {   rethrow;   }   } }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 {   const WeatherPage({super.key});   @override   State\<WeatherPage> createState() => \_WeatherPageState(); } class \_WeatherPageState extends State\<WeatherPage> {   final ApiUtil \_apiUtil = ApiUtil();   WeatherModel? \_weatherModel;   final TextEditingController \_cityController = TextEditingController();   @override   void initState() {   super.initState();   // 初始化加载提示组件   EasyLoading.init();   }   /// 获取定位权限并定位当前城市   Future\<void> getLocationWeather() async {   EasyLoading.show(status: '获取定位中...');   // 检查定位权限   bool serviceEnabled = await Geolocator.isLocationServiceEnabled();   if (!serviceEnabled) {   EasyLoading.showError('定位服务未开启');   return;   }   LocationPermission permission = await Geolocator.checkPermission();   if (permission == LocationPermission.denied) {   permission = await Geolocator.requestPermission();   if (permission == LocationPermission.denied) {   EasyLoading.showError('定位权限被拒绝');   return;   }   }   if (permission == LocationPermission.deniedForever) {   EasyLoading.showError('权限永久拒绝,无法定位');   return;   }   // 获取定位坐标,实际开发可通过经纬度获取城市   Position position = await Geolocator.getCurrentPosition();   await getWeatherData('北京');   }   /// 获取天气数据   Future\<void> getWeatherData(String city) async {   if (city.isEmpty) {   EasyLoading.showInfo('请输入城市名称');   return;   }   EasyLoading.show(status: '加载天气中...');   try {   final data = await \_apiUtil.getWeather(city);   setState(() {   \_weatherModel = data;   });   EasyLoading.showSuccess('加载成功');   } catch (e) {   EasyLoading.showError('获取天气失败:\${e.toString()}');   }   }   @override   Widget build(BuildContext context) {   return Scaffold(   appBar: AppBar(   title: const Text('Flutter鸿蒙天气查询'),   centerTitle: true,   ),   body: SingleChildScrollView(   padding: const EdgeInsets.all(20),   child: Column(   children: \[   // 城市输入框   TextField(   controller: \_cityController,   decoration: InputDecoration(   hintText: '请输入城市名称',   suffixIcon: IconButton(   icon: const Icon(Icons.search),   onPressed: () {   getWeatherData(\_cityController.text.trim());   },   ),   border: const OutlineInputBorder(),   ),   ),   const SizedBox(height: 15),   // 定位获取天气按钮   ElevatedButton.icon(   onPressed: getLocationWeather,   icon: const FaIcon(FontAwesomeIcons.locationCrosshairs),   label: const Text('定位获取当前天气'),   ),   const SizedBox(height: 30),   // 天气信息展示区域   if (\_weatherModel != null)   Card(   elevation: 5,   shape: RoundedRectangleBorder(   borderRadius: BorderRadius.circular(15),   ),   child: Padding(   padding: const EdgeInsets.all(25),   child: Column(   children: \[   Text(   \_weatherModel!.city,   style: const TextStyle(   fontSize: 24, fontWeight: FontWeight.bold),   ),   const SizedBox(height: 20),   Text(   '\${\_weatherModel!.temp}℃',   style: const TextStyle(fontSize: 40),   ),   const SizedBox(height: 10),   Text(   \_weatherModel!.weather,   style: const TextStyle(fontSize: 20),   ),   const Divider(height: 30),   Row(   mainAxisAlignment: MainAxisAlignment.spaceAround,   children: \[   \_weatherItem(   FontAwesomeIcons.wind,   '风力',   \_weatherModel!.wind,   ),   \_weatherItem(   FontAwesomeIcons.droplet,   '湿度',   \_weatherModel!.humidity,   ),   ],   ),   ],   ),   ),   ),   ],   ),   ),   );   }   /// 天气信息子项   Widget \_weatherItem(IconData icon, String title, String value) {   return Column(   children: \[   FaIcon(icon, size: 25),   const SizedBox(height: 5),   Text(title),   Text(value),   ],   );   } }4. 应用入口:main.dart
全局配置加载提示,挂载主页面
import 'package:flutter/material.dart'; import 'package:flutter\_easyloading/flutter\_easyloading.dart'; import 'pages/weather\_page.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 WeatherPage(),   // 配置加载提示三方库   builder: EasyLoading.init(),   debugShowCheckedModeBanner: false,   );   } }六、鸿蒙 6.0 (API20) 运行步骤
启动 DevEco Studio 中鸿蒙 6.0 API20 模拟器
连接设备后执行运行命令
flutter run授予应用定位、网络权限
输入城市或使用定位功能获取天气信息
七、三方库在鸿蒙平台的使用说明
dio:网络请求无兼容问题,可正常请求天气接口
geolocator:适配鸿蒙定位服务,可成功获取设备位置
flutter_easyloading:加载弹窗在鸿蒙设备渲染正常
font_awesome_flutter:矢量图标完美展示
八、开发注意事项
正式开发需替换为合规商用天气 API,替换接口地址即可
鸿蒙设备需手动开启应用权限,否则定位功能无法使用
网络请求需处理异常情况,提升应用稳定性
九、总结
本项目完整展示了Flutter 结合三方库开发鸿蒙 6.0 应用的全流程,贴合实际开发场景。借助 Flutter 跨平台特性,一套代码可同时运行在 Android、iOS、鸿蒙设备上,大幅降低鸿蒙应用开发成本。
