HarmonyOS 鸿蒙Next中使用高德天气 SDK 实现实时天气与预报查询

HarmonyOS 鸿蒙Next中使用高德天气 SDK 实现实时天气与预报查询 在开发旅行类应用时,需要为用户提供目的地天气信息:

  1. 查询指定城市的实时天气(温度、天气现象、风向、风力、湿度)
  2. 查询城市的未来几天天气预报(白天/夜间温度、天气)
  3. 根据天气现象显示对应的天气图标
  4. 异步查询,不阻塞 UI 线程
3 回复

1. 配置高德地图 SDK

oh-package.json5 中添加依赖:

{
  "dependencies": {
    "@amap/amap_lbs_search": "^1.0.0"
  }
}

注意: 使用高德天气 API 需要在高德开放平台申请 Key,并在项目中正确配置。

2. 创建天气服务类

// services/WeatherService.ets
import {
  WeatherSearch,
  WeatherSearchQuery,
  LocalWeatherLive,
  LocalWeatherLiveResult,
  LocalWeatherForecast,
  LocalWeatherForecastResult,
  OnWeatherSearchListener,
  AMapException
} from '@amap/amap_lbs_search'
import { common } from '@kit.AbilityKit'

/**
 * 天气服务类
 * 封装高德 SDK 天气查询 API
 */
export class WeatherService {
  private context: common.UIAbilityContext
  
  constructor(context: common.UIAbilityContext) {
    this.context = context
  }
}

3. 实现实时天气查询

/**
 * 查询实时天气
 * @param cityName 城市名称(支持城市名称或 adcode,如 "北京" 或 "110000")
 * @returns 实时天气数据
 */
async searchLiveWeather(cityName: string): Promise<LocalWeatherLive | null> {
  return new Promise<LocalWeatherLive | null>((resolve) => {
    try {
      // 创建天气查询监听器
      const weatherSearchListener: OnWeatherSearchListener = {
        onWeatherLiveSearched: (
          weatherLiveResult: LocalWeatherLiveResult | undefined,
          errorCode: number
        ): void => {
          if (errorCode === AMapException.CODE_AMAP_SUCCESS) {
            if (weatherLiveResult && weatherLiveResult.getLiveResult()) {
              console.info(`[WeatherService] ✅ 实时天气查询成功: ${cityName}`)
              resolve(weatherLiveResult.getLiveResult())
            } else {
              console.warn(`[WeatherService] ⚠️ 实时天气查询无数据: ${cityName}`)
              resolve(null)
            }
          } else {
            console.error(`[WeatherService] ❌ 实时天气查询失败,错误码: ${errorCode}`)
            resolve(null)
          }
        },
        onWeatherForecastSearched: (
          weatherForecastResult: LocalWeatherForecastResult | undefined,
          errorCode: number
        ): void => {
          // 不处理预报天气回调
        }
      }
      
      // 创建查询参数
      // WEATHER_TYPE_LIVE = 1:实时天气
      const query = new WeatherSearchQuery(cityName, WeatherSearchQuery.WEATHER_TYPE_LIVE)
      
      // 创建天气搜索对象
      const weatherSearch = new WeatherSearch(this.context)
      weatherSearch.setOnWeatherSearchListener(weatherSearchListener)
      weatherSearch.setQuery(query)
      
      // 异步搜索
      weatherSearch.searchWeatherAsyn()
      console.info(`[WeatherService] 🔍 开始查询实时天气: ${cityName}`)
    } catch (error) {
      console.error(`[WeatherService] ❌ 实时天气查询异常:`, error)
      resolve(null)
    }
  })
}

4. 实现天气预报查询

/**
 * 查询预报天气(未来几天)
 * @param cityName 城市名称(支持城市名称或 adcode)
 * @returns 预报天气数据
 */
