HarmonyOS 天气预报 App 开发实战:ArkTS 从零实现定位、天气查询与城市管理
这个天气预报 App,涵盖了很多初学者必踩的知识点:权限申请、定位服务、网络请求、数据持久化、列表渲染、下拉刷新、动画等。这篇文章把整个项目从架构到核心代码完整梳理一遍,适合刚入门 ArkTS / ArkUI 的同学参考。
一、项目介绍
功能一览:
- 自动定位当前城市(GPS 定位优先,失败后降级 IP 定位,再失败兜底默认城市)
- 实时天气展示:温度、天气现象、体感温度、风向风力
- 24 小时逐时预报(横向滑动)
- 7 天天气预报
- 天气详情:湿度、气压、能见度、降水量、风速、云量
- 城市搜索(支持关键字搜索 + 热门城市 + 全量城市按字母分组)
- 城市管理:添加/删除常用城市,并显示每个城市的实时温度
- 下拉刷新 + 内容渐入动画
技术栈:
开发语言 :ArkTS(Stage 模型)
UI 框架 :ArkUI 声明式开发(@Entry / @Component / @State / @Builder)
天气数据 :和风天气 API v7(now / 24h / 7d)
定位 :@kit.LocationKit + 高德逆地理编码 / IP 定位
网络请求 : @kit.NetworkKit(http)
数据持久化 : @kit.ArkData(Preferences)
日志 : hilog
二、项目结构
entry/src/main/ets
├── constants/Constants.ets // API Key、URL 常量
├── utils/HttpUtil.ets // 网络请求封装
├── model/ // 数据模型(和风/高德响应实体)
│ ├── QWeatherNow.ets / QWeatherHourly.ets / QWeatherDaily.ets
│ ├── AmapIpLocation.ets / AmapWeather.ets
│ ├── CityData.ets / ManagedCity.ets
├── service/
│ ├── LocationService.ets // 定位 + 城市搜索(GPS/IP/逆地理)
│ ├── WeatherService.ets // 和风天气接口封装
│ └── CityStore.ets // 城市管理持久化
├── pages/Index.ets // 主页面(单页 + 覆盖层)
└── entryability/EntryAbility.ets
分层思路很清晰:model(实体)→ service(业务)→ pages(UI),ArkTS 强类型约束下每层之间都通过显式类传递数据。
三、权限配置
定位功能需要在 module.json5 中声明三个权限:
"requestPermissions": [
{ "name": "ohos.permission.INTERNET" },
{ "name": "ohos.permission.APPROXIMATELY_LOCATION" },
{ "name": "ohos.permission.LOCATION" }
]
注意:定位权限属于用户授权类权限,光声明不够,代码里还要动态申请:
const atManager = abilityAccessCtrl.createAtManager();
const result = await atManager.requestPermissionsFromUser(context, [
'ohos.permission.APPROXIMATELY_LOCATION',
'ohos.permission.LOCATION'
]);
四、核心实现
1. 网络请求封装(HttpUtil)
基于 @kit.NetworkKit 封装了一个泛型 GET 方法,统一处理超时、状态码校验、JSON 解析和资源释放:
export class HttpUtil {
static async get<T>(url: string): Promise<T | undefined> {
const httpRequest = http.createHttp();
try {
const response = await httpRequest.request(url, {
method: http.RequestMethod.GET,
expectDataType: http.HttpDataType.STRING,
connectTimeout: 15000,
readTimeout: 15000
});
if (response.responseCode === 200) {
return JSON.parse(response.result as string) as T;
}
return undefined;
} catch (err) {
const error = err as BusinessError;
hilog.error(DOMAIN, TAG, `HTTP request failed: ${error.message}`);
return undefined;
} finally {
httpRequest.destroy(); // 记得销毁,避免资源泄漏
}
}
}
踩坑点: JSON.parse 在 ArkTS 里返回的结果需要配合显式类型标注,响应实体类必须和接口字段完全对齐,否则运行时取值就是 undefined。
2. 三级降级的定位策略
这是本项目最有意思的设计。LocationService.getCityLocation() 实现了完整的降级链:
GPS 定位(geoLocationManager.getCurrentLocation)
↓ 失败
高德 IP 定位(restapi.amap.com/v3/ip,取城市矩形区域中心点)
↓ 失败
兜底默认城市(北京)
GPS 定位拿到经纬度后,还要调高德逆地理编码把坐标翻译成城市/区县名。IP 定位则巧妙地利用高德返回的 rectangle(城市西南、东北角坐标),取两个点的中点作为坐标:
const lng = ((parseFloat(leftBottom[0]) + parseFloat(rightTop[0])) / 2).toFixed(2);
const lat = ((parseFloat(leftBottom[1]) + parseFloat(rightTop[1])) / 2).toFixed(2);
踩坑点:
- 真机上 getCurrentLocation 要先检查 isLocationEnabled(),位置服务没开会直接抛异常;
- 模拟器上 GPS 基本拿不到,所以 IP 降级这条路径非常必要,调试时强烈建议都做。
3. 和风天气 API 对接
WeatherService 封装了三个接口:/weather/now(实时)、/weather/24h(逐时)、/weather/7d(七天)。注意和风 v7 API 响应里 code === '200' 才是成功。还有一点:和风现在很多账号的 API Host 不再是 devapi.qweather.com,而是控制台里分配的专属域名,配置错会一直 404。
4. 城市搜索与管理
- 搜索用高德的 inputtips 联想接口,返回的 location 拆分出经纬度直接作为和风的 location 参数(和风支持 经度,纬度 格式查询,可以不查 LocationID,省一步接口调用);
- 城市列表页做了热门城市 + 全量城市按首字母分组(ListItemGroup + @Builder LetterHeader);
- 城市管理用 Preferences 持久化,ManagedCity 序列化成 JSON 字符串存储,读取时逐项校验字段合法性,防止脏数据崩溃。
5. UI 层的一些技巧
主页面采用单页 + Stack 覆盖层架构,搜索页和城市管理页不是独立路由,而是覆盖在主页面之上:
Stack() {
Column() {
if (this.isLoading) { this.LoadingView(); }
else if (this.nowResponse === undefined) { this.ErrorView(); }
else { this.WeatherContent(); }
}
if (this.showSearch) { this.SearchOverlay(); }
if (this.showCityManage) { this.CityManageOverlay(); }
}
几个值得说的点:
1. 加载/错误/内容三态切换:用 if-else 条件渲染,比路由跳转体验好;
2. 内容渐入动画:数据加载完后先置 opacity: 0,setTimeout 50ms 后置 1,配合 translate 和 .animation() 实现上滑渐入,几个卡片用 delay: 100/200/300 做出阶梯式入场;
3. 下拉刷新:Refresh({ refreshing: $$this.isRefreshing }) 双向绑定刷新状态;
4. 城市列表局部更新:cityWeatherInfos 逐个请求每个城市的实时天气,每拿到一个结果就用 slice() 生成新数组替换,保证 @State 能感知变化,逐行从“加载中...”刷成真实温度;
5. 天气图标:没有引图片资源,直接用和风 icon 字段映射成 Emoji,省资源又好看。
五、ArkTS 语法上的注意点
写这个项目总结几条 ArkTS 和普通 TypeScript 的差异,都是编译期强约束:
1. 不能用对象字面量当类型,必须先 class 定义实体类(如 CityLocation、SearchResult)
2. 禁止 any / 结构化类型,接口响应解析必须 as 到显式类
3. ForEach 的键值生成函数要保证唯一,列表带 index 时用 index ?? 0 处理可选参数
4. 异步方法返回 Promise<T | undefined>,调用侧全部要判空,链路上一环判漏运行时就可能白屏。
六、总结与展望
这个项目虽然不大,但完整走通了 HarmonyOS 应用开发的典型链路:声明式 UI + 权限体系 + 系统能力(定位/网络/存储)+ 三方 API 集成。整体下来对 Stage 模型、ArkTS 类型约束和声明式范式有了体感。
后续可以优化的方向:
- 接入和风分钟级降雨和空气质量接口
- 用 Navigation 重构为多页面路由,支持深链
- 加上深色模式适配和 @ohos.permission.NOTIFICATION 的天气预警推送
- 把 API Key 迁移到服务端代理,避免硬编码在客户端
更多推荐



所有评论(0)