更新记录
1.0.0(2026-11-10) 下载此版本
变更
- 统一异步 Promise API:
initialize、setItem、getItem、removeItem、generateKeyBase64。 - Android、iOS、HarmonyOS 统一使用应用层认证加密,系统安全存储用于保护主密钥。
- 增加旧 Android、iOS、HarmonyOS 数据的按条目迁移入口,遵循先写新数据、验证后删除旧数据。
- HarmonyOS 写入、读取、删除和初始化等待真实 Asset Store 操作完成。
- 主密钥缺失且仍存在新格式密文时拒绝生成新密钥,避免静默丢失旧数据。
- 修复 HarmonyOS 空字符串读取,并为旧数据迁移增加写入后回读校验。
- HarmonyOS 支持使用 CryptoArchitectureKit 生成 32 字节随机 Base64 密钥,三端 API 行为统一。
- 初始化结果移除无法准确表达惰性迁移状态的
migrated字段。 - 三端错误统一为
UniError扩展对象,提供统一的errSubject、errCode和errMsg,并在错误消息中保留稳定字符串错误码。 - Android 示例页补充结构化错误码 Smoke 检查;独立 instrumentation 测试和 iOS/HarmonyOS 验证仍未完成。
注意
- 本版本为插件首次公开发布,支持 Android、iOS 和 HarmonyOS。当前仅完成 Android 编译、真机验证和迁移验收;iOS、HarmonyOS 未进行本次发布前的编译和真机验证,使用方应将这两个平台视为未验证平台。
- Android 本地 Backup Transport 恢复验证通过:恢复密文但缺少 Keystore 主密钥时返回
MASTER_KEY_MISSING,不会静默生成新密钥。 - Web 不提供实现。
- 正式发布前必须完成仓库根目录
RELEASE_PLAN.md中仍适用于本次发布范围的迁移、测试和元数据任务。 - iOS Privacy Manifest 的官方 reason code、资源打包和 Xcode Archive 结果本次未核验。
平台兼容性
uni-app x(4.0)
| Chrome | Safari | Android | iOS | 鸿蒙 | 微信小程序 |
|---|---|---|---|---|---|
| × | × | 6.0 | 13 | 11.0 | - |
其他
| 多语言 | 暗黑模式 | 宽屏模式 | 蒸汽模式 |
|---|---|---|---|
| √ | √ | √ | √ |
Diboy Secure Storage
面向 uni-app x 的本地加密键值存储 UTS 插件,用于安全保存 Token、数据库密钥、设备标识等少量敏感字符串。插件使用 Android Keystore、iOS Keychain 和 HarmonyOS Asset Store 保护应用主密钥,并使用 AES-GCM 加密业务 value。
当前版本:1.0.0。插件支持 Android、iOS 和 HarmonyOS;本次发布已完成 Android 编译、真机验证和迁移验收,iOS、HarmonyOS 已提供实现但未进行本次发布前的编译和真机验证,使用方应将这两个平台视为未验证平台。
插件支持 uni-app x Vapor 模式;Android 已完成 Vapor 编译验证,iOS 和 HarmonyOS 尚未完成本次发布前验证。
支持范围
| 平台 | 系统安全存储 | 应用层加密 | 最低版本 |
|---|---|---|---|
| Android | Android Keystore | AES-GCM | API 23 |
| iOS | Keychain | CryptoKit AES-GCM | iOS 13 |
| HarmonyOS | Asset Store | CryptoArchitectureKit AES-GCM | API 11 |
| Web | 不支持 | 不支持 | - |
插件不提供明文存储降级。业务 value 不应存放大文件,当前上限为 1MB;key 上限为 UTF-8 256 字节。
功能概览
- 初始化本地安全存储,并检测当前设备是否具备所需安全能力。
- 加密写入、读取和删除字符串键值。
- 对已有旧格式条目进行逐条迁移,迁移成功后才删除旧数据。
- Android、iOS 和 HarmonyOS 生成 32 字节 Base64 密钥,可用于本地数据库加密。
- 不连接远程服务,不采集数据,不申请额外系统权限。
适合保存 refresh token、session token、本地数据库密钥和少量配置密钥;不适合保存对象、二进制数据、文件或大文本。
安装
在 HBuilderX 中通过 uni_modules 安装插件,或将 uni_modules/diboy-secure-storage 目录放入项目的 uni_modules 目录。插件仅支持 uni-app x App,不支持传统 uni-app 和 Web。
导入
import {
initialize,
getSecureStorageCapabilities,
setItem,
getItem,
removeItem,
generateKeyBase64,
} from '@/uni_modules/diboy-secure-storage'
应用启动时先初始化一次,初始化是幂等的:
async function useSecureStorage(): Promise<void> {
await initialize()
await setItem('example.key', 'example value')
const value = await getItem('example.key')
console.log(`stored value: ${value == null ? 'not found' : value}`)
await removeItem('example.key')
}
getItem 找不到条目时返回 null。写入、读取、删除、初始化失败时 Promise reject SecureStorageErrorImpl。这是标准 UniError 扩展对象:使用 error.errCode 获取数字错误码,使用 error.errMsg 获取 错误码:错误描述;稳定字符串错误码是 error.errMsg 中冒号前的部分。业务日志不得输出 key、value、Token、密钥或密文。
API
调用顺序
- 应用启动时调用一次
initialize()。 - 初始化成功后调用
setItem()、getItem()或removeItem()。 generateKeyBase64()可独立调用,不依赖插件内部主密钥初始化。
initialize()
const result = await initialize()
- 参数:无
- 返回:
Promise<SecureStorageInitializationResult> initialized:是否初始化成功capabilities:本机安全能力,结构见下文- 失败:Promise reject
Error - 常见错误:
UNSUPPORTED_API_LEVEL、KEYSTORE_UNAVAILABLE、KEY_RETRIEVAL_FAILED、KEY_GENERATION_FAILED、MASTER_KEY_MISSING、MASTER_KEY_INVALIDATED、LEGACY_MIGRATION_FAILED
初始化是幂等的,可以重复调用,但建议在应用启动流程中集中调用一次。主密钥丢失或失效时会失败,不会自动生成新主密钥覆盖已有密文。
getSecureStorageCapabilities()
const capabilities = getSecureStorageCapabilities()
- 参数:无
- 返回:
SecureStorageCapabilities,同步返回 supported:当前设备是否支持插件platform:平台名称minApiLevel:插件要求的最低系统 API 级别apiLevel:当前设备系统 API 级别keystoreAvailable:系统安全存储是否可用aesGcmAvailable:AES-GCM 是否可用error:不支持时的错误对象,否则为null
这是可选的预检查和诊断 API,不负责初始化,也不负责创建主密钥。普通业务直接调用 initialize() 即可;HarmonyOS 建议在初始化成功后再读取该结果,以获得完整的能力状态。
setItem(key, value)
await setItem('session.refreshToken', refreshToken)
key:string,不能为空,UTF-8 长度不超过 256 字节value:string,UTF-8 长度不超过 1 MiB- 返回:
Promise<void>,成功时无返回值 - 前置条件:必须先成功调用
initialize() - 常见错误:
INITIALIZATION_REQUIRED、INVALID_KEY、KEY_TOO_LONG、VALUE_TOO_LARGE、ENCRYPTION_FAILED、PREFERENCES_WRITE_FAILED、MASTER_KEY_MISSING
getItem(key)
const refreshToken = await getItem('session.refreshToken')
key:string,不能为空,UTF-8 长度不超过 256 字节- 返回:
Promise<string | null>;条目存在时返回明文字符串,不存在时返回null - 前置条件:必须先成功调用
initialize() - 常见错误:
INITIALIZATION_REQUIRED、INVALID_KEY、KEY_TOO_LONG、DECRYPTION_FAILED、AUTHENTICATION_FAILED、ENVELOPE_INVALID、MASTER_KEY_MISSING、PREFERENCES_READ_FAILED、LEGACY_MIGRATION_FAILED
removeItem(key)
await removeItem('session.refreshToken')
key:string,不能为空,UTF-8 长度不超过 256 字节- 返回:
Promise<void>,成功时无返回值;条目不存在时也视为成功 - 前置条件:必须先成功调用
initialize() - 常见错误:
INITIALIZATION_REQUIRED、INVALID_KEY、KEY_TOO_LONG、PREFERENCES_REMOVE_FAILED、MASTER_KEY_MISSING
generateKeyBase64()
const databaseKey = await generateKeyBase64()
- 参数:无
- 返回:
Promise<string>,32 字节随机密钥的 Base64 字符串,通常长度为 44 个字符(包含结尾=) - 前置条件:无,可独立调用
- 用途:生成业务侧本地数据库或其他本地加密场景使用的密钥
- 常见错误:
KEY_GENERATION_FAILED、UNSUPPORTED_PLATFORM
该密钥与插件内部主密钥相互独立。插件不会自动保存或恢复此密钥;业务应使用 setItem() 将其安全保存,并在使用数据库前先读取并校验。
所有异步 API 都必须使用 await 或 Promise 链处理。捕获异常时应读取 error.errMsg 前缀或 error.errCode;业务应根据错误码采取重试、重新登录或恢复流程,不应因为任意错误直接清空安全存储。
建议统一捕获异常并根据错误码处理:
try {
await initialize()
const token = 'your-token'
await setItem('session.token', token)
} catch (error) {
// 生产环境只记录错误码,不要记录 token 或密文。
console.error(`secure storage failed: ${error.errMsg}`)
}
常见错误码包括:INITIALIZATION_REQUIRED、INVALID_KEY、KEY_TOO_LONG、VALUE_TOO_LARGE、MASTER_KEY_MISSING、MASTER_KEY_INVALIDATED、STORAGE_LOCKED、AUTHENTICATION_FAILED 和 UNSUPPORTED_PLATFORM。完整错误码以 SecureStorageErrorCode 导出类型为准。
错误码按场景可分为:
- 参数错误:
INVALID_KEY、KEY_TOO_LONG、VALUE_TOO_LARGE - 平台能力错误:
UNSUPPORTED_PLATFORM、UNSUPPORTED_API_LEVEL、KEYSTORE_UNAVAILABLE、CAPABILITY_CHECK_FAILED - 主密钥错误:
KEY_GENERATION_FAILED、KEY_RETRIEVAL_FAILED、KEY_INVALIDATED、MASTER_KEY_MISSING、MASTER_KEY_INVALIDATED - 数据完整性错误:
INVALID_IV、INVALID_CIPHERTEXT、AUTHENTICATION_FAILED、ENVELOPE_INVALID、DECRYPTION_FAILED - 持久化错误:
PREFERENCES_OPEN_FAILED、PREFERENCES_READ_FAILED、PREFERENCES_WRITE_FAILED、PREFERENCES_REMOVE_FAILED - 迁移和状态错误:
INITIALIZATION_REQUIRED、STORAGE_LOCKED、LEGACY_MIGRATION_FAILED、LEGACY_DATA_INVALID、INTERNAL_ERROR
生成数据库密钥
Android、iOS 和 HarmonyOS 均支持生成随机数据库密钥:
const databaseSecret = await generateKeyBase64()
generateKeyBase64() 生成的是供业务使用的独立随机密钥,不是插件内部主密钥。插件内部主密钥仍由各平台安全存储独立管理。
安全模型
- 三端生成随机应用主密钥,并由系统安全存储保护。
- 业务 value 使用版本化 AES-GCM Envelope 保存,不直接保存明文。
- Envelope 绑定格式版本、主密钥版本和业务 key,篡改或跨 key 替换会认证失败。
- 此前版本产生的 Android、iOS、HarmonyOS 数据按条目迁移:读取旧值、写入新格式、回读验证成功后删除旧数据。
- 主密钥丢失或失效不会静默生成新密钥覆盖旧数据;调用方应根据错误码进入恢复或重新登录流程。
兼容和限制
- 设备首次解锁后可用;设备安全存储暂不可用时应重试,不应清空业务数据。
- Android 备份、iOS Keychain 卸载保留和 HarmonyOS 设备迁移行为由平台决定,业务不应把安全存储当作跨设备备份。Android 本地 Backup Transport 已验证:恢复密文但缺少 Keystore 主密钥时返回
MASTER_KEY_MISSING,不会静默生成新密钥。 - 当前不支持 Web、对象序列化、二进制 API 和大文件存储。
数据和安全边界
- 插件不采集数据、不连接远程服务、不包含广告,也不申请额外系统权限。
- 插件保护的是本地存储数据,不承诺防止已完全控制设备的攻击,也不是跨设备备份方案。
- 主密钥丢失或失效时会返回错误,不会静默生成新密钥覆盖已有密文;业务应进入恢复或重新登录流程。
- 卸载重装、系统备份恢复和设备迁移行为由系统平台决定,业务应自行设计恢复策略。
发布状态
作者:Diboy
版权:diboy.cn
许可证:MIT
仓库:https://cnb.cool/diboycn/Diboy.SecureStorage
问题反馈:https://cnb.cool/diboycn/Diboy.SecureStorage/-/issues
发布验证状态:Android 已完成编译、真机迁移、篡改、锁屏/解锁、进程终止和备份恢复验证,示例页包含最小 Smoke 流程;iOS、HarmonyOS 的编译和真机验证尚未完成,使用方应将这两个平台视为未验证平台。iOS Privacy Manifest 的官方 reason code 和最终打包结果尚未核验。

收藏人数:
https://cnb.cool/diboycn/Diboy.SecureStorage
下载插件并导入HBuilder
赞赏(0)
下载 0
赞赏 0
下载 12755599
赞赏 1959
赞赏
京公网安备:11010802035340号