MiniApp 开发排错
排查入口、状态、按钮、输入、列表、布局和系统能力问题。
排错先看运行时是否选对,再看入口是否完整,最后查状态、交互、布局和系统能力。不要只确认“预览能打开”,还要确认按钮、输入、搜索、刷新和弹层都能产生可见变化。
#最小健康样例
已复制
import appui
state = appui.State(saved=False)
def save():
state.saved = True
def body():
label = "Saved" if state.saved else "Not saved"
return appui.NavigationStack(
appui.Form([
appui.Section("Action", [
appui.LabeledContent("Status", value=label),
appui.Button("Save", action=save)
.button_style("bordered_prominent"),
])
]).navigation_title("排错")
)
appui.run(body, state=state)
预期效果:页面显示保存状态,点击 Save 后状态从 Not saved 变成 Saved。
#快速定位
| 现象 | 先查 | 继续看 |
|---|---|---|
| 预览打不开 | import appui、body()、appui.run(...) | 快速上手 |
| 点按钮没反应 | action 是否传函数本身 | AppUI API 地图 |
| 输入不更新 | on_change 是否写回 State | 状态管理 |
| 列表刷新错乱 | ForEach 是否有稳定 key | 布局系统 |
| 页面不像原生 App | 是否使用 List、Form、NavigationStack | AppUI UI 模式 |
| 高频刷新卡顿 | Timer 是否在 body() 外创建 | 性能与实时界面 |
| 权限或系统能力失败 | 是否处理拒绝、取消和不可用 | 原生能力入口 |
#正确的按钮写法
已复制
def save():
state.saved = True
appui.Button("Save", action=save)
不要这样写:
已复制
appui.Button("Save", action=save())
save() 会在构建页面时立刻执行,按钮拿不到正确回调。
#正确的列表写法
已复制
def row_key(row):
return row["id"]
def row_view(row):
return appui.Text(row["title"])
appui.ForEach(rows, row_builder=row_view, key=row_key)
不要把筛选后的 index 当 key。删除、重排、搜索后 index 会变化,行状态可能错位。
#运行前检查
- 完整示例应该能独立复制运行,入口只保留一次
appui.run(...)。 - 按钮、输入、搜索、刷新和弹层都应该有可见状态变化。
- 动态列表必须有稳定
key,删除、搜索、重排后不能错行。 - 涉及相册、相机、定位、通知、健康数据等能力时,要处理权限拒绝、用户取消和设备不可用。
- 网络、文件、权限请求不要直接写在
body()里,放到按钮、刷新或明确的加载动作中。 - 失败时保留旧数据或显示空状态,不要让页面静默空白。
#失败路径
- 空白:先跑本页“最小健康样例”。如果它能显示,问题通常在你的状态、资源、权限或页面结构中。
- 交互无效:确认回调是命名函数,并且回调里修改了
State。 - 输入无法保存:确认
on_change接收新值,保存按钮读取的是同一个State。 - 列表错行:确认每个数据项有稳定 id,并传给
ForEach(..., key=...)。 - 页面结构失控:回到 AppUI UI 模式,先确定页面类型。
#相关文档
| 文档 | 用途 |
|---|---|
| 运行时选择 | 判断 AppUI、widget、ui、scene 和 console。 |
| 快速上手 | 用四个可预览示例掌握入口、状态、表单和导航。 |
| AppUI UI 模式 | 常见页面结构和反模式。 |
| AppUI API 地图 | 按任务查 API。 |
| 原生能力入口 | 系统能力、权限和失败路径。 |