Flutter跨平台实战:鸿蒙6.0(API20)集成三方库开发企业级天气查询应用
鸿蒙 6.0 适配核心、权限显式声明、包名一致性三方库选型原则:优先选择 “支持 Android 13+”“维护活跃” 的库,避免小众库开发流程规范:分层架构 → 模型定义 → 工具封装 → UI 实现 → 鸿蒙适配 → 调试上线关键技术点Dio 拦截器处理鸿蒙网络错误Geolocator 适配鸿蒙定位权限Provider 实现跨页面数据共享JSON 序列化提升解析效率。
Flutter 跨平台实战:鸿蒙 6.0 (API20) 集成三方库开发企业级天气查询应用
前言
作为鸿蒙开发者入门 Flutter 跨端开发,三方库选型与鸿蒙兼容性适配是核心痛点。本文以企业级天气查询应用为实战载体,深度整合网络请求、定位服务、状态管理、UI 组件四大类高频三方库,针对鸿蒙 6.0 (API20) 系统特性优化配置,从环境搭建到上线部署全流程拆解,包含完整错误处理、权限动态申请、接口容错、鸿蒙特有适配方案,助力新手快速掌握 “Flutter + 三方库 + 鸿蒙” 开发范式,产出可落地的生产级应用。
一、技术栈选型与核心优势(鸿蒙 6.0 适配版)
| 技术模块 | 选用三方库 | 版本号 | 鸿蒙 6.0 适配优势 |
|---|---|---|---|
| 网络请求 | dio | ^5.4.3+1 | 支持鸿蒙 HTTPS/HTTP 请求,拦截器稳定 |
| 定位服务 | geolocator | ^10.1.1 | 兼容鸿蒙原生定位 API,权限回调正常 |
| 加载状态 | flutter_easyloading | ^3.0.5 | 鸿蒙原生弹窗渲染,无卡顿闪屏 |
| 图标组件 | font_awesome_flutter | ^10.7.0 | 矢量图标适配鸿蒙多分辨率屏幕 |
| 状态管理 | provider | ^6.1.1 | 轻量无侵入,适配鸿蒙页面生命周期 |
| JSON 解析 | json_serializable | ^6.7.1 | 代码生成式解析,性能优于手动解析 |
选型依据:所有库均经过鸿蒙 6.0 (API20) 真机 / 模拟器双重验证,无兼容性报错,且为 Flutter 生态 StarsTop10 库,文档完善。
二、环境搭建与鸿蒙专属配置(精准适配 API20)
1. 基础环境要求(必选)
-
Flutter SDK:3.19.0+(稳定版,修复鸿蒙部分渲染 bug)
-
DevEco Studio:4.1.3.300+(支持鸿蒙 6.0 模拟器创建)
-
鸿蒙设备:API20(鸿蒙 6.0)模拟器 / 真机(需开启开发者模式)
-
依赖工具:Android SDK Build-Tools 33.0.2+(鸿蒙底层依赖)
2. 环境校验命令(确保鸿蒙适配)
\# 检查Flutter环境(重点看Android/HarmonyOS工具链)
flutter doctor -v
\# 验证鸿蒙设备连接(需提前启动模拟器/连接真机)
flutter devices
预期结果:鸿蒙设备显示为 “HarmonyOS” 类型,无 “unauthorized” 权限提示。
3. 项目创建与鸿蒙适配配置
步骤 1:创建 Flutter 项目(指定 Android 包名,便于鸿蒙上架)
flutter create --org com.harmony.flutter --project-name weather\_app flutter\_harmony\_weather
cd flutter\_harmony\_weather
步骤 2:Android 层鸿蒙适配(关键配置)
修改android/app/build.gradle,添加鸿蒙特有配置:
android {
  compileSdkVersion 33
  namespace "com.harmony.flutter.weather\_app" // 与鸿蒙应用包名一致
  defaultConfig {
  applicationId "com.harmony.flutter.weather\_app"
  minSdkVersion 21 // 兼容鸿蒙API20底层
  targetSdkVersion 33 // 匹配鸿蒙6.0系统版本
  versionCode 1
  versionName "1.0.0"
  // 鸿蒙应用权限申请配置(必须添加)
  manifestPlaceholders = \[
  "HARMONYOS\_PERMISSION\_LOCATION": "true",
  "HARMONYOS\_PERMISSION\_INTERNET": "true"
  ]
  }
  // 鸿蒙6.0混淆配置(避免三方库被混淆)
  buildTypes {
  release {
  minifyEnabled true
  proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
  // 鸿蒙专属混淆规则
  consumerProguardFiles 'consumer-rules.pro'
  }
  }
}
步骤 3:鸿蒙权限配置(AndroidManifest.xml)
打开android/app/src/main/AndroidManifest.xml,添加鸿蒙动态权限:
网络权限(鸿蒙6.0默认开启,但需显式声明) -->
\<uses-permission android:name="android.permission.INTERNET" />
定位权限(鸿蒙6.0需同时声明精确+模糊定位) -->
\<uses-permission android:name="android.permission.ACCESS\_FINE\_LOCATION" />
:name="android.permission.ACCESS\_COARSE\_LOCATION" />
鸿蒙后台定位权限(可选,根据业务需求添加) -->
 android:name="android.permission.ACCESS\_BACKGROUND\_LOCATION" />
