storage
UserDefaults 持久键值存储。
轻量级键值存储(基于 UserDefaults):保存设置项、开关、计数和小型 JSON 配置。
边界:适合小数据偏好,不是文件数据库,也不是敏感数据存储。token / 密码用 keychain;大列表、离线缓存用 database。默认数据按 Python 文件或 MiniApp 的稳定 ID 隔离;不同所有者可以放心使用相同键名。
写入后可在「设置 → 应用数据」中直接查看和修改,不需要把经常变化的值写死在代码里。关联小组件可读取显式声明或代码中直接使用的键;界面只显示脚本使用的简单键名,不显示内部隔离前缀。
「应用数据」用于普通状态和配置,不是密码库。Cookie、Token、密码、API Key 等敏感值请使用 keychain;浏览器 Cookie、网页 localStorage 和 keychain 内容不会出现在该页面。
#模块概览
| 项 | 说明 |
|---|---|
| 导入 | import storage |
| 适合做什么 | 主题、排序、筛选条件、开关、小型 JSON 配置 |
| 调用时机 | 在 on_change、按钮回调或启动时读写;不要在 body() 里反复写入 |
| 推荐顺序 | 启动时 get(带默认值)→ 用户操作后 set → 需要时 remove / all_keys |
| 键名规范 | 用 settings.theme 这类分组名,便于本文件批量管理 |
| 跨脚本共享 | 只有确实需要共享时才使用 storage.shared.* |
#快速开始
下面脚本写入并读取字符串、布尔、整数和 JSON:
import storage
storage.set("settings.theme", "dark")
storage.set_bool("settings.notifications", True)
storage.set_int("app.launch_count", storage.get_int("app.launch_count", 0) + 1)
storage.set_json("profile", {"name": "Ada", "level": 3})
print("主题:", storage.get("settings.theme", "system"))
print("通知:", storage.get_bool("settings.notifications", False))
print("启动次数:", storage.get_int("app.launch_count", 0))
print("资料:", storage.get_json("profile", {}))
#AppUI 示例
设置项与 State 同步:用户改动时写入 storage,启动时从 storage 恢复。
import appui
import storage
THEME_OPTIONS = ["跟随系统", "浅色", "深色"]
state = appui.State(
theme=storage.get("settings.theme", "跟随系统"),
notifications=storage.get_bool("settings.notifications", True),
message="设置会自动保存",
)
def set_theme(value):
state.theme = value
storage.set("settings.theme", value)
state.message = f"主题已保存: {value}"
def set_notifications(value):
state.notifications = value
storage.set_bool("settings.notifications", value)
state.message = "通知开关已保存" if value else "通知已关闭"
def reset_settings():
for key in storage.all_keys(prefix="settings."):
storage.remove(key)
state.batch_update(
theme="跟随系统",
notifications=True,
message="已重置 settings.* 下的所有键",
)
def body():
return appui.NavigationStack(
appui.Form([
appui.Section("偏好", [
appui.Picker(
"主题",
selection=state.theme,
options=THEME_OPTIONS,
on_change=set_theme,
).picker_style("segmented"),
appui.Toggle(
"允许通知",
is_on=state.notifications,
on_change=set_notifications,
),
]),
appui.Section("维护", [
appui.Button("重置设置", action=reset_settings, role="destructive"),
appui.Text(state.message).foreground_color("secondaryLabel"),
]),
]).navigation_title("设置")
)
appui.run(body, state=state)
#API 参考
#速查
| API | 作用 |
|---|---|
get(key, default) / set(key, value) | 字符串读写 |
get_bool / set_bool | 布尔读写 |
get_int / set_int | 整数读写 |
get_float / set_float | 浮点数读写 |
get_json / set_json | JSON 对象读写 |
has_key(key) | 判断键是否存在 |
remove(key) | 删除一个键 |
all_keys(prefix="") | 列出键,可按前缀筛选 |
shared.<同名 API> | 显式读写所有获准脚本共用的公共区 |
#基础读写
import storage
storage.set("settings.theme", "dark")
theme = storage.get("settings.theme", "system")
storage.set_bool("settings.done", True)
done = storage.get_bool("settings.done", False)
storage.set_int("counter", 3)
storage.set_float("volume", 0.8)
| API | 返回 | 说明 |
|---|---|---|
get(key, default=None) | str 或 default | 键不存在时返回 default |
set(key, value) | None | 写入字符串或可转字符串的值;失败时抛出异常,旧值保持不变 |
get_int / set_int | int / None | 计数、索引、步进值 |
get_float / set_float | float / None | 比例、阈值、音量 |
get_bool / set_bool | bool / None | 开关状态 |
注意:读取时总是传 default,让首次运行和清空后仍能正常工作。
#JSON
get_json(key, default=None) / set_json(key, value) — 存取 JSON 可序列化对象。
storage.set_json("filters", {"status": "open", "sort": "date"})
filters = storage.get_json("filters", {})
保持 JSON 小而稳定;大列表、图片、日志请改用 database 或文件。
#键管理
has_key(key) — 判断当前脚本或 MiniApp 的隔离空间内是否存在该键。
remove(key) — 删除键;MiniApp 会同时清理稳定 ID 和旧目录前缀下的兼容值,但不会访问应用自身的其他设置。
all_keys(prefix="") — 列出键,传前缀可清理一组设置:
for key in storage.all_keys(prefix="settings."):
storage.remove(key)
MiniApp 内 all_keys 返回的是去掉应用前缀后的逻辑键名,便于脚本按 settings.* 管理。
脚本在本次运行中创建的 Python 子线程会继承同一个私有存储身份;运行结束后该身份立即失效,因此旧线程或延迟回调不能误写到下一次运行的文件或 MiniApp。
同一个 Python 文件无论通过编辑器运行按钮还是项目终端中的 python3 文件.py 启动,都会使用同一个私有存储空间。终端中的 python3 -c 和交互式片段没有独立文件身份,因此使用当前项目目录专属的 Terminal 私有空间;不同项目目录之间仍然互相隔离。以上入口都可以显式访问同一个 storage.shared.* 公共区。
#公共数据
默认的 storage.* 永远属于当前 Python 文件或 MiniApp。需要让多个组件协作时,显式改用 storage.shared.*;公共区提供与默认区相同的类型化 API:
import storage
storage.shared.set_json("player.now_playing", {
"title": "示例视频",
"position": 42,
})
snapshot = storage.shared.get_json("player.now_playing", {})
普通 Python 文件可直接使用公共区。MiniApp 除 storage 外,还必须在 miniapp.json 的 capabilities 中声明 shared_storage:
{
"capabilities": ["storage", "shared_storage"]
}
公共数据会在「设置 → 应用数据 → 公共数据」单独显示。升级前由旧版脚本写入的全局数据也会在这里读取;下一次保存同名公共值时会无损迁移到新公共命名空间。公共区仍然不能保存 Cookie、Token、密码或 API Key。
#常见错误
| 错误写法 | 后果 | 修正 |
|---|---|---|
把 token 放进 storage | 敏感数据不安全 | 使用 keychain |
为了“省事”把所有状态都放进 storage.shared | 无关脚本可以读取或覆盖 | 默认使用 storage,只共享明确的协作状态 |
MiniApp 未声明 shared_storage 就访问公共区 | 抛出权限错误 | 在清单中显式声明,或改回私有 storage |
读取不传 default | 首次运行显示 None | storage.get("key", default) |
| 大列表 / 图片塞进 JSON | 慢、占空间 | 改用 database 或文件 |
#相关文档
#预期效果
运行示例后,界面应出现文档描述的目标结果;若与预期不符,先看「失败路径」并按返回值或日志排查。