async searchForecastWeather(cityName: string): Promise<LocalWeatherForecast | null> {
  return new Promise<LocalWeatherForecast | null>((resolve) => {
    try {
      // 创建天气查询监听器
      const weatherSearchListener: OnWeatherSearchListener = {
        onWeatherLiveSearched: (
          weatherLiveResult: LocalWeatherLiveResult | undefined,
          errorCode: number
        ): void => {
          // 不处理实时天气回调
        },
        onWeatherForecastSearched: (
          weatherForecastResult: LocalWeatherForecastResult | undefined,
          errorCode: number
        ): void => {
          if (errorCode === AMapException.CODE_AMAP_SUCCESS) {
            if (weatherForecastResult && 
                weatherForecastResult.getForecastResult() &&
                weatherForecastResult.getForecastResult().getWeatherForecast() &&
                weatherForecastResult.getForecastResult().getWeatherForecast().length > 0) {
              console.info(`[WeatherService] ✅ 预报天气查询成功: ${cityName}`)
              resolve(weatherForecastResult.getForecastResult())
            } else {
              console.warn(`[WeatherService] ⚠️ 预报天气查询无数据: ${cityName}`)
              resolve(null)
            }
          } else {
            console.error(`[WeatherService] ❌ 预报天气查询失败,错误码: ${errorCode}`)
            resolve(null)
          }
        }
      }
      
      // 创建查询参数
      // WEATHER_TYPE_FORECAST = 2:预报天气
      const query = new WeatherSearchQuery(cityName, WeatherSearchQuery.WEATHER_TYPE_FORECAST)
      
      // 创建天气搜索对象
      const weatherSearch = new WeatherSearch(this.context)
      weatherSearch.setOnWeatherSearchListener(weatherSearchListener)
      weatherSearch.setQuery(query)
      
      // 异步搜索
      weatherSearch.searchWeatherAsyn()
      console.info(`[WeatherService] 🔍 开始查询预报天气: ${cityName}`)
    } catch (error) {
      console.error(`[WeatherService] ❌ 预报天气查询异常:`, error)
      resolve(null)
    }
  })
}

5. 创建天气图标映射工具

// models/WeatherModels.ets

/**
 * 天气图标映射类
 * 将天气现象字符串映射为对应的图标资源
 */
export class WeatherIconMapper {
  /**
   * 根据天气现象返回对应的图标路径
   * @param weather 天气现象字符串(如"晴"、"多云"、"小雨")
   * @returns SVG 图标路径
   */
  static getIconPath(weather: string): string {
    const iconMap: Record<string, string> = {
      // 晴天类
      '晴': 'icons/weather/sunny.svg',
      '少云': 'icons/weather/sunny.svg',
      '热': 'icons/weather/sunny.svg',
      
      // 多云类
      '晴间多云': 'icons/weather/cloudy.svg',
      '多云': 'icons/weather/cloudy.svg',
      '有风': 'icons/weather/cloudy.svg',
      '微风': 'icons/weather/cloudy.svg',
      
      // 阴天类
      '阴': 'icons/weather/overcast.svg',
      '冷': 'icons/weather/overcast.svg',
      
      // 雨天类
      '小雨': 'icons/weather/rain.svg',
      '中雨': 'icons/weather/rain.svg',
      '大雨': 'icons/weather/rain.svg',
      '暴雨': 'icons/weather/rain.svg',
      '大暴雨': 'icons/weather/rain.svg',
      '特大暴雨': 'icons/weather/rain.svg',
      '毛毛雨': 'icons/weather/rain.svg',
      '雨': 'icons/weather/rain.svg',
      
      // 阵雨类
      '阵雨': 'icons/weather/shower.svg',
      '雷阵雨': 'icons/weather/shower.svg',
      '雷阵雨并伴有冰雹': 'icons/weather/shower.svg',
      
      // 雪天类
      '小雪': 'icons/weather/snow.svg',
      '中雪': 'icons/weather/snow.svg',
      '大雪': 'icons/weather/snow.svg',
      '暴雪': 'icons/weather/snow.svg',
      '雨夹雪': 'icons/weather/snow.svg',
      '阵雪': 'icons/weather/snow.svg',
      
      // 雾霾类
      '雾': 'icons/weather/fog.svg',
      '浓雾': 'icons/weather/fog.svg',
      '霾': 'icons/weather/fog.svg',
      '中度霾': 'icons/weather/fog.svg',
      '重度霾': 'icons/weather/fog.svg',
      '沙尘暴': 'icons/weather/fog.svg',
      '浮尘': 'icons/weather/fog.svg',
      '扬沙': 'icons/weather/fog.svg',
      
      // 默认
      '未知': 'icons/weather/default.svg'
    }
    
    return iconMap[weather] || 'icons/weather/default.svg'
  }
  
  /**
   * 获取天气对应的主题色
   * @param weather 天气现象字符串
   * @returns 颜色值
   */
  static getWeatherColor(weather: string): string {
    if (weather.includes('晴')) {
      return '#FFA500'  // 橙色 - 晴天
    } else if (weather.includes('云')) {
      return '#87CEEB'  // 天蓝色 - 多云
    } else if (weather.includes('雨')) {
      return '#4682B4'  // 钢蓝色 - 雨天
    } else if (weather.includes('雪')) {
      return '#B0E0E6'  // 粉蓝色 - 雪天
    } else if (weather.includes('雾') || weather.includes('霾')) {
      return '#808080'  // 灰色 - 雾霾
    } else {
      return '#A9846A'  // 默认驼色
    }
  }
}

6. 在页面中使用天气服务

// pages/WeatherDetailPage.ets
import { WeatherService } from '../services/WeatherService'
import { WeatherIconMapper } from '../models/WeatherModels'
import {
  LocalWeatherLive,
  LocalWeatherForecast,
  LocalDayWeatherForecast
} from '@amap/amap_lbs_search'
import { ArrayList } from '@kit.ArkTS'
import { common } from '@kit.AbilityKit'

@Entry
@Component
struct WeatherDetailPage {
  private context: Context = this.getUIContext().getHostContext() as Context
  
  @State cityName: string = '北京'
  @State weatherLive: LocalWeatherLive | null = null
  @State weatherForecast: LocalWeatherForecast | null = null
  @State forecastList: ArrayList<LocalDayWeatherForecast> = new ArrayList()
  @State isLoading: boolean = true
  
  aboutToAppear(): void {
    this.loadWeatherData()
  }
  
  /**
   * 加载天气数据(实时 + 预报)
   */
  private async loadWeatherData(): Promise<void> {
    this.isLoading = true
    
    try {
      const weatherService = new WeatherService(this.context as common.UIAbilityContext)
      
      // 并行获取实时天气和预报天气
      const livePromise = weatherService.searchLiveWeather(this.cityName)
      const forecastPromise = weatherService.searchForecastWeather(this.cityName)
      
      this.weatherLive = await livePromise
      this.weatherForecast = await forecastPromise
      
      if (this.weatherForecast) {
        this.forecastList = this.weatherForecast.getWeatherForecast()
      }
      
      console.info(`[WeatherDetailPage] ✅ 天气数据加载成功`)
    } catch (error) {
      console.error(`[WeatherDetailPage] ❌ 天气数据加载失败:`, error)
    } finally {
      this.isLoading = false
    }
  }
  
  build() {
    Column() {
      // 加载状态
      if (this.isLoading) {
        LoadingProgress().width(48).height(48)
        Text('加载天气数据...').fontSize(14).margin({ top: 12 })
      } else {
        // 实时天气卡片
        if (this.weatherLive) {
          this.LiveWeatherCard()
        }
        
        // 天气预报列表
        if (this.forecastList.length > 0) {
          this.ForecastList()
        }
      }
    }
    .width('100%')
    .height('100%')
    .padding(16)
  }
  