鸿蒙应用声明(必须添加,否则无法在鸿蒙设备安装) -->
  android:name="\${applicationName}"
  android:icon="@mipmap/ic\_launcher"
  android:label="Flutter鸿蒙天气"
  android:supportsRtl="true"
  android:theme="@style/Theme.AppCompat.Light.NoActionBar">
  鸿蒙6.0兼容配置 -->
   
  android:name="com.huawei.hms.client.appid"
  android:value="appid=你的鸿蒙开发者APPID" /> 开发者平台获取 -->
\</application>
4. 三方库依赖集成(精准版本控制)
打开pubspec.yaml,添加依赖并指定版本(避免自动升级导致兼容问题):
name: flutter\_harmony\_weather
description: 鸿蒙6.0(API20)兼容的Flutter天气查询应用
version: 1.0.0+1
environment:
  sdk: '>=3.0.0 .0.0'
dependencies:
  flutter:
  sdk: flutter
  \# 网络请求
  dio: ^5.4.3+1
  \# 定位服务
  geolocator: ^10.1.1
  \# 加载状态
  flutter\_easyloading: ^3.0.5
  \# 图标组件
  font\_awesome\_flutter: ^10.7.0
  \# 状态管理
  provider: ^6.1.1
  \# JSON解析(代码生成)
  json\_annotation: ^4.8.1
dev\_dependencies:
  flutter\_test:
  sdk: flutter
  \# JSON解析代码生成器
  build\_runner: ^2.4.6
  json\_serializable: ^6.7.1
flutter:
  uses-material-design: true
  \# 鸿蒙图标适配(添加高分辨率图标)
  assets:
  \- assets/icons/
执行依赖安装命令,确保无报错:
flutter pub get
\# 验证依赖安装成功(可选)
flutter pub deps | grep "dio\\|geolocator"
三、项目架构设计(企业级分层方案)
采用 “MVVM + 分层架构”,便于后续维护与鸿蒙特性扩展:
lib/
├── main.dart # 应用入口(鸿蒙全局配置)
├── core/ # 核心配置
│ ├── api/ # 接口封装(dio配置)
│ │ ├── weather\_api.dart # 天气接口
│ │ └── dio\_client.dart # dio实例初始化
│ ├── constants/ # 常量定义(鸿蒙适配参数)
│ └── utils/ # 工具类(定位、权限)
├── models/ # 数据模型(JSON解析)
│ ├── weather\_model.dart # 天气数据模型
│ └── weather\_model.g.dart # 自动生成的解析代码
├── providers/ # 状态管理
│ └── weather\_provider.dart # 天气数据状态管理
└── pages/ # 页面
  └── weather\_page.dart # 主页面(UI+交互)
四、核心功能实现(带鸿蒙适配注释)
1. 数据模型:models/weather_model.dart(JSON 序列化)
采用json_serializable生成解析代码,避免手动解析错误,适配鸿蒙复杂 JSON 返回:
import 'package:json\_annotation/json\_annotation.dart';
// 生成的解析代码文件(需执行build\_runner命令)
part 'weather\_model.g.dart';
/// 天气数据模型(适配聚合数据天气API返回格式)
@JsonSerializable()
class WeatherModel {
  /// 城市名称
  @JsonKey(name: 'city')
  final String city;
  /// 实时温度(单位:℃)
  @JsonKey(name: 'realtime\_temp')
  final String temp;
  /// 天气状况(如:晴、多云)
  @JsonKey(name: 'weather')
  final String weather;
  /// 风力(如:3-4级)
  @JsonKey(name: 'wind\_power')
  final String wind;
  /// 湿度(如:60%)
  @JsonKey(name: 'humidity')
  final String humidity;
  /// 更新时间
  @JsonKey(name: 'update\_time')
  final String updateTime;
  // 构造函数(必填参数不可为空)
  WeatherModel({
  required this.city,
  required this.temp,
  required this.weather,
  required this.wind,
  required this.humidity,
  required this.updateTime,
  });
  // 从JSON解析为对象(自动生成)
  factory WeatherModel.fromJson(Map\<String, dynamic> json) =>
  \_\$WeatherModelFromJson(json);
  // 从对象转为JSON(自动生成)
  Map toJson() => \_\$WeatherModelToJson(this);
}
生成解析代码命令(终端执行):
flutter pub run build\_runner build
生成
weather_model.g.dart文件后,无需手动修改,后续模型变更重新执行命令即可。
2. 核心工具:core/api/dio_client.dart(鸿蒙网络适配)
封装 dio 实例,处理鸿蒙网络特有问题(如:HTTPS 证书校验、网络状态监听):
import 'package:dio/dio.dart';
import 'package:flutter\_easyloading/flutter\_easyloading.dart';
import '../constants/constants.dart';
/// Dio网络请求客户端(鸿蒙6.0适配版)
class DioClient {
  final Dio \_dio;
  // 单例模式(避免重复创建实例)
  DioClient.\_internal() : \_dio = Dio() {
  // 基础配置
  \_dio.options.baseUrl = Constants.WEATHER\_API\_BASE\_URL;
  \_dio.options.connectTimeout = const Duration(seconds: 10); // 鸿蒙网络超时适配
  \_dio.options.receiveTimeout = const Duration(seconds: 10);
  \_dio.options.responseType = ResponseType.json;
  // 鸿蒙HTTPS适配:忽略证书校验(开发环境,生产环境需配置证书)
  (\_dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate =
  (client) {
  client.badCertificateCallback =
  (X509Certificate cert, String host, int port) => true;
  return client;
  };
  // 请求拦截器:添加API密钥(聚合数据天气API示例)
  \_dio.interceptors.add(InterceptorsWrapper(
  onRequest: (options, handler) {
  options.queryParameters\['key'] = Constants.WEATHER\_API\_KEY;
  handler.next(options);
  },
  // 响应拦截器:统一错误处理
  onResponse: (response, handler) {
  if (response.data\['error\_code'] != 0) {
  EasyLoading.showError('接口错误:\${response.data\['reason']}');
  handler.reject(DioException(
  requestOptions: response.requestOptions,
  message: response.data\['reason'],
  ));
  } else {
  handler.next(response);
  }
  },
  // 错误拦截器:鸿蒙网络错误适配
  onError: (DioException e, handler) {
  if (e.type == DioExceptionType.connectionTimeout) {
  EasyLoading.showError('鸿蒙网络超时,请检查网络');
  } else if (e.type == DioExceptionType.connectionError) {
  EasyLoading.showError('鸿蒙网络连接失败,请开启网络权限');
  } else {
  EasyLoading.showError('请求失败:\${e.message}');
  }
  handler.next(e);
  },
  ));
  }
  // 单例实例
  static final DioClient instance = DioClient.\_internal();
  // GET请求方法
  Future get path, {
  Map\<String, dynamic>? queryParameters,
  }) async {
  final response = await \_dio.get(path, queryParameters: queryParameters);
  return response.data\['result'] as T;
  }
}
3. 接口封装:core/api/weather_api.dart(业务分离)
import 'package:flutter\_harmony\_weather/models/weather\_model.dart';
import 'dio\_client.dart';
/// 天气接口封装
class WeatherApi {
  final DioClient \_dioClient = DioClient.instance;
  /// 根据城市名称获取天气
  FutureModel> getWeatherByCity(String city) async {
  final data = await \_dioClient.get\<String, dynamic>>(
  'weather/query', // 接口路径(聚合数据示例)
  queryParameters: {'city': city},
  );
  return WeatherModel.fromJson(data);
  }
  /// 根据经纬度获取天气(鸿蒙定位后使用)
  Future getWeatherByLocation(double lat, double lon) async {
  final data = await \_dioClient.get\<Map 'weather/query',
  queryParameters: {'lat': lat, 'lon': lon},
  );
  return WeatherModel.fromJson(data);
  }
}
4. 定位工具:core/utils/location_util.dart(鸿蒙定位适配)
处理鸿蒙定位权限动态申请、定位失败重试逻辑:
import 'package:geolocator/geolocator.dart';
import 'package:flutter\_easyloading/flutter\_easyloading.dart';
/// 鸿蒙定位工具类
class LocationUtil {
  /// 检查并请求定位权限
  static Future\<bool> requestLocationPermission() async {
  // 检查定位服务是否开启(鸿蒙特有:部分设备需手动开启定位开关)
  bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
  if (!serviceEnabled) {
  EasyLoading.showError('鸿蒙定位服务未开启,请在设置中开启');
  return false;
  }
  // 检查定位权限
  LocationPermission permission = await Geolocator.checkPermission();
  if (permission == LocationPermission.denied) {
  // 请求权限(鸿蒙6.0会弹出系统权限弹窗)
  permission = await Geolocator.requestPermission();
  if (permission == LocationPermission.denied) {
  EasyLoading.showError('定位权限被拒绝,请在应用设置中允许');
  return false;
  }
  }
  // 权限永久拒绝(鸿蒙需引导用户手动开启)
  if (permission == LocationPermission.deniedForever) {
  EasyLoading.showInfo('定位权限永久拒绝,请在系统设置中手动开启');
  // 跳转鸿蒙应用权限设置页面(鸿蒙特有)
  await Geolocator.openAppSettings();
  return false;
  }
  return true;
  }
  /// 获取当前设备经纬度
  static Future getCurrentLocation() async {
  try {
  bool hasPermission = await requestLocationPermission();
  if (!hasPermission) return null;
  // 鸿蒙定位精度设置(平衡性能与精度)
  return await Geolocator.getCurrentPosition(
  desiredAccuracy: LocationAccuracy.medium,
  timeLimit: const Duration(seconds: 15), // 鸿蒙定位超时保护
  );
  } catch (e) {
  EasyLoading.showError('鸿蒙定位失败:\${e.toString()}');
  return null;
  }
  }
}
5. 状态管理:providers/weather_provider.dart(数据共享)
使用provider管理天气数据,适配鸿蒙页面重建时数据持久化:
import 'package:flutter/material.dart';
import 'package:flutter\_harmony\_weather/core/api/weather\_api.dart';
import 'package:flutter\_harmony\_weather/core/utils/location\_util.dart';
import 'package:flutter\_harmony\_weather/models/weather\_model.dart';
/// 天气状态管理类
class WeatherProvider with ChangeNotifier {
  final WeatherApi \_weatherApi = WeatherApi();
  WeatherModel? \_weatherData;
  bool \_isLoading = false;
  // 对外提供数据(只读)
  WeatherModel? get weatherData => \_weatherData;
  bool get isLoading => \_isLoading;
  /// 根据城市获取天气
  FutureByCity(String city) async {
  \_setLoading(true);
  try {
  final data = await \_weatherApi.getWeatherByCity(city);
  \_weatherData = data;
  notifyListeners(); // 通知UI更新
  } catch (e) {
  // 错误已在Dio拦截器处理,此处仅恢复状态
  } finally {
  \_setLoading(false);
  }
  }
  /// 根据定位获取天气
  FutureWeatherByLocation() async {
  \_setLoading(true);
  try {
  Position? position = await LocationUtil.getCurrentLocation();
  if (position != null) {
  final data = await \_weatherApi.getWeatherByLocation(
  position.latitude,
  position.longitude,
  );
  \_weatherData = data;
  notifyListeners();
  }
  } catch (e) {
  } finally {
  \_setLoading(false);
  }
  }
  /// 更新加载状态
  void \_setLoading(bool loading) {
  \_isLoading = loading;
  if (loading) {
  EasyLoading.show(status: '加载中...');
  } else {
  EasyLoading.dismiss();
  }
  notifyListeners();
  }
  /// 清空天气数据(退出页面时调用)
  void clearWeatherData() {
  \_weatherData = null;
  notifyListeners();
  }
}
6. 主页面:pages/weather_page.dart(鸿蒙 UI 适配)
优化鸿蒙屏幕适配、触摸反馈、权限引导,提升用户体验:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:font\_awesome\_flutter/font\_awesome\_flutter.dart';
import 'package:flutter\_harmony\_weather/providers/weather\_provider.dart';
class WeatherPage extends StatefulWidget {
  const WeatherPage({super.key});
  @override
  State createState() => \_WeatherPageState();
}
class \_WeatherPageState extends State
  final TextEditingController \_cityController = TextEditingController();
  final FocusNode \_cityFocusNode = FocusNode();
  @override
  void dispose() {
  // 释放资源(鸿蒙页面销毁时避免内存泄漏)
  \_cityController.dispose();
  \_cityFocusNode.dispose();
  Provider.of, listen: false).clearWeatherData();
  super.dispose();
  }
  /// 隐藏键盘(鸿蒙设备触摸空白处触发)
  void \_hideKeyboard() {
  \_cityFocusNode.unfocus();
  }
  /// 根据天气状况返回对应图标(鸿蒙图标适配)
  Widget \_getWeatherIcon(String weather) {
  if (weather.contains('晴')) {
  return const FaIcon(FontAwesomeIcons.sun, size: 60, color: Colors.amber);
  } else if (weather.contains('雨')) {
  return const FaIcon(FontAwesomeIcons.cloudRain, size: 60, color: Colors.blue);
  } else if (weather.contains('云')) {
  return const FaIcon(FontAwesomeIcons.cloud, size: 60, color: Colors.grey);
  } else if (weather.contains('雪')) {
  return const FaIcon(FontAwesomeIcons.snowflake, size: 60, color: Colors.white);
  } else {
  return const FaIcon(FontAwesomeIcons.cloudSun, size: 60, color: Colors.orange);
  }
  }
  @override
  Widget build(BuildContext context) {
  // 鸿蒙屏幕尺寸适配(获取屏幕宽度)
  final screenWidth = MediaQuery.of(context).size.width;
  return Scaffold(
  appBar: AppBar(
  title: const Text('Flutter鸿蒙天气查询'),
  centerTitle: true,
  // 鸿蒙沉浸式状态栏适配
  systemOverlayStyle: SystemUiOverlayStyle(
  statusBarColor: Colors.transparent,
  statusBarIconBrightness: Brightness.dark,
  ),
  ),
  // 触摸空白处隐藏键盘(鸿蒙用户习惯适配)
  body: GestureDetector(
  onTap: \_hideKeyboard,
  child: SingleChildScrollView(
  padding: EdgeInsets.symmetric(
  horizontal: screenWidth \* 0.05, // 左右边距适配屏幕
  vertical: 20,
  ),
  child: Column(
  crossAxisAlignment: CrossAxisAlignment.stretch,
  children: \[
  // 城市输入框(鸿蒙样式优化)
  TextField(
  controller: \_cityController,
  focusNode: \_cityFocusNode,
  decoration: InputDecoration(
  hintText: '请输入城市名称(如:北京)',
  hintStyle: const TextStyle(color: Colors.grey, fontSize: 14),
  prefixIcon: const FaIcon(FontAwesomeIcons.city, color: Colors.blue),
  suffixIcon: IconButton(
  icon: const Icon(Icons.search, color: Colors.blue),
  onPressed: () {
  final city = \_cityController.text.trim();
  if (city.isNotEmpty) {
  Provider.ofProvider>(context, listen: false)
  .fetchWeatherByCity(city);
  \_hideKeyboard();
  } else {
  EasyLoading.showInfo('请输入城市名称');
  }
  },
  ),
  border: OutlineInputBorder(
  borderRadius: BorderRadius.circular(12),
  borderSide: const BorderSide(color: Colors.blue),
  ),
  focusedBorder: OutlineInputBorder(
  borderRadius: BorderRadius.circular(12),
  borderSide: const BorderSide(color: Colors.blue, width: 2),
  ),
  contentPadding: const EdgeInsets.symmetric(vertical: 15),
  ),
  style: const TextStyle(fontSize: 16),
  textInputAction: TextInputAction.search,
  onSubmitted: (value) {
  if (value.trim().isNotEmpty) {
  Provider.of, listen: false)
  .fetchWeatherByCity(value.trim());
  }
  },
  ),
  const SizedBox(height: 20),
  // 定位按钮(鸿蒙原生按钮样式)
  ElevatedButton.icon(
  onPressed: () {
  Provider.ofProvider>(context, listen: false)
  .fetchWeatherByLocation();
  },
  icon: const FaIcon(FontAwesomeIcons.locationCrosshairs),
  label: const Text('定位获取当前城市天气'),
  style: ElevatedButton.styleFrom(
  padding: const EdgeInsets.symmetric(vertical: 15),
  shape: RoundedRectangleBorder(
  borderRadius: BorderRadius.circular(12),
  ),
  backgroundColor: Colors.blue,
  foregroundColor: Colors.white,
  textStyle: const TextStyle(fontSize: 16),
  ),
  ),
  const SizedBox(height: 30),
  // 天气数据展示(使用Consumer监听状态变化)
  Consumer
  builder: (context, provider, child) {
  if (provider.weatherData == null) {
  return \_buildEmptyState();
  }
  return \_buildWeatherCard(provider.weatherData!);
  },
  ),
  ],
  ),
  ),
  ),
  );
  }
  /// 空状态展示(鸿蒙友好提示)
  Widget \_buildEmptyState() {
  return Column(
  crossAxisAlignment: CrossAxisAlignment.center,
  children: \[
  const SizedBox(height: 80),
  const FaIcon(FontAwesomeIcons.cloudQuestion, size: 80, color: Colors.grey),
  const SizedBox(height: 20),
  Text(
  '暂无天气数据',
  style: TextStyle(fontSize: 18, color: Colors.grey\[600]),
  ),
  const SizedBox(height: 10),
  Text(
  '请输入城市名称或点击定位按钮查询',
  style: TextStyle(fontSize: 14, color: Colors.grey\[400]),
  ),
  ],
  );
  }
  /// 天气卡片(鸿蒙阴影效果适配)
  Widget \_buildWeatherCard(WeatherModel weather) {
  return Card(
  elevation: 8, // 鸿蒙设备阴影渲染优化
  shape: RoundedRectangleBorder(
  borderRadius: BorderRadius.circular(16),
  ),
  child: Padding(
  padding: const EdgeInsets.all(25),
  child: Column(
  crossAxisAlignment: CrossAxisAlignment.center,
  children: \[
  // 城市名称
  Text(
  weather.city,
  style: const TextStyle(
  fontSize: 28,
  fontWeight: FontWeight.bold,
  color: Colors.black87,
  ),
  ),
  const SizedBox(height: 5),
  // 更新时间
  Text(
  '更新时间:\${weather.updateTime}',
  style: TextStyle(fontSize: 14, color: Colors.grey\[500]),
  ),
  const SizedBox(height: 30),
  // 天气图标+温度
  Row(
  mainAxisAlignment: MainAxisAlignment.center,
  crossAxisAlignment: CrossAxisAlignment.center,
  children: \[
  \_getWeatherIcon(weather.weather),
  const SizedBox(width: 20),
  Text(
  '\${weather.temp}℃',
  style: const TextStyle(
  fontSize: 60,
  fontWeight: FontWeight.w300,
  color: Colors.black87,
  ),
  ),
  ],
  ),
  const SizedBox(height: 15),
  // 天气状况
  Text(
  weather.weather,
  style: const TextStyle(fontSize: 22, color: Colors.black87),
  ),
  const SizedBox(height: 30),
  // 风力+湿度(鸿蒙双列布局适配)
  Row(
  mainAxisAlignment: MainAxisAlignment.space-around,
  children: \[
  \_buildWeatherInfoItem(
  FontAwesomeIcons.wind,
  '风力',
  weather.wind,
  ),
  \_buildWeatherInfoItem(
  FontAwesomeIcons.droplet,
  '湿度',
  weather.humidity,
  ),
  ],
  ),
  ],
  ),
  ),
  );
  }
  /// 天气信息子项(复用组件)
  Widget \_buildWeatherInfoItem(IconData icon, String title, String value) {
  return Column(
  children: \[
  FaIcon(icon, size: 30, color: Colors.blue),
  const SizedBox(height: 10),
  Text(
  title,
  style: TextStyle(fontSize: 16, color: Colors.grey\[600]),
  ),
  const SizedBox(height: 5),
  Text(
  value,
  style: const TextStyle(fontSize: 18, color: Colors.black87),
  ),
  ],
  );
  }
}
7. 应用入口:main.dart(鸿蒙全局配置)
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:flutter\_easyloading/flutter\_easyloading.dart';
import 'pages/weather\_page.dart';
import 'providers/weather\_provider.dart';
import 'core/constants/constants.dart';
void main() {
  runApp(
  // 全局注入状态管理
  ChangeNotifierProvider(
  create: (context) => WeatherProvider(),
  child: const MyApp(),
  ),
  );
}
class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
  return MaterialApp(
  title: 'Flutter鸿蒙天气',
  // 鸿蒙主题适配(贴近鸿蒙系统风格)
  theme: ThemeData(
  primarySwatch: Colors.blue,
  scaffoldBackgroundColor: Colors.grey\[50],
  appBarTheme: const AppBarTheme(
  backgroundColor: Colors.white,
  foregroundColor: Colors.black87,
  elevation: 1,
  ),
  // 鸿蒙按钮样式适配
  elevatedButtonTheme: ElevatedButtonThemeData(
  style: ElevatedButton.styleFrom(
  shape: RoundedRectangleBorder(
  borderRadius: BorderRadius.circular(8),
  ),
  ),
  ),
  ),
  home: const WeatherPage(),
  // 配置加载提示(鸿蒙样式优化)
  builder: EasyLoading.init(
  builder: (context, child) {
  return MediaQuery(
  // 鸿蒙字体适配(跟随系统字体大小)
  data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0),
  child: child!,
  );
  },
  ),
  debugShowCheckedModeBanner: false,
  );
  }
}
五、鸿蒙 6.0 (API20) 运行与调试指南
1. 运行前准备
-
启动鸿蒙 6.0 (API20) 模拟器(DevEco Studio → Tools → Device Manager → 创建 HarmonyOS 6.0 模拟器)
-
替换
core/constants/constants.dart中的 API 密钥(从聚合数据 / 高德地图等平台申请):
class Constants {
  // 天气API基础地址(示例:聚合数据)
  static const String WEATHER\_API\_BASE\_URL = 'http://v.juhe.cn';
  // 替换为你的API密钥
  static const String WEATHER\_API\_KEY = '你的天气API密钥';
}
2. 运行命令(终端执行)
\# 运行鸿蒙设备(自动检测已连接设备)
flutter run
\# 如需指定设备,先执行flutter devices获取设备ID,再运行:
flutter run -d 你的鸿蒙设备ID
3. 鸿蒙特有调试技巧
-
权限调试:若定位失败,在鸿蒙设备 “设置 → 应用 → Flutter 鸿蒙天气 → 权限” 中手动开启定位权限
-
网络调试:鸿蒙模拟器需确保 “设置 → 网络” 已连接,可通过
flutter logs查看网络请求日志 -
UI 调试:使用
flutter inspector查看组件布局,鸿蒙设备需开启 “USB 调试(安全设置)” -
日志查看:终端执行
flutter logs --device 你的设备ID,过滤关键词 “Dio”“Location” 查看关键日志
六、鸿蒙 6.0 兼容性问题与解决方案
| 问题现象 | 原因分析 | 解决方案 |
|---|---|---|
| 应用安装失败,提示 “解析包错误” | 包名与鸿蒙开发者平台不一致 | 修改build.gradle中applicationId与平台一致 |
| 定位权限申请无响应 | 鸿蒙设备未开启定位服务 | 引导用户开启 “设置 → 定位服务” |
| 网络请求失败,提示 “证书错误” | 鸿蒙 HTTPS 证书校验严格 | 在 Dio 中配置忽略证书校验(开发环境) |
| UI 组件变形 | 未适配鸿蒙多分辨率屏幕 | 使用MediaQuery动态计算尺寸,避免固定值 |
| 加载弹窗闪屏 | Flutter 与鸿蒙原生渲染冲突 | 延迟弹窗显示,或使用EasyLoading最新版本 |
七、生产环境优化(鸿蒙上线必备)
-
API 密钥安全:将 API 密钥迁移到鸿蒙云函数 / 后端服务,避免客户端泄露
-
混淆加固:在
proguard-rules.pro中添加三方库混淆规则,防止反编译 -
性能优化:
-
图片资源压缩(适配鸿蒙设备分辨率)
-
定位结果缓存(避免频繁调用定位 API)
-
接口数据缓存(使用
shared_preferences缓存天气数据)
- 鸿蒙上架适配:
-
替换应用图标为鸿蒙规范图标(尺寸:16x16、48x48、128x128)
-
填写鸿蒙应用市场所需权限说明、隐私政策
-
适配鸿蒙深色模式(添加
ThemeData.dark()主题)
八、核心知识点总结(新手必记)
-
鸿蒙 6.0 适配核心:
targetSdkVersion 33、权限显式声明、包名一致性 -
三方库选型原则:优先选择 “支持 Android 13+”“维护活跃” 的库,避免小众库
-
开发流程规范:分层架构 → 模型定义 → 工具封装 → UI 实现 → 鸿蒙适配 → 调试上线
-
关键技术点:
-
Dio 拦截器处理鸿蒙网络错误
-
Geolocator 适配鸿蒙定位权限
-
Provider 实现跨页面数据共享
-
JSON 序列化提升解析效率
九、拓展方向(进阶学习)
-
集成鸿蒙原生能力:调用鸿蒙推送、支付、地图等原生 API(通过
method_channel) -
多语言适配:添加中文 / 英文切换,适配鸿蒙系统语言设置
-
离线功能:使用
sqflite存储历史天气数据,支持离线查看 -
图表展示:集成
fl_chart库,展示未来 7 天天气趋势
更多推荐



所有评论(0)