资讯动态

shared_preferences 演进全史:从 0.1.0 到 2.5.5 的 API 架构、平台联邦化与迁移实践

发布时间:2026/9/19 10:19:27 来源:尧图企业网站定制
shared_preferences 演进全史从 0.1.0 到 2.5.5 的 API 架构、平台联邦化与迁移实践【免费下载链接】packagesA collection of useful packages maintained by the Flutter team项目地址: https://gitcode.com/GitHub_Trending/pac/packages本篇文章以 shared_preferences 的 CHANGELOG 为时间轴主线系统梳理 Flutter 团队官方维护的shared_preferences插件从 2017 年开源初版到 2.5.5 的完整演进历程。通过对照当前仓库中的真实源码与配置文件读者可以理解其从单体插件到联邦化federated架构的转变、SharedPreferences旧 API 与SharedPreferencesAsync/SharedPreferencesWithCache新 API 的取舍逻辑、setPrefix与allowList过滤机制、Android 安全更新与存储后端切换以及如何借助迁移工具与 DevTools 扩展平滑升级存量代码。一、插件定位为“简单键值对”而生的官方持久化方案shared_preferences是 Flutter 官方维护的持久化插件负责在移动端与桌面端封装平台原生的简单键值存储。根据其 pubspec.yaml 的描述Flutter plugin for reading and writing simple key-value pairs. Wraps NSUserDefaults on iOS and SharedPreferences on Android.在 Android 上底层是SharedPreferences新版 API 默认改为 DataStore Preferences在 iOS/macOS 上是NSUserDefaultsWeb 上是LocalStorageLinux 上是XDG_DATA_HOME目录Windows 上是 roaming AppData 目录。支持的数据类型固定为五种int、double、bool、String、ListString。一个重要的使用前提写在其 README.md 中数据是异步落盘的写入方法返回后不保证已经持久化到磁盘因此该插件不得用于存储关键数据。这一点从 CHANGELOG 中0.5.21的“.commit()调用在 Android 上改为异步后台任务执行”也能得到印证——写盘始终是异步、尽力而为的。二、CHANGELOG 揭示的核心演进主线这份 CHANGELOG 从0.1.0Initial Open Source release一直记录到2.5.5其演进主线可以归纳为四条API 现代化、架构联邦化、平台支持扩展、稳定性与安全加固。下面逐条展开。2.1 早期 API 打磨0.1.0 – 0.5.x从“能用”到“好用”早期版本0.1.0 到 0.5.x主要是功能补齐与 Android 工具链适配0.2.0升级到新的插件注册机制plugin registration从 Flutter 1.x 早期的手动注册走向自动注册。0.2.1setInt支持任意长度整数。0.2.2破坏性变更setStringSetAPI 改为setStringList并支持有序存储。0.2.4新增setMockInitialValues为单元测试提供注入 mock 数据的能力该能力在0.5.33中进一步支持重复调用并自动reload()单例。0.2.5修复设置 null 值导致崩溃的问题——现在 set 一个 null 值会触发 key 被移除同时新增remove()方法。0.3.2新增get泛型 getter可读取任意类型的值。0.4.1新增getKeys()方法返回存储中所有 key。0.5.2新增containsKey()方法。0.5.3新增reload()方法用于重新从平台读取最新数据——这是解决“原生代码修改了底层存储而 Dart 侧缓存未同步”的关键手段。0.5.1Android 上 double 改为以字符串形式存储避免精度问题。这些能力在今天的 shared_preferences_legacy.dart 中依然可见getKeys()、containsKey()、reload()、setMockInitialValues()都是SharedPreferences类的核心成员。其中getStringList在2.3.1还修复过一个ListObject?强转异常2.2.1修复过单例初始化竞态条件——这类细节正是“持久化插件”最容易踩坑的地方。2.2 架构转型从单体插件到联邦化Federated插件2.0.x 时代2.0.x系列是本插件最重要的架构分水岭2.0.9Android 与 iOS 实现被拆分到独立的联邦化包federated packages。2.0.16iOS/macOS 切换到新的shared_preferences_foundation实现包。2.0.10移除 Windows/Linux 实现的旧式手动注册。联邦化之后主包shared_preferences只剩 API 层平台实现由独立包提供。这一点可以从当前 pubspec.yaml 的flutter.plugin.platforms配置一览无余flutter: plugin: platforms: android: default_package: shared_preferences_android ios: default_package: shared_preferences_foundation linux: default_package: shared_preferences_linux macos: default_package: shared_preferences_foundation web: default_package: shared_preferences_web windows: default_package: shared_preferences_windows六个平台Android、iOS、Linux、macOS、Web、Windows各自对应独立的 endorsed官方背书实现包Dart 侧通过shared_preferences_platform_interface抽象层解耦。主包 lib/shared_preferences.dart 仅做三件事导出SharedPreferencesOptions类型、导出 async 新 API、导出 legacy 旧 API。2.3 破坏性变更Null Safety 迁移2.0.02.0.0完成空安全null-safety迁移并带有一个重要的破坏性变更Setters no longer accept null to mean removing values. If you were previously usingset*(key, null)for removing, useremove(key)instead.也就是说2.0.0 之后不能再通过setString(key, null)来删除值必须显式调用remove(key)。这一点在今天的源码中仍然强制_setValue方法第一行就是ArgumentError.checkNotNull(value, value)见 shared_preferences_legacy.dart。同期的其他稳定性修复包括2.0.2修复方法通道调用时重复创建线程池的问题、2.0.3修复 Android 上重复创建 Handler 的问题、2.0.4修复 Android 同时写入的回归问题——这些都属于典型的“高频调用 平台通道”性能与并发陷阱。2.4 新 API 时代SharedPreferencesAsync 与 SharedPreferencesWithCache2.3.02.3.0是本插件在功能层面最重要的一次发布新增了两套全新 APISharedPreferencesAsync无本地缓存所有读写都是异步的平台调用始终返回平台上的最新数据。SharedPreferencesWithCache带内存缓存初始化时一次性加载数据之后 getter 全部同步执行适合对读性能敏感的场景。从源码可以清晰看到两者设计意图的差异。SharedPreferencesAsync见 shared_preferences_async.dart所有方法返回Future直接委托给SharedPreferencesAsyncPlatform而SharedPreferencesWithCache内部持有一个MapString, Object? _cache创建时通过reloadCache()从平台拉取数据getter 直接读缓存同步setter 则“先写缓存、再异步落盘”。缓存方案的核心风险在 README 中被明确列出README.md多 isolate 使用每个 isolate 有各自的单例与缓存多引擎实例包括firebase_messaging等插件创建的后台 context通过原生代码直接修改底层存储。这些场景下缓存可能与实际存储不一致。解决方案是读之前调用reloadCache()/reload()如果绝大多数读取都需要 reload则直接改用SharedPreferencesAsync。2.4.1 allowList把过滤权交给开发者新 API 引入了allowList白名单机制。SharedPreferencesAsync的getKeys、getAll、clear都接受可选allowList参数SharedPreferencesWithCacheOptions则在创建时通过allowList限定可缓存、可读写的 key 集合。源码注释给出了明确语义见 shared_preferences_async.dartnullallowList不过滤缓存所有条目空 allowList禁止一切缓存、读取与写入强烈建议设置 allowList以避免读取和缓存到非预期数据。clear()方法特别危险SharedPreferencesAsync.clear()在不带allowList时会清掉平台上所有偏好项包括原生代码或其他包写入的数据因此官方源码注释明确建议调用时务必提供allowList。SharedPreferencesWithCache还实现了“超出白名单即抛异常”的守卫逻辑containsKey、get、各类 getter/setter 都会先调用_isValidKey检查key 不在allowList中则抛出ArgumentError见 shared_preferences_async.dart。2.5 前缀机制setPrefix 与 allowList 的组合2.1.0 – 2.4.02.1.0新增setPrefix2.2.0为其增加allowList选项2.4.0又补充了“更新前缀后 allowList 处理”的说明注释2.3.3澄清了 README 中前缀处理的范围。默认情况下SharedPreferences只读写以flutter.开头的 key这个前缀由插件内部自动处理开发者无需手动拼前缀见 shared_preferences_legacy.dart。setPrefix的使用要点源码注释 README 双重确认必须在getInstance()之前调用调用getInstance()之后再调setPrefix会抛StateError前缀设为可访问所有非 Flutter 写入的偏好常用于从原生 App 迁移到 Flutter 的场景前缀设为后可能读到类型不兼容的值导致初始化失败此时应配合allowList只保留受支持类型的 key若要从旧前缀迁移到新前缀需要手动改写现有偏好数据setPrefix本身不做迁移使用 allowList 时allowList 中的 key 必须包含前缀本身。从实现看_getSharedPreferencesMap()在_prefixHasBeenChanged时会走getAllWithParameters携带PreferencesFilter(prefix, allowList)随后把带前缀的 key 剥离出来返回见 shared_preferences_legacy.dart。如果底层实现不支持setPrefix还会抛出带有明确提示的UnimplementedError。2.6 迁移工具legacy → async 的官方通道2.4.02.4.0新增官方迁移工具帮助开发者从旧SharedPreferences平滑迁移到SharedPreferencesAsync。该工具位于 legacy_to_async_migration_util.dart核心函数为Futurevoid migrateLegacySharedPreferencesToSharedPreferencesAsyncIfNecessary({ required SharedPreferences legacySharedPreferencesInstance, required SharedPreferencesOptions sharedPreferencesAsyncOptions, required String migrationCompletedKey, })迁移逻辑对应 README 中的示例见 README.md检查目标系统中migrationCompletedKey是否存在存在则直接返回幂等可每次启动都调用对 legacy 实例执行reload()取回全部 key按runtimeType分派bool/int/double/String/ListString逐一写入 async 实例处理ListString?、ListObject?、Listdynamic等变体遇到含非 String 元素的列表会捕获TypeError跳过最后写入migrationCompletedKey: true标记迁移完成。使用该工具需要保证migrationCompletedKey不与业务 key 冲突否则可能造成数据丢失。如果应用之前调用过setPrefix必须在迁移前完成前缀设置。2.7 DevTools 扩展可视化调试2.5.02.5.0为 shared_preferences 新增 DevTools 扩展2.5.4又更新了shared_preferences_tool的依赖并修复相关弃用问题。DevTools 扩展的能力见 shared_preferences_tool/README.md列出应用中存储的所有 key搜索特定 key直接编辑或删除值改动即时反映到运行中的应用支持全部五种数据类型String、int、double、bool、ListString。数据层由 shared_preferences_devtools_extension_data.dart 提供通过developer.postEvent以shared_preferences.前缀事件与 DevTools 通信事件类型包括all_keys、value、change_value、remove。值得注意的实现细节requestValueChange中先jsonDecode再按kind分派注释明确指出因为 double 有时会被解析成 int所以必须校验 kind 而不是直接模式匹配——这是序列化边界上非常典型的坑。本地运行该扩展的方式先运行shared_preferences包的 example 工程并拷贝 debug service URL然后执行flutter run -d chrome --dart-defineuse_simulated_environmenttrue三、平台支持与支持矩阵的演变CHANGELOG 清晰记录了各平台“默认支持”的里程碑0.5.5macOS 默认支持0.5.410新增shared_preferences_macos包0.5.6Web 默认支持0.5.47为 Web 支持重构了项目结构0.5.48切换到底层使用shared_preferences_platform_interface0.5.8Linux 默认支持0.5.11Windows 默认支持。版本演进也伴随着系统版本要求的变化2.2.3宣布 iOS 11 不再支持2.1.2将 macOS 最低版本提升到 10.142.2.3要求 iOS 实现包含隐私清单privacy manifest。当前的支持矩阵README.md平台支持版本AndroidSDK 24iOS13.0Linux任意macOS10.15Web任意Windows任意2.5.4特别说明README 反映的是“最新版本 endorsed 平台实现”的支持情况使用旧版本 Flutter 构建的应用仍可继续使用与之兼容的旧版本平台实现。四、Android 存储后端从 SharedPreferences 到 DataStore2.5.x2.3.5增加了 Android SharedPreferences 支持的相关说明2.3.4是一次安全更新强制要求shared_preferences_android升级到 2.3.4。在新 API 体系下Android 存储后端可选DataStore Preferences默认选项也是平台官方推荐的偏好存储方案Android SharedPreferences用于兼容“由不受你控制的代码写入的 SharedPreferences 数据”。如果需要切换到 SharedPreferences 后端使用SharedPreferencesAsyncAndroidOptions指定const SharedPreferencesAsyncAndroidOptions options SharedPreferencesAsyncAndroidOptions( backend: SharedPreferencesAndroidBackendLibrary.SharedPreferences, originalSharedPreferencesOptions: AndroidSharedPreferencesStoreOptions( fileName: the_name_of_a_file, ), );而旧的SharedPreferencesAPI 则固定使用原生 Android SharedPreferences 存储。各平台的存储位置对照README.md平台SharedPreferencesSharedPreferencesAsync/WithCacheAndroidSharedPreferencesDataStore Preferences 或 SharedPreferencesiOSNSUserDefaultsNSUserDefaultsLinuxXDG_DATA_HOME 目录XDG_DATA_HOME 目录macOSNSUserDefaultsNSUserDefaultsWebLocalStorageLocalStorageWindowsroaming AppData 目录roaming AppData 目录五、API 速查与选型建议5.1 三套 API 的代码形态对比旧 APIlegacy同步 getter 缓存final SharedPreferences prefs await SharedPreferences.getInstance(); // 写入 await prefs.setInt(counter, 10); await prefs.setBool(repeat, true); await prefs.setDouble(decimal, 1.5); await prefs.setString(action, Start); await prefs.setStringList(items, String[Earth, Moon, Sun]); // 读取同步走本地缓存不存在返回 null final int? counter prefs.getInt(counter); final bool? repeat prefs.getBool(repeat); // 删除 await prefs.remove(counter);新 API 之一async无缓存全部异步final asyncPrefs SharedPreferencesAsync(); await asyncPrefs.setBool(repeat, true); final bool? repeat await asyncPrefs.getBool(repeat); await asyncPrefs.remove(repeat); // 强烈建议 clear 时带 allowList避免清掉非本实例写入的数据 await asyncPrefs.clear(allowList: String{action, repeat});新 API 之二with cache同步 getterfinal SharedPreferencesWithCache prefsWithCache await SharedPreferencesWithCache.create( cacheOptions: const SharedPreferencesWithCacheOptions( allowList: String{repeat, action}, ), ); await prefsWithCache.setBool(repeat, true); final bool? repeat prefsWithCache.getBool(repeat); // 同步读缓存 await prefsWithCache.remove(repeat); await prefsWithCache.clear();5.2 选型决策要点新项目一律优先SharedPreferencesAsync或SharedPreferencesWithCacheREADME 明确说明旧SharedPreferences是 legacy API未来会被废弃读写频率高、读路径敏感 → 选SharedPreferencesWithCache同步 getter但需接受缓存一致性问题数据可能被原生代码 / 其他 isolate / 其他引擎修改 → 选SharedPreferencesAsync始终读最新数据对任何clear/ 批量读取调用优先提供allowList以规避副作用存量代码迁移使用migrateLegacySharedPreferencesToSharedPreferencesAsyncIfNecessary注意migrationCompletedKey的选择。六、版本演进中的工程实践启示从这份 CHANGELOG 中还能提炼出 Flutter 官方插件工程的几项长期实践破坏性变更集中在大版本0.2.2、0.3.0、0.4.0、0.5.0、2.0.0且每次都有明确说明与迁移指引例如 0.5.0 的 AndroidX 迁移、2.0.0 的 null-safety 与remove()语义调整安全与合规持续跟进2.3.4 安全更新、2.2.3 隐私清单、0.5.0 AndroidX、0.5.21 后台异步提交反映了对平台政策变化的响应测试基础设施同步演进0.2.4 引入setMockInitialValues与首个测试、0.5.12 增加 driver 测试、0.5.13 迁移到testWidgets、2.0.7 增加 iOS 单元测试目标——当前仓库的 test 目录 中shared_preferences_test.dart、shared_preferences_async_test.dart、shared_preferences_devtools_extension_data_test.dart三个测试文件正是这一积累的产物SDK 约束随 Flutter 版本滚动从 0.4.0 的 beta 约束、0.5.6 的 Flutter 1.12、2.0.18 的 Flutter 3.0一路到 NEXT 版本的 Flutter 3.38/Dart 3.10每个里程碑都同步更新environment约束当前为sdk: ^3.10.0、flutter: 3.38.0。七、总结通过 CHANGELOG 这条时间轴可以完整看到shared_preferences从一个简单的读写封装逐步成长为拥有联邦化架构、双新 API、白名单过滤、官方迁移工具与 DevTools 可视化调试的成熟插件。对于开发者而言最重要的实操结论有三点新代码选择SharedPreferencesAsync/SharedPreferencesWithCache并善用allowList存量代码借助迁移工具平滑升级涉及多进程或多引擎写入时优先使用无缓存 API 或显式 reload。相关源码、测试与配置均可在本仓库的 packages/shared_preferences 目录下继续深入阅读。【免费下载链接】packagesA collection of useful packages maintained by the Flutter team项目地址: https://gitcode.com/GitHub_Trending/pac/packages创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价