weather
当前天气与每日/每小时预报(WeatherKit)。
当前天气与预报(基于 Apple WeatherKit)。支持按坐标查询、按设备位置查询,以及多日/多小时预报。
边界:需要 App 开启 WeatherKit 能力(Apple Developer 配置 + 带 entitlement 的签名构建)。current_location() 还需要定位权限;不包含地图或定位 UI,定位请看 location。
#模块概览
| 项 | 说明 |
|---|---|
| 导入 | import weather |
| 适合做什么 | 天气卡片、出行建议、温度/湿度/风速展示、短期预报 |
| 调用时机 | 放在按钮回调或加载任务;不要写在 AppUI body() 中 |
| 推荐顺序 | 需要时申请定位 → current / current_location → 可选 daily / hourly |
| 单位约定 | 温度 °C;风速 m/s;湿度 0..1;symbol 为 SF Symbol 名 |
#快速开始
下面脚本按坐标查询上海当前天气,并打印未来 3 天预报:
已复制
import weather
LAT, LON = 31.2304, 121.4737
try:
now = weather.current(LAT, LON)
print(f"{now['temperature']:.1f}°C", now["condition"], now["symbol"])
print(f"体感 {now['feels_like']:.1f}°C · 湿度 {now['humidity']:.0%}")
days = weather.daily(LAT, LON, days=3)
for day in days:
print(day["date"][:10], day["low"], "~", day["high"], "°C", day["condition"])
except weather.WeatherError as exc:
print("查询失败:", exc, f"(code={exc.code})")
#AppUI 示例
天气请求放进按钮回调;结果写进 State,用 symbol 显示 SF Symbol 图标。
已复制
import appui
import permission
import weather
DEMO_LAT = 31.2304
DEMO_LON = 121.4737
state = appui.State(
temp="—",
summary="点击按钮开始",
symbol="cloud",
forecast="—",
message="",
)
def _apply_current(now, label):
state.temp = f"{now.get('temperature', 0):.1f}°C"
state.summary = now.get("condition", "—")
state.symbol = now.get("symbol", "cloud")
state.message = f"{label}查询成功"
def _format_forecast(days):
lines = []
for day in days[:3]:
date = str(day.get("date", ""))[:10]
low = day.get("low", "—")
high = day.get("high", "—")
lines.append(f"{date} {low}~{high}°C {day.get('condition', '')}")
return "\n".join(lines) if lines else "暂无预报"
def load_shanghai():
try:
now = weather.current(DEMO_LAT, DEMO_LON)
_apply_current(now, "上海")
state.forecast = _format_forecast(
weather.daily(DEMO_LAT, DEMO_LON, days=3)
)
except weather.WeatherError as exc:
state.message = f"查询失败: {exc} (code={exc.code})"
def load_here():
entry = permission.status("location")
if not entry.get("authorized"):
permission.request("location")
entry = permission.status("location")
if not entry.get("authorized"):
state.message = "需要定位权限,请先在系统弹窗中允许"
return
try:
now = weather.current_location()
_apply_current(now, "当前位置")
except weather.WeatherError as exc:
state.message = f"查询失败: {exc} (code={exc.code})"
def body():
return appui.NavigationStack(
appui.Form([
appui.Section("当前", [
appui.Image(system_name=state.symbol).font("largeTitle"),
appui.LabeledContent("温度", value=state.temp),
appui.LabeledContent("状况", value=state.summary),
]),
appui.Section("操作", [
appui.Button("查询上海天气", action=load_shanghai)
.button_style("bordered_prominent"),
appui.Button("查询当前位置天气", action=load_here),
]),
appui.Section("3 日预报", [
appui.Text(state.forecast).font("caption").foreground_color("secondaryLabel"),
appui.Text(state.message).font("caption2").foreground_color("tertiaryLabel"),
], footer="需要 WeatherKit 能力与网络;真机测试最可靠。"),
]).navigation_title("天气")
)
appui.run(body, state=state)
#API 参考
#速查
| API | 作用 |
|---|---|
current(lat, lon) | 按坐标查当前天气 → dict |
current_location() | 按设备位置查当前天气 → dict(需定位权限) |
daily(lat, lon, days=7) | 每日预报 → list[dict] |
hourly(lat, lon, hours=24) | 每小时预报 → list[dict] |
WeatherError | 查询失败时抛出的异常 |
#当前天气
current(latitude, longitude) — 按经纬度查询。
已复制
now = weather.current(37.33, -122.03)
print(now["temperature"], now["symbol"])
current_location() — 使用设备当前位置,需先获得定位授权。
已复制
import permission
if not permission.status("location").get("authorized"):
permission.request("location")
now = weather.current_location()
当前天气常见字段:
| 字段 | 说明 |
|---|---|
temperature / feels_like | 气温 / 体感温度(°C) |
condition | 天气状况文字 |
symbol | SF Symbol 名,可配合 appui.Image(system_name=...) |
humidity | 湿度(0..1) |
wind_speed | 风速(m/s) |
uv_index | 紫外线指数 |
is_daylight | 是否白天 |
#预报
daily(latitude, longitude, days=7) — 返回每日预报列表。
已复制
days = weather.daily(31.23, 121.47, days=5)
for day in days:
print(day["date"], day["low"], day["high"], day["symbol"])
每日字段:date、condition、symbol、high、low、precipitation_chance。
hourly(latitude, longitude, hours=24) — 返回每小时预报列表。
已复制
hours = weather.hourly(31.23, 121.47, hours=12)
for hour in hours:
print(hour["date"], hour["temperature"], hour["condition"])
每小时字段:date、condition、symbol、temperature、precipitation_chance。
#异常
查询失败时抛出 WeatherError,可通过 exc.code 区分原因:
code | 含义 |
|---|---|
unavailable | 系统版本过低、WeatherKit 未启用或暂无数据 |
weatherkit_auth | WeatherKit JWT/entitlement 未正确配置 |
denied | 定位权限未授权(current_location) |
network_error | 网络或 WeatherKit 服务异常 |
已复制
try:
weather.current(0, 0)
except weather.WeatherError as exc:
print(exc.code, exc)
#常见错误
| 错误写法 | 后果 | 修正 |
|---|---|---|
在 body() 里调 weather.current() | 每次刷新都联网 | 放进按钮回调,结果写进 State |
未授权就 current_location() | 抛出 WeatherError(code="denied") | 先 permission.request("location") |
| 未配置 WeatherKit | weatherkit_auth 或 unavailable | 在 Developer 为 App ID 开启 WeatherKit 并重装 |
不捕获 WeatherError | 异常直接打断流程 | 用 try/except 并给出兜底 UI |
#相关文档
| 文档 | 用途 |
|---|---|
| location | 定位权限与坐标 |
| permission | 统一查询 location 权限 |
| 原生能力入口 | MiniApp 场景配方 |
#预期效果
运行示例后,界面应出现文档描述的目标结果;若与预期不符,先看「失败路径」并按返回值或日志排查。