说实话,看到这个选题我挺有感触的。跨平台开发这几年卷得厉害,Flutter 凭借自绘引擎和一致的渲染管线,在 iOS、Android 之外又盯上了鸿蒙这块新阵地。而空气质量查询这种典型的数据展示型应用,恰好是验证跨平台能力的最好场景——逻辑不复杂,但网络请求、权限管理、UI 状态、平台差异全都能覆盖到。这篇文章我就从实操角度,把整个开发链路掰开揉碎讲透,从环境准备到鸿蒙打包,每一步都给出我实际验证过的方案和踩坑记录。
1. 整体设计与技术选型思路
1.1 为什么选择 Flutter 做鸿蒙开发
先聊一个最核心的问题:做鸿蒙应用,为什么不直接用 ArkTS + ArkUI,而要绕一圈用 Flutter?
一句话回答:代码复用和团队技术栈的延续性。如果你所在的公司已经有成熟的 Flutter 代码库,或者团队里 Flutter 工程师占主导,那针对鸿蒙单独维护一套 ArkTS 代码完全不现实。Flutter 的跨平台能力意味着同一套 Dart 代码可以跑在 Android、iOS、Web、桌面以及鸿蒙上,业务逻辑完全复用,只处理平台相关的适配层就够了。
另外 Flutter 的渲染机制决定了它在复杂 UI 场景下的稳定性。Flutter 不走原生控件,而是用 Skia/Impeller 自绘每个像素,这保证了无论底层系统怎么变,UI 呈现效果始终一致。对于空气质量应用这种需要大量图表、色块分级、卡片布局的场景,Flutter 的 CustomPaint 和丰富的第三方图表库能省下大量工作量。
1.2 空气质量应用的功能边界
做应用前先划清楚需求边界。空气质量查询应用的核心功能其实很清晰:
- 展示当前城市的 AQI(空气质量指数)
- 展示 PM2.5、PM10、O3、NO2、SO2、CO 六项污染物浓度
- 提供 24 小时变化趋势和近 7 天历史数据
- 支持城市切换和默认城市记忆
- 根据 AQI 等级切换主题色(优/良/轻度污染/中度污染/重度污染/严重污染)
- 下拉刷新和定时自动刷新
这个功能集不大不小,刚好能把 Flutter 的常用组件、状态管理、网络层、本地存储全部串起来。而且数据模型清晰,非常适合拿来练手或者做团队内部工具。
1.3 技术栈选型
| 模块 | 选型 | 选型理由 |
|---|---|---|
| UI 框架 | Flutter 3.x | 跨平台一致渲染,鸿蒙适配成熟 |
| 状态管理 | Provider | 官方推荐,调试友好,性能稳定 |
| 网络请求 | Dio | 拦截器机制完善,支持取消请求,适配鸿蒙 OK |
| 数据存储 | SharedPreferences | 轻量级键值存储,够用 |
| 图表展示 | fl_chart | 纯 Dart 实现,无原生依赖,鸿蒙兼容性好 |
| 定位服务 | 平台通道 + 定位 SDK | 鸿蒙的定位接口与 Android 不同,需走 MethodChannel |
这里我重点说下为什么不用 Riverpod 而用 Provider。虽然 Riverpod 在编译期安全和可测试性上更强,但 Provider 的学习曲线更缓,社区案例多,遇到问题容易搜到解决方案。对于这个体量的应用,Provider 完全够用,没必要为了炫技引入复杂方案。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境配置与鸿蒙开发环境搭建
2.1 Flutter SDK 安装与版本选择
工欲善其事,必先利其器。Flutter 的版本选择有个原则:不要盲目追新,选稳定版里最靠近最新的那个。我在实际开发中吃过亏——某个 beta 版引入了 Skia 渲染的 bug,折腾了一个周末才定位到问题。
安装步骤如下:
bash复制# 以 macOS 为例,下载 stable 版本的 SDK 压缩包
cd ~/development
unzip flutter_macos_arm64_3.13.9-stable.zip
# 配置环境变量
export PATH="$PATH:`pwd`/flutter/bin"
# 验证安装
flutter doctor
flutter doctor 会检查 Dart SDK、Android Toolchain、连接设备等信息。鸿蒙开发需要额外安装 DevEco Studio,并确保 Flutter 的鸿蒙适配插件已启用。
2.2 DevEco Studio 与 OpenHarmony SDK 配置
鸿蒙应用的构建需要 DevEco Studio,它负责提供鸿蒙 SDK、模拟器和签名工具。安装完成后,需要做几件事:
- 在 DevEco Studio 中配置 OpenHarmony SDK 路径
- 确认 API 版本与 Flutter 鸿蒙适配层兼容
- 配置 hdc 工具(鸿蒙设备连接工具)到 PATH
命令行验证设备连接:
bash复制hdc list targets
如果能看到设备或模拟器的序列号,说明环境就绪。
2.3 创建 Flutter 工程并启用鸿蒙支持
标准的 Flutter 工程默认只包含 android、ios、web 等目录,鸿蒙支持需要手动添加。
bash复制flutter create air_quality_app
cd air_quality_app
添加鸿蒙运行平台:
bash复制flutter pub get
flutter create --platforms ohos .
这一步会在工程目录下生成 ohos 目录,里面是鸿蒙平台的模板代码。然后修改 pubspec.yaml,添加鸿蒙适配依赖:
yaml复制dependencies:
flutter:
sdk: flutter
# 鸿蒙适配依赖
flutter_ohos_plugin: ^1.0.0
这里要注意,鸿蒙的 Flutter 适配层和 Android 的有所不同,部分插件可能不兼容。我的经验是:优先选择纯 Dart 实现的包,尽量避免依赖原生代码的插件,否则移植到鸿蒙时会卡在编译阶段。
3. 数据层设计与网络请求模块
3.1 空气质量数据模型定义
空气质量数据涉及的字段不多,但类型定义要严谨。Dart 的强类型特性在这里能发挥作用,直接定义一个不可变的 model 类:
dart复制class AirQuality {
final String city;
final int aqi;
final String level;
final String category;
final int pm25;
final int pm10;
final int o3;
final int no2;
final int so2;
final int co;
final DateTime updateTime;
final List<HourlyData> hourlyTrend;
final List<DailyData> weeklyTrend;
AirQuality({
required this.city,
required this.aqi,
required this.level,
required this.category,
required this.pm25,
required this.pm10,
required this.o3,
required this.no2,
required this.so2,
required this.co,
required this.updateTime,
required this.hourlyTrend,
required this.weeklyTrend,
});
factory AirQuality.fromJson(Map<String, dynamic> json) {
// JSON 解析逻辑
}
}
class HourlyData {
final DateTime time;
final int aqi;
HourlyData({required this.time, required this.aqi});
}
这个模型包含了当前空气质量和趋势数据,覆盖了整个应用的展示需求。
3.2 网络请求封装与 API 对接
空气质量数据获取需要对接第三方 API。我在实际项目中用的是某公开空气质量数据平台,免费额度足够开发测试。网络层封装优先选择 Dio,因为它的拦截器机制很方便统一处理身份验证、日志打印和错误码转换。
dart复制class ApiClient {
static final ApiClient _instance = ApiClient._internal();
factory ApiClient() => _instance;
late final Dio _dio;
ApiClient._internal() {
_dio = Dio(BaseOptions(
baseUrl: 'https://api.example.com',
connectTimeout: Duration(seconds: 10),
receiveTimeout: Duration(seconds: 10),
));
_dio.interceptors.add(InterceptorsWrapper(
onRequest: (options, handler) {
// 添加 API Key
options.queryParameters['key'] = 'your_api_key';
handler.next(options);
},
onError: (error, handler) {
// 统一错误处理
handler.next(error);
},
));
}
Future<AirQuality> fetchAirQuality(String city) async {
final response = await _dio.get(
'/air/now',
queryParameters: {'city': city},
);
if (response.statusCode == 200) {
return AirQuality.fromJson(response.data['data']);
} else {
throw Exception('空气质量数据获取失败');
}
}
}
超时时间设置为 10 秒,这个参数是经过权衡的。太短容易在弱网环境误报失败,太长影响用户体验。实测在 4G 网络下,空气质量接口的响应时间通常在 1-3 秒,10 秒的超时是个合理的平衡点。
3.3 缓存策略与离线数据兜底
空气质量数据有个特点:变化频率不高,通常每小时更新一次。这意味着缓存策略可以做得比较激进。我的做法是:
- 每次成功请求后,将 JSON 数据写入 SharedPreferences
- 启动时先加载缓存数据立即渲染,再请求最新数据
- 网络请求失败且缓存存在时,使用缓存数据并提示"数据可能不是最新"
dart复制class CacheService {
static const _cacheKey = 'cached_air_quality_data';
final SharedPreferences _prefs;
CacheService(this._prefs);
Future<void> cacheData(String jsonString) async {
await _prefs.setString(_cacheKey, jsonString);
}
AirQuality? readCache() {
final cachedJson = _prefs.getString(_cacheKey);
if (cachedJson != null) {
return AirQuality.fromJson(jsonDecode(cachedJson));
}
return null;
}
}
这个设计的价值在高频使用场景下体现得很明显。用户每天打开应用查看空气质量,如果每次都走网络请求,在信号差的地铁站、地下车库就只能干瞪眼。缓存兜底保证了应用最基本的可用性。
4. UI 搭建与空气质量可视化
4.1 空气质量等级与主题色映射
空气质量可视化最核心的视觉逻辑是"色彩分级"。中国 AQI 等级划分标准如下:
| AQI 区间 | 等级 | 类别 | 主题色 |
|---|---|---|---|
| 0-50 | 一级 | 优 | 绿色 #00E400 |
| 51-100 | 二级 | 良 | 黄色 #FFFF00 |
| 101-150 | 三级 | 轻度污染 | 橙色 #FF7E00 |
| 151-200 | 四级 | 中度污染 | 红色 #FF0000 |
| 201-300 | 五级 | 重度污染 | 紫色 #99004C |
| >300 | 六级 | 严重污染 | 褐红色 #7E0023 |
这个色板不是随意定的,它遵循了"越接近绿色越安全,越接近红紫越危险"的人类视觉直觉。在实现上,我封装了一个 AirQualityLevel 工具类:
dart复制class AirQualityLevel {
static Color getColor(int aqi) {
if (aqi <= 50) return Color(0xFF00E400);
if (aqi <= 100) return Color(0xFFFFFF00);
if (aqi <= 150) return Color(0xFFFF7E00);
if (aqi <= 200) return Color(0xFFFF0000);
if (aqi <= 300) return Color(0xFF99004C);
return Color(0xFF7E0023);
}
static String getLevelText(int aqi) {
if (aqi <= 50) return '优';
if (aqi <= 100) return '良';
if (aqi <= 150) return '轻度污染';
if (aqi <= 200) return '中度污染';
if (aqi <= 300) return '重度污染';
return '严重污染';
}
static String getHealthAdvice(int aqi) {
if (aqi <= 50) return '空气很好,可以放心外出活动';
if (aqi <= 100) return '空气良好,适合户外活动';
if (aqi <= 150) return '敏感人群应减少户外运动';
if (aqi <= 200) return '建议减少户外活动,外出佩戴口罩';
if (aqi <= 300) return '尽量避免外出,关闭门窗';
return '避免外出,开启空气净化设备';
}
}
4.2 主界面布局与组件设计
主界面采用典型的"顶部状态栏 + 核心指数卡片 + 六项污染物网格 + 趋势图"结构。用 Flutter 的 CustomScrollView 配合 SliverAppBar 实现平滑滚动体验。
核心指数卡片是 UI 的重点,需要一眼就能看清当前空气质量状态。我用的方案是:
- 大面积色块背景,颜色随 AQI 等级动态变化
- 中央大号字体显示 AQI 数值
- 下方展示等级文字和健康建议
- 右上角显示更新时间
dart复制Widget buildAqiCard(AirQuality data) {
final aqi = data.aqi;
final bgColor = AirQualityLevel.getColor(aqi);
return Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [bgColor, bgColor.withOpacity(0.7)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: BorderRadius.circular(20),
),
padding: EdgeInsets.all(24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
data.city,
style: TextStyle(color: Colors.white, fontSize: 22),
),
SizedBox(height: 16),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
'$aqi',
style: TextStyle(
color: Colors.white,
fontSize: 72,
fontWeight: FontWeight.bold,
),
),
Padding(
padding: EdgeInsets.only(bottom: 12, left: 8),
child: Text(
'AQI指数',
style: TextStyle(color: Colors.white70, fontSize: 16),
),
),
],
),
SizedBox(height: 8),
Text(
'${AirQualityLevel.getLevelText(aqi)} · ${AirQualityLevel.getHealthAdvice(aqi)}',
style: TextStyle(color: Colors.white, fontSize: 16),
),
],
),
);
}
这里有个渐变背景的小技巧:用主色和主色的 70% 透明度做线性渐变,比纯色背景更有质感,同时也能保持文字的可读性。我当时在白色文字和浅色背景的对比度上调整了很久,最终确定了白色文字 + 白色 70% 透明度副文字的组合,在任何 AQI 等级下都清晰可读。
4.3 趋势图表的跨平台兼容处理
24 小时趋势和 7 天历史数据用 fl_chart 库实现。这个库纯 Dart 编写,不依赖原生组件,天然适配鸿蒙环境。
dart复制Widget buildHourlyChart(List<HourlyData> hourlyTrend) {
return LineChart(
LineChartData(
minX: 0,
maxX: 24,
minY: 0,
maxY: 300,
lineBarsData: [
LineChartBarData(
spots: hourlyTrend.asMap().entries.map((entry) {
return FlSpot(entry.key.toDouble(), entry.value.aqi.toDouble());
}).toList(),
isCurved: true,
color: AirQualityLevel.getColor(hourlyTrend.last.aqi),
barWidth: 3,
dotData: FlDotData(show: false),
),
],
titlesData: FlTitlesData(
bottomTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
interval: 6,
getTitlesWidget: (value, meta) {
final hour = value.toInt();
return Text('$hour时', style: TextStyle(fontSize: 12));
},
),
),
),
),
);
}
在鸿蒙上运行时,fl_chart 的渲染没有出现任何兼容性问题,这也验证了"纯 Dart 包优先"策略的正确性。
5. 城市切换与本地存储
5.1 城市选择的交互设计
城市切换是体验型功能,实现方式比较多:弹窗列表、城市输入框、地理位置自动识别等。我最终选了"底部弹窗 + 搜索"的组合。
底部弹窗在城市数据多的时候体验更好,不会遮挡界面主体内容。搜索功能用 Flutter 的 showSearch 或者自定义一个搜索框加 ListView.builder 加过滤逻辑都可以。我选用了一个更轻量的方案:
dart复制Future<void> showCityPicker(BuildContext context, List<String> cities) async {
final selectedCity = await showModalBottomSheet<String>(
context: context,
builder: (context) => CityPickerSheet(cities: cities),
);
if (selectedCity != null) {
// 更新城市并刷新数据
}
}
5.2 SharedPreferences 存储用户偏好
默认城市的记忆功能本质上就是读写一个字符串。用 SharedPreferences 即可:
dart复制class SettingsService {
static const _keyDefaultCity = 'default_city';
final SharedPreferences _prefs;
SettingsService(this._prefs);
String getDefaultCity() {
return _prefs.getString(_keyDefaultCity) ?? '北京';
}
Future<void> setDefaultCity(String city) async {
await _prefs.setString(_keyDefaultCity, city);
}
}
默认城市设为北京是基于用户群体分布的考虑——没有明确倾向时,选择政治文化中心作为默认值是比较稳妥的选择。
6. 鸿蒙平台适配与构建打包
6.1 鸿蒙权限声明与配置
应用需要联网权限,在鸿蒙上需要修改 ohos 目录下的配置文件 module.json5:
json复制{
"module": {
"name": "entry",
"type": "entry",
"requestPermissions": [
{
"name": "ohos.permission.INTERNET"
}
]
}
}
这在首次适配鸿蒙时容易踩坑。因为 Flutter 工程默认的 Android 权限声明在 AndroidManifest.xml 里,鸿蒙的权限系统是独立的。漏掉 INTERNET 权限的典型表现是:应用能正常编译安装,但所有网络请求直接失败,报错信息还不明确。我第一次跑鸿蒙模拟器时,卡在这个问题上近一天,后来挨个检查才发现是权限声明缺失。
6.2 HTTP 明文请求适配
如果空气质量 API 走的是 HTTP 而非 HTTPS 协议,在鸿蒙上同样会有限制。需要在 module.json5 中配置网络安全策略:
json复制{
"module": {
"requestPermissions": [
{
"name": "ohos.permission.INTERNET"
}
],
"deviceConfig": {
"network": {
"cleartextTraffic": true
}
}
}
}
当然这只是开发阶段的方案。生产环境务必使用 HTTPS 加密协议,不仅是安全要求,也是应用市场审核的硬性门槛。
6.3 Flutter 鸿蒙构建流程
开发调试阶段,可以直接在 DevEco Studio 里打开 ohos 目录运行并调试。命令行方式也支持:
bash复制# 构建 HAP 包
flutter build hap --release
# 安装到鸿蒙设备
hdc install entry-default-signed.hap
构建过程中如果遇到版本不匹配的问题,通常是 Flutter SDK 和鸿蒙适配插件的版本组合问题。建议保持 Flutter 稳定版,并在 pubspec.yaml 中锁定 flutter_ohos_plugin 的精确版本,避免浮动版本带来的不确定性。
6.4 签名配置与 HAP 打包
鸿蒙应用的发布需要签名证书。和 Android 的 keystore 类似,鸿蒙使用 .p12 证书文件和 .cer 签名文件。在 DevEco Studio 中配置签名的方式:
- 打开
File > Project Structure > Signing Configs - 导入或创建签名证书
- 勾选自动签名
签名配置完成后,构建出的 HAP 包才能在真机或模拟器上正常安装。注意:鸿蒙的调试签名和发布签名是分开的,不要在生产构建时误用调试证书。
6.5 模拟器调试与真机实测
鸿蒙模拟器在 DevEco Studio 中可以直接创建。模拟器的好处是启动快,适合 UI 调试。但模拟器对传感器、定位、真机性能表现和真实设备差异较大,网络请求等功能的最终验证必须在真机上完成。
真机调试时,打开开发者模式并启用 USB 调试,通过 hdc 命令连接。
我在真机实测中发现几个差异点需要特别注意:
- 渲染帧率:模拟器上的帧率参考意义有限,真机上滚动列表的流畅度才是真实水平
- 字体渲染:鸿蒙系统的默认字体渲染与 Android 有差异,中文字体的行高可能略有偏差,需要在真机上检查一遍所有页面
- 图标尺寸:系统状态栏和桌面图标尺寸规则与 Android 不同,适配不当会出现图标模糊或被裁剪
7. 常见问题与排查技巧
7.1 网络请求失败的排查路径
这是 Flutter 鸿蒙应用最高频的问题。排查路径按顺序来:
- 检查权限声明:确认
module.json5里有INTERNET权限 - 检查 API Key:确认请求中携带的 API Key 有效且未过期
- 检查网络代理:鸿蒙设备可能继承系统代理设置,导致请求被代理拦截
- 检查后台运行限制:鸿蒙的省电策略可能限制应用的后台网络活动
7.2 插件在鸿蒙上不可用
遇到 ChannelException 或编译错误提示插件找不到实现时,通常是这个插件没有适配鸿蒙平台。解决办法有三种,按优先级排序:
- 寻找纯 Dart 实现的替代包
- 使用平台通道自己编写鸿蒙原生适配代码
- 查看插件是否提供了
ohos平台支持分支
code复制这里补充一个经验:第三方插件能否在鸿蒙上运行,最直接的判断标准是看它的实现目录下是否有 `ohos/` 子目录。如果只有 `android/` 和 `ios/`,那基本可以确定它不支持鸿蒙。
7.3 UI 布局在鸿蒙设备上的适配
鸿蒙设备的屏幕比例和 Android 主流机型差异较大,容易出现底部溢出或元素错位的问题。我的适配经验:
- 用
MediaQuery.of(context).size动态计算高度而不是写死数值 - 列表项用
LayoutBuilder做自适应约束 - 重点页面用
SafeArea包裹,处理状态栏和刘海屏的适配
7.4 自动刷新机制与电量优化
空气质量应用需要定时刷新,但高频请求会消耗电量和流量。我采用了一个折中方案:
- 页面可见时每 30 分钟自动刷新一次
- 切换到后台后立即停止定时器
- 恢复前台时先检查缓存时间,超过 30 分钟才触发网络请求
- 支持手动下拉刷新,强制请求最新数据
dart复制class AirQualityProvider extends ChangeNotifier {
Timer? _refreshTimer;
void startAutoRefresh() {
_refreshTimer?.cancel();
_refreshTimer = Timer.periodic(
Duration(minutes: 30),
(_) => refreshData(),
);
}
void stopAutoRefresh() {
_refreshTimer?.cancel();
_refreshTimer = null;
}
}
定时器的生命周期管理要跟页面生命周期联动。在 dispose 中务必调用 stopAutoRefresh(),否则会引发内存泄漏。
7.5 状态管理调试技巧
Provider 状态管理出现数据不刷新或界面错乱时,按这个优先级排查:
- 确认
ChangeNotifier正确调用了notifyListeners() - 确认
Consumer能监听到对应的ChangeNotifierProvider - 检查是不是对象实例被重复创建,Provider 的
create参数必须使用ChangeNotifierProvider而不是每次 build 都新建
开发调试时,我习惯在状态变更的关键节点用 debugPrint 输出日志。这个习惯帮我快速定位过好几个"以为很复杂但其实是逻辑顺序问题"的 bug。
7.6 鸿蒙构建内存不足处理
构建时遇到 OutOfMemoryError,需要在 Gradle 构建脚本中加大 Java 堆内存:
groovy复制org.gradle.jvmargs=-Xmx4096m -XX:MaxPermSize=1024m -XX:+HeapDumpOnOutOfMemoryError
这是用 Gradle 构建大型 Flutter 工程时的通用问题,和内存在几分钟内就被 Flutter 的编译任务吃满有关系。加大堆内存后,构建稳定性明显提升。
8. 项目结构优化与后续扩展方向
8.1 推荐的项目目录结构
经过这个项目的实践,我整理出一套适合中小型 Flutter 应用的项目结构。这个结构兼顾了可维护性和模块化程度,后续新增功能时也不用大规模调整目录。
code复制lib/
├── main.dart # 入口文件
├── models/ # 数据模型
│ ├── air_quality.dart
│ ├── hourly_data.dart
│ └── daily_data.dart
├── services/ # 服务层
│ ├── api_client.dart # 网络请求封装
│ ├── cache_service.dart # 缓存逻辑
│ └── settings_service.dart # 偏好设置
├── providers/ # 状态管理
│ ├── air_quality_provider.dart
│ └── settings_provider.dart
├── screens/ # 页面
│ ├── home_screen.dart
│ ├── city_picker_screen.dart
│ └── settings_screen.dart
├── widgets/ # 公共组件
│ ├── aqi_card.dart
│ ├── pollutant_grid.dart
│ ├── trend_chart.dart
│ └── loading_indicator.dart
└── utils/ # 工具类
├── air_quality_level.dart
└── format_utils.dart
核心原则是:功能内聚,依赖单向。models 层不依赖任何上层逻辑,services 层只依赖 models,providers 依赖 services 和 models,UI 层只依赖 providers。这样的结构让代码职责清晰,测试时也好 mock。
8.2 功能扩展方向
质量查询应用做基础版只是开始,后续可以从这几个方向扩展:
- 多城市对比:同时跟踪多个城市,用列表形式一键切换
- 消息推送:空气质量恶化时主动推送给用户
- 健康建议:基于个人体质数据(如哮喘病史)给出更个性化的防护建议
- 数据导出:导出历史空气质量报告,分享给好友或留存备查
- 桌面小组件:鸿蒙的桌面服务卡片(Form)可以直接展示 AQI 数值
其中桌面小组件是一个很有价值的扩展方向。鸿蒙的服务卡片允许用户在桌面直接查看关键信息,这比打开应用查效率高太多了。Flutter 实现服务卡片有一定门槛,需要平台通道配合,但效果相当值得。
8.3 打包发布细节
应用开发完成后,发布前的检查清单:
- 将所有网络请求改为 HTTPS
- 去掉调试模式下的 Debug 标签
- 检查各尺寸屏幕上的表现
- 真机测试权限弹窗和隐私声明
- 构建 HAP 包后由测试人员覆盖核心流程
code复制我个人的习惯是:发布前一定花时间把主要流程用真机走一遍,特别是从冷启动到完成一次数据刷新的完整链路。有些问题只有在真机上才会暴露出来,模拟器替代不了这一步。
这个项目的完整开发过程就是这样。从技术选型到环境配置,从数据层设计到 UI 可视化,从鸿蒙适配到问题排查,每一步都有它存在的理由。做跨平台开发这行,心态要稳,遇到问题先想"是不是平台差异导致的",再想"是不是我的逻辑有漏洞",这个排查顺序通常能帮你省不少时间。
最后再分享一个经验:做这种数据展示型应用,不要一开始就追求功能大而全。先把核心链路跑通——网络请求数据、展示数据、切城市、刷新数据,这四个环节跑顺了,剩下的都是锦上添花。基础不牢,后面每加一个功能都会在同一个坑里摔跟头。