  @Builder
  LiveWeatherCard() {
    Column({ space: 8 }) {
      // 城市名称
      Text(this.cityName)
        .fontSize(18)
        .fontWeight(FontWeight.Medium)
      
      Row({ space: 24 }) {
        // 天气图标
        Image($rawfile(WeatherIconMapper.getIconPath(this.weatherLive!.getWeather() || '晴')))
          .width(64)
          .height(64)
        
        Column({ space: 4 }) {
          // 温度
          Text(`${this.weatherLive!.getTemperature() || '--'}°`)
            .fontSize(48)
            .fontWeight(FontWeight.Bold)
          
          // 天气现象
          Text(this.weatherLive!.getWeather() || '--')
            .fontSize(16)
            .fontColor('#666666')
        }
      }
      
      // 详细信息
      Row({ space: 16 }) {
        Text(`风向:${this.weatherLive!.getWindDirection() || '--'}`)
        Text(`风力:${this.weatherLive!.getWindPower() || '--'}级`)
        Text(`湿度:${this.weatherLive!.getHumidity() || '--'}%`)
      }
      .fontSize(14)
      .fontColor('#999999')
    }
    .width('100%')
    .padding(20)
    .backgroundColor('#FFFFFF')
    .borderRadius(12)
    .shadow({ radius: 4, color: '#00000010' })
  }
  
  @Builder
  ForecastList() {
    Column({ space: 8 }) {
      Text('未来天气预报')
        .fontSize(16)
        .fontWeight(FontWeight.Medium)
        .margin({ top: 16, bottom: 8 })
      
      ForEach(this.forecastList.convertToArray(), (item: LocalDayWeatherForecast) => {
        Row() {
          // 日期
          Column() {
            Text(item.getDate() || '--')
              .fontSize(14)
            Text(this.getWeekName(item.getWeek()))
              .fontSize(12)
              .fontColor('#999999')
          }
          .width(80)
          
          // 白天天气
          Row({ space: 4 }) {
            Image($rawfile(WeatherIconMapper.getIconPath(item.getDayWeather() || '晴')))
              .width(24)
              .height(24)
            Text(item.getDayWeather() || '--')
              .fontSize(14)
          }
          .layoutWeight(1)
          
          // 温度范围
          Text(`${item.getNightTemp() || '--'}° ~ ${item.getDayTemp() || '--'}°`)
            .fontSize(14)
            .fontColor('#666666')
        }
        .width('100%')
        .padding(12)
        .backgroundColor('#FFFFFF')
        .borderRadius(8)
      })
    }
  }
  
  private getWeekName(week: string | undefined): string {
    const weekMap: Record<string, string> = {
      '1': '周一', '2': '周二', '3': '周三', '4': '周四',
      '5': '周五', '6': '周六', '7': '周日'
    }
    return weekMap[week || ''] || ''
  }
}

返回数据说明

实时天气 LocalWeatherLive

方法 返回值 说明
getCity() string 城市名称
getWeather() string 天气现象(晴、多云、小雨等)
getTemperature() string 当前温度(摄氏度)
getWindDirection() string 风向(东、西南等)
getWindPower() string 风力等级(1-12级)
getHumidity() string 相对湿度(百分比)
getReportTime() string 数据发布时间

天气预报 LocalDayWeatherForecast

方法 返回值 说明
getDate() string 日期(YYYY-MM-DD)
getWeek() string 星期(1-7)
getDayWeather() string 白天天气现象
getNightWeather() string 夜间天气现象
getDayTemp() string 白天温度
getNightTemp() string 夜间温度
getDayWind() string 白天风向
getNightWind() string 夜间风向

效果

控制台日志:

[WeatherService] 🔍 开始查询实时天气: 北京
[WeatherService] 🔍 开始查询预报天气: 北京
[WeatherService] ✅ 实时天气查询成功: 北京
[WeatherService] ✅ 预报天气查询成功: 北京
[WeatherDetailPage] ✅ 天气数据加载成功

数据示例:

字段
城市 北京
天气
温度 25°
风向 东北风
风力 3级
湿度 45%

常见错误码

错误码 说明 解决方案
1001 参数错误 检查城市名称是否正确
1002 网络错误 检查网络连接
1003 服务不可用 稍后重试
1008 Key 无效 检查高德 Key 配置

关键点总结

步骤 说明
1. 创建查询参数 WeatherSearchQuery(城市, 类型)
2. 设置监听器 OnWeatherSearchListener 处理回调
3. 异步查询 searchWeatherAsyn() 非阻塞
4. 处理结果 判断 errorCode 是否成功
5. 图标映射 天气现象 → 图标资源路径

查询类型对比

类型 常量值 返回数据 使用场景
实时天气 WEATHER_TYPE_LIVE = 1 当前天气详情 首页天气展示
预报天气 WEATHER_TYPE_FORECAST

更多关于HarmonyOS 鸿蒙Next中使用高德天气 SDK 实现实时天气与预报查询的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS Next中集成高德天气SDK

步骤概述

1. 申请API Key

首先需要在高德开放平台申请API Key。

2. 创建项目

通过DevEco Studio创建项目。

3. 配置网络权限

module.json5配置文件中添加网络权限。

4. 使用天气API

  • 使用高德天气API接口,例如实时天气和预报查询。
  • 通过ArkTS的HTTP模块发起请求。
  • 解析返回的JSON数据。

5. 注意事项

  • SDK需适配HarmonyOS Next的API版本。
  • 确保兼容性。

在HarmonyOS Next中集成高德天气SDK实现天气查询,可以按照以下步骤进行:

1. 环境准备

  • 在AppGallery Connect中创建项目,并开启高德地图服务。
  • 下载高德天气SDK的HarmonyOS版本,将.har包放入工程的entry/libs目录。
  • module.json5中添加权限:
{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET"
      }
    ]
  }
}

2. 初始化SDK

EntryAbilityonCreate中初始化:

import weather from '@ohos/weather';

export default class EntryAbility extends Ability {
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    weather.init({
      apiKey: '你的高德开放平台Key'
    });
  }
}

3. 实时天气查询

使用异步任务避免阻塞UI:

import { weather } from '@ohos/weather';
import { BusinessError } from '@ohos.base';

async function getRealtimeWeather(city: string): Promise<void> {
  try {
    const result = await weather.getRealtimeWeather({
      city: city,
      extensions: 'base' // 返回基础信息
    });
    
    // 解析数据
    const temperature = result.temperature; // 温度
    const weatherDesc = result.weather; // 天气现象
    const windDirection = result.winddirection; // 风向
    const windPower = result.windpower; // 风力
    const humidity = result.humidity; // 湿度
    
    // 更新UI(需在主线程)
    getContext().uiTaskCenter.executeTask(() => {
      // 更新UI组件
    });
  } catch (error) {
    const err: BusinessError = error as BusinessError;
    console.error(`查询失败: ${err.code} ${err.message}`);
  }
}

4. 天气预报查询

async function getWeatherForecast(city: string, days: number): Promise<void> {
  try {
    const result = await weather.getWeatherForecast({
      city: city,
      extensions: 'all', // 返回预报信息
      days: days
    });
    
    // 处理预报数据
    result.forecasts.forEach((forecast: any) => {
      const date = forecast.date; // 日期
      const dayTemp = forecast.daytemp; // 白天温度
      const nightTemp = forecast.nighttemp; // 夜间温度
      const dayWeather = forecast.dayweather; // 白天天气
      const nightWeather = forecast.nightweather; // 夜间天气
    });
  } catch (error) {
    // 错误处理
  }
}

5. 天气图标显示

建议方案:

  • 下载高德天气图标包(或自定义图标)
  • 根据返回的天气代码映射图标:
const weatherIcons: Map<string, string> = new Map([
  ['晴', 'sunny.png'],
  ['多云', 'cloudy.png'],
  ['雨', 'rain.png'],
  // ...其他映射
]);

function getWeatherIcon(weatherDesc: string): Resource {
  const iconName = weatherIcons.get(weatherDesc) || 'default.png';
  return $r(`app.media.${iconName}`);
}

6. 异步处理最佳实践

  • 使用TaskPoolWorker处理复杂计算
  • UI更新通过uiTaskCenter.executeTask()回到主线程
  • 添加加载状态和错误重试机制

关键注意事项

  1. 确保网络权限正确配置
  2. 高德Key需要在真机测试
  3. 注意API调用频率限制
  4. 错误处理要完善,特别是网络异常情况

通过以上实现,可以完成天气查询功能,且不会阻塞UI线程。

回到顶部