从版本演进看 shared_preferences_web:Flutter Web 端本地存储插件实现与升级指南
【免费下载链接】pluginsPlugins for Flutter maintained by the Flutter team项目地址: https://gitcode.com/gh_mirrors/pl/plugins
shared_preferences_web 是 Flutter 官方维护的联邦插件体系中 Web 平台的实现,负责把shared_preferences的 API 映射到浏览器localStorage上。本文以本仓库中该包的 CHANGELOG.md 为脉络,梳理其版本演进历程,并结合 lib/shared_preferences_web.dart 的源码实现与集成测试,讲解 Web 端本地存储的底层原理、联邦插件注册机制,以及开发者升级到 2.x 时需要关注的破坏性变化。读完本文,你将掌握该插件的运行机制、测试方法与版本兼容要点。
一、版本演进全景:从 0.1.0 到 2.0.4
CHANGELOG 完整记录了该包从诞生到成熟的全部变更,可以清晰看出三条主线:平台适配、工程质量与空安全迁移。
1. 早期阶段(0.1.0 ~ 0.1.2+8):补齐平台占位与依赖约束
0.1.0:初始发布,随后在0.1.0+1中移除 pubspec 中废弃的author:字段,并要求 Flutter SDK ≥ 1.10.0。0.1.1:新增了配套的shared_preferences_macos包,联邦插件体系开始成型。0.1.2:提升 Flutter 版本下限,并添加 stub podspec 文件,为后续 Apple 平台接入做准备。0.1.2+1:临时添加了一个空实现的android/目录,用于规避 Flutter issue #46898(Android 构建在缺少该目录时解析失败的问题)。这是联邦插件早期"占位目录"的典型做法。0.1.2+2 ~ 0.1.2+8:清理未使用的onMethodCall方法、升级 gradle 版本规避 Android 工程问题、显式声明 pedantic dev_dependency、将 Dart 下限提升到 2.1.0,最终在0.1.2+7中移除 Android 占位目录,宣告该包正式回归纯 Web 实现。
从源码看,Web 实现根本不需要任何原生目录——lib/shared_preferences_web.dart 只依赖dart:html与flutter_web_plugins,因此占位目录的移除与"声明 API 稳定性"(0.1.2+5)共同标志着该包走向成熟。
2. 2.0.0:空安全迁移的破坏性升级
2.0.0是唯一一个带破坏性语义的版本——迁移到 null-safety。这要求:
- 使用方 Dart SDK 必须 ≥ 2.12.0;
- 插件内部所有可空类型显式标注,例如源码中
setValue(String valueType, String key, Object? value)的Object?参数、registerWith(Registrar? registrar)的可空注册器。
3. 2.0.1 ~ 2.0.4:测试体系与代码质量收尾
2.0.1:更新 README 安装说明;把测试迁移到 example 目录,改用flutter drive作为集成测试运行方式。这解释了为什么包的 test/tests_exist_elsewhere_test.dart 里只有一个打印提示的占位测试——真正的测试已全部迁往 example。2.0.2:在 pubspec 中为联邦插件添加implements声明(详见下文第三节)。2.0.3:修复新启用的 analyzer 选项告警,并移除对meta的依赖。2.0.4:修复library_private_types_in_public_api、sort_child_properties_last、use_key_in_widget_constructors等 lint 警告。NEXT(未发布):将最低 Flutter 版本提升至3.0。
二、核心实现原理:localStorage 上的 JSON 编解码层
虽然 CHANGELOG 以变更条目为主,但对应版本的行为可以从 lib/shared_preferences_web.dart 中完整还原。整个实现只有约 80 行,围绕浏览器html.window.localStorage封装了四个核心操作:
| 方法 | 对应 shared_preferences API | 底层行为 |
|---|---|---|
getAll() | getKeys/get*系列 | 遍历所有flutter.前缀键并逐个json.decode |
setValue() | setString/setBool/setInt/setDouble/setStringList | json.encode后写入localStorage[key] |
remove() | remove | 直接localStorage.remove(key) |
clear() | clear | 只移除flutter.前缀的键 |
实现中有三个值得注意的设计点:
- 键前缀校验:
_checkPrefix要求所有键必须以flutter.开头,否则抛出FormatException(源码 L53-L61)。这是为了避免污染同一域名下其他应用的数据。 - clear 的精确删除:源码注释明确强调不要使用
localStorage.clear(),因为它会清掉该域名下所有站点的数据,而不仅是flutter.前缀键(源码 L22-L28)。 - 泛型恢复:JSON 往返会丢失泛型信息(
List<String>解码后变成List<dynamic>),因此_decodeValue对 List 显式执行cast<String>()恢复 RTTI(源码 L75-L80)。
这正是2.0.0空安全迁移得以成立的基础——Object?值通过json.encode序列化,读取时再json.decode还原,整个编解码链路在 null-safety 下依然完整。
三、联邦插件结构:implements 声明与自动注册
2.0.2添加的implements是理解该包运行方式的关键。查看 pubspec.yaml:
flutter: plugin: implements: shared_preferences platforms: web: pluginClass: SharedPreferencesPlugin fileName: shared_preferences_web.dart这表示shared_preferences_web是shared_preferences联邦插件在 Web 端的认可(endorsed)实现。开发者只需在工程中依赖shared_preferences,Flutter 工具链在构建 Web 目标时会自动拉入本包,无需手动注册任何平台代码。
插件入口是 SharedPreferencesPlugin.registerWith,其内部只有一行核心逻辑:
SharedPreferencesStorePlatform.instance = SharedPreferencesPlugin();即把SharedPreferencesStorePlatform(来自shared_preferences_platform_interface)的默认实例替换为 Web 实现。集成测试 shared_preferences_web_test.dart 专门验证了这一注册行为:先用MethodChannelSharedPreferencesStore占位,调用registerWith后断言实例已变为SharedPreferencesPlugin。
四、测试体系:为什么测试都在 example 目录
CHANGELOG 2.0.1 提到的"Move tests toexampledirectory"需要结合测试文件理解。包级目录下 test/tests_exist_elsewhere_test.dart 只负责在flutter test时打印指引,说明真实测试位置;而真正的行为测试位于 example/integration_test/shared_preferences_web_test.dart,因为 Web 插件的dart:html与localStorage只能在真实浏览器环境中运行。
测试覆盖了本节前述的全部关键行为:
- getAll:只返回
flutter.前缀键,unprefixed_key被过滤; - setValue:断言写入值与
json.encode结果一致,并验证StringList恢复为List<String>; - remove / clear:验证非前缀键抛
FormatException、clear保留非 Flutter 键; - registerWith:验证插件注册逻辑。
运行方式见 run_test.sh(依赖 chromedriver):
flutter drive -d web-server --web-port=7357 --browser-name=chrome \ --driver=test_driver/integration_test.dart \ --target=integration_test/shared_preferences_web_test.dart五、升级到 2.x 的实操清单
综合 CHANGELOG 各版本约束,开发者迁移到shared_preferences_web2.x 需要满足:
- SDK 版本:Dart ≥ 2.12.0(2.0.0 空安全)、Flutter ≥ 3.0(NEXT 版本要求),pubspec 中已显式声明
sdk: ">=2.12.0 <3.0.0"、flutter: ">=3.0.0"; - 依赖方式:工程中只需依赖
shared_preferences,无需直接声明本包(endorsed 机制自动引入); - 键名规范:自定义键需以
flutter.开头,否则运行时会抛FormatException; - 数据兼容性:Web 端数据以 JSON 字符串存储于
localStorage,跨版本读取依赖编解码一致性,升级后旧键值仍可正常读取。
结语
从 0.1.0 的初始发布到 2.0.4 的 lint 收尾,CHANGELOG.md 完整折射出一个官方联邦插件走向稳定的全过程:平台占位的增删、空安全迁移、测试体系重构、工程质量收敛。而其 80 行的核心实现与详尽的集成测试,则为 Web 端本地存储提供了"麻雀虽小、五脏俱全"的最佳范本。读者如需深入,可继续查看 README.md 与同目录下的 pubspec.yaml。
【免费下载链接】pluginsPlugins for Flutter maintained by the Flutter team项目地址: https://gitcode.com/gh_mirrors/pl/plugins
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考