HarmonyOS NEXT实战:WinkWeatherPulse天气应用完整开发记录
HarmonyOS NEXT实战:WinkWeatherPulse天气应用完整开发记录
HarmonyOS NEXT实战:WinkWeatherPulse天气应用完整开发记录
一、项目简介
WinkWeatherPulse是一款基于HarmonyOS NEXT(ArkTS)开发的沉浸式天气应用,主打"多源数据融合 + AI天气助手 + 动态视觉体验"。不同于普通天气App只调用单一数据源,本项目同时接入和风天气和高德地图两路API,通过字段级合并算法实现数据互补;同时内置DeepSeek和通义千问双AI模型,提供每日天气简报、预警解读、生活指数建议等智能服务。
项目从0到1完整实现了天气查询、城市管理、地图选点、AI对话、桌面小组件、预警通知等功能,代码分层清晰,适合作为HarmonyOS NEXT开发的实战参考。
二、功能一览
| 功能模块 | 说明 |
|---|---|
| 实时天气 | 温度、体感、湿度、风向风力、气压、能见度 |
| 多日预报 | 3天/7天/15天天气预报,逐小时预报 |
| 空气质量 | AQI指数、污染物详情、空气质量等级 |
| 生活指数 | 穿衣、紫外线、运动、洗车等指数 |
| 天气预警 | 灾害性天气预警推送,后台轮询检测 |
| AI天气助手 | 每日简报、预警解读、自由对话,支持DeepSeek/通义千问切换 |
| 城市管理 | 多城市添加切换,地图选点定位 |
| 动态背景 | 根据天气类型切换渐变色+Canvas粒子动画(雨/雪/晴/雾) |
| 桌面小组件 | 2x2、2x4、4x4三种尺寸天气卡片 |
| 自定义图表 | 温度趋势曲线、AQI柱状图、风力罗盘 |
三、技术栈
| 类别 | 技术 |
|---|---|
| 开发语言 | ArkTS(TypeScript超集) |
| 系统 | HarmonyOS NEXT |
| 开发工具 | DevEco Studio |
| 状态管理 | AppStorage + @StorageProp + @ObservedV2 |
| 天气API | 和风天气(QWeather)+ 高德地图(AMap) |
| AI模型 | DeepSeek V4 Flash + 通义千问 Qwen3.6 Max |
| 网络请求 | 封装HttpClient,支持超时重试、gzip压缩 |
| 动画渲染 | Canvas自定义粒子系统 |
| 桌面卡片 | Form Extension Ability |
| 数据存储 | Preferences持久化 |
四、项目结构
entry/src/main/ets/
├── api/ # API层
│ ├── ApiConfig.ets # 全局API配置(密钥、端点、超时)
│ ├── amap/ # 高德地图API(地理编码、天气)
│ └── qweather/ # 和风天气API(实况、预报、空气、预警)
├── component/ # 自定义组件
│ ├── DynamicBackground.ets # 动态沉浸式背景
│ ├── BottomTabBar.ets # 底部导航栏
│ ├── WeatherCard.ets # 天气卡片
│ ├── TempCurveChart.ets # 温度趋势曲线
│ ├── AqiBarChart.ets # AQI柱状图
│ ├── WindCompass.ets # 风力罗盘
│ ├── WeatherIcon.ets # 天气图标映射
│ └── ChatBubble.ets # AI聊天气泡
├── model/ # 数据模型
│ ├── MergedWeather.ets # 合并后的天气数据模型
│ ├── MergeStrategy.ets # 合并策略定义
│ ├── WeatherTypes.ets # 天气类型枚举
│ ├── City.ets # 城市模型
│ └── AiConversation.ets # AI对话模型
├── pages/ # 页面
│ ├── Index.ets # 主页(Tab容器)
│ ├── WeatherHome.ets # 天气主页
│ ├── AiAssistantPage.ets # AI助手页
│ ├── CityManagePage.ets # 城市管理
│ ├── CitySelectMapPage.ets # 地图选城
│ ├── LoginPage.ets # 登录页
│ ├── MinePage.ets # 我的页面
│ ├── SettingsPage.ets # 设置页
│ └── RadarPage.ets # 雷达图页
├── service/ # 服务层
│ ├── WeatherRepository.ets # 天气数据仓库(单例)
│ ├── WeatherMergeService.ets # 双源合并调度服务
│ ├── FieldMerger.ets # 字段级合并器
│ ├── LocationService.ets # 定位服务
│ ├── WarningPollService.ets # 预警轮询服务
│ ├── NotificationManager.ets # 通知管理
│ ├── BackgroundTaskManager.ets # 后台任务管理
│ └── ai/ # AI服务
│ ├── AiService.ets # AI服务门面
│ ├── OpenAiCompatibleClient.ets # OpenAI兼容客户端
│ ├── PromptTemplates.ets # 场景化Prompt模板
│ └── WeatherContextBuilder.ets # 天气上下文构建
├── widget/ # 桌面小组件
│ └── pages/
│ ├── Widget2x2.ets
│ ├── Widget2x4.ets
│ └── Widget4x4.ets
└── utils/ # 工具类
├── HttpClient.ets # 网络请求封装
├── Logger.ets # 日志工具
├── PreferencesStorage.ets # 持久化存储
└── StreamParser.ets # 流式解析(AI SSE)
五、核心功能实现
5.1 双源天气数据合并
这是本项目的核心亮点之一。不做简单的"主源失败切备源",而是双向并发拉取 + 字段级互补合并。
实现思路:
- 并发请求和风天气(基于经纬度)和高德天气(基于adcode)
- 使用
Promise.allSettled保证任一源失败不影响另一源 FieldMerger逐字段执行primary/fallback/tolerance合并策略- 若位置信息缺少adcode,先调用高德逆地理编码获取
关键代码:
// WeatherMergeService.ets 核心片段
async fetchAndMerge(loc: LocationRef, cityName?: string): Promise<MergedWeather> {
// 1. 若无adcode,先逆地理编码
let adcode = loc.adcode ?? null;
if (!adcode) {
const regeo = await amapGeoService.reverseGeocode(loc.lat, loc.lng);
adcode = regeo?.adcode;
}
// 2. 并发拉取双源,allSettled保证不抛异常
const results = await Promise.allSettled([
qweatherService.fetchAll(loc),
amapWeatherService.fetchAll(adcode),
]);
const qw = results[0].status === 'fulfilled' ? results[0].value : null;
const amap = results[1].status === 'fulfilled' ? results[1].value : null;
// 3. 字段级合并
return this.merger.merge(qw, amap);
}
合并策略示例:
- 实时温度:以和风为主,高德为备,差值超过2℃时取均值
- 空气质量:以和风为主(和风AQI数据更全)
- 风力风向:两源都有则取和风,缺失则用高德
- 预警信息:两源合并去重
5.2 AI天气助手
AI助手支持双模型切换,内置4种场景化Prompt,支持流式输出(SSE)。
架构设计:
AiService作为门面,统一对外接口OpenAiCompatibleClient封装OpenAI兼容协议,DeepSeek和通义千问都走这套PromptTemplates定义每日简报、预警解读、生活指数、自由对话4种system promptWeatherContextBuilder动态注入当前天气数据作为上下文
关键代码:
// AiService.ets - 每日简报快捷方法
async dailyBriefing(weather: MergedWeather): Promise<string> {
const context = WeatherContextBuilder.build(weather);
const prompt = PromptTemplates.dailyBriefing(context);
return this.client.chatCompletion([
{ role: 'system', content: prompt },
{ role: 'user', content: '请生成今日天气简报' }
], { stream: true });
}
AI配置:
// ApiConfig.ets
export const AI_CONFIG = {
deepseek: {
baseUrl: 'https://api.deepseek.com/v1',
model: 'deepseek-v4-flash',
displayName: 'DeepSeek V4 Flash',
},
qwen: {
baseUrl: 'https://xxx.aliyuncs.com/compatible-mode/v1',
model: 'qwen3.6-max-preview',
displayName: 'Qwen3.6 Max',
},
defaultTemperature: 0.7,
defaultMaxTokens: 800,
};
5.3 动态沉浸式背景
根据天气类型和昼夜状态,动态切换渐变色 + Canvas粒子动画。
实现要点:
- 9种天气大类(晴/多云/阴/雨/大雨/雷暴/雪/雾/霾)各有日间/夜间两套渐变色
- 粒子系统基于Canvas定时绘制,避免大量DOM节点
@ObservedV2+@Trace实现状态驱动的背景刷新
粒子类型:
type ParticleType = 'none' | 'rain' | 'snow' | 'sun' | 'fog' | 'haze';
// 渐变色板示例
const GRADIENTS = {
sunny: ['#1E5A9F', '#4A90D9', '#7BB8E8'], // 晴天日间
rain: ['#1A1A2E', '#16213E', '#0F3460'], // 雨天日间
snow: ['#2C3E50', '#34495E', '#5D6D7E'], // 雪天日间
// ... 夜间版本颜色更深
};
5.4 桌面小组件
通过Form Extension Ability实现三种尺寸的天气卡片:
- 2x2:仅显示当前温度和天气图标
- 2x4:温度 + 天气描述 + 高低温
- 4x4:完整天气信息 + 逐小时预报
小组件支持定时刷新和点击跳转App对应页面。
5.5 自定义图表组件
没有使用第三方图表库,全部基于ArkTS自定义绘制:
| 组件 | 实现方式 | 特点 |
|---|---|---|
| TempCurveChart | Canvas路径绘制 | 平滑贝塞尔曲线,渐变填充,高低温双线 |
| AqiBarChart | Column组件+动画 | 柱状图高度动画,AQI分级配色 |
| WindCompass | Canvas旋转 | 罗盘指针随风向旋转,风速显示在中心 |
六、状态管理方案
项目采用AppStorage全局存储 + Repository单例的状态管理方案:
// 天气数据存入AppStorage,UI通过@StorageProp自动响应
AppStorage.setOrCreate('current_weather_obj', null);
// Index.ets中绑定
@StorageProp('current_weather_obj') weather: MergedWeather | null = null;
// WeatherRepository单例负责数据加载和缓存
export const weatherRepository = new WeatherRepository();
数据流:
用户操作 → WeatherRepository.loadWeather()
→ WeatherMergeService.fetchAndMerge()
→ 双API并发请求 → FieldMerger合并
→ AppStorage更新 → @StorageProp自动触发UI刷新
七、网络请求封装
HttpClient统一封装了超时、重试、gzip、错误处理:
// 支持连接超时/传输超时分离配置
timeout: { connect: 5000, transfer: 10000 }
// 指数退避重试
retryBackoffMs: 500
// 统一错误分类:HttpError(网络层)/ BusinessError(业务层)
八、开发踩坑记录
8.1 双源合并的adcode问题
高德天气API需要adcode(城市编码),而定位只能拿到经纬度。解决方案:首次定位时调用高德逆地理编码接口获取adcode并缓存,后续直接使用。
8.2 AI流式输出的解析
DeepSeek和通义千问的SSE格式略有差异,需要统一的StreamParser处理data: 前缀和[DONE]结束标记。
8.3 Canvas粒子性能优化
粒子数量过多会导致帧率下降,解决方案:根据设备性能动态调整粒子数量,低端设备减少粒子数并降低绘制频率。
8.4 后台预警轮询
HarmonyOS NEXT对后台任务限制严格,需要使用backgroundTaskManager申请短时任务,配合系统闹钟实现定期轮询。
8.5 桌面卡片刷新限制
Form卡片有刷新频率限制(默认30分钟一次),需要在用户点击时主动触发刷新,避免数据过旧。
九、总结
WinkWeatherPulse项目覆盖了HarmonyOS NEXT开发的核心知识点:ArkTS声明式UI、AppStorage状态管理、Canvas自定义绘制、网络请求封装、Form小组件、后台任务、AI API集成等。
双源数据合并和AI天气助手是项目的两大特色,前者提升了数据可靠性,后者让天气App从"工具"升级为"助手"。动态背景和自定义图表则提升了整体视觉体验。
如果你也在学习HarmonyOS NEXT开发,这个项目可以作为一个不错的实战参考。后续计划加入更多功能:天气雷达图动画、语音播报、智能出行建议等。
参考资料
更多推荐




所有评论(0)