首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Flutter 全平台 | 从 shared_preferences 聊聊六端插件

Flutter 全平台 | 从 shared_preferences 聊聊六端插件

作者头像
张风捷特烈
发布于 2024-06-06 01:04:53
发布于 2024-06-06 01:04:53
91601
代码可运行
举报
运行总次数:1
代码可运行

用过 Flutter 的小伙伴应该对 shared_preferences 并不陌生,它支持 六大平台,用于存储键值对,并以 xml 文件的形式将数据进行持久化。这种功能的实现会依赖各个平台的能力,而且功能点并不复杂。所以它是一个非常好的六端插件 研究对象。


1. 项目结构

进入 shared_preferences 插件源码中,可以看到它并非是一个简单的插件项目。而是:

  • 统一接口 shared_preferences_platform_interface;
  • 每个平台给出自己的实现包,比如安卓端通过 shared_preferences_android 实现;
  • 通过 shared_preferences 库整合各个平台包的功能。

这样对于开发者,既可以独立维护和发展每个平台的类库。对于使用者,又可以基于 shared_preferences 一个库来访问所有子系统的功能。是一种非常好的项目结构。


2. 依赖关系

通过各个类库的 pubspec.yaml,可以查看他们之间的依赖关系。如下所示,shared_preferences 库依赖了其他的五个分库:

在分库中,会依赖 shared_preferences_platform_interface 接口,对接口中定义的抽象功能进行具体实现。

通过下面的简图,可以更好的理解这六个类库之间的关系:


3. 接口包 shared_preferences_platform_interface

shared_preferences_platform_interface 包中定义了 SharedPreferencesStorePlatform 接口,其中声明了一些抽象方法:

并且通过静态变量 instance 得到 SharedPreferencesStorePlatform 实例对象,注意这里并非单例模式,首先它没有私有化构造;其次它可以通过 set 方法设置其他实例。可以看出,默认的实例是 MethodChannelSharedPreferencesStore 对象。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
abstract class SharedPreferencesStorePlatform extends PlatformInterface {
  SharedPreferencesStorePlatform() : super(token: _token);

  static final Object _token = Object();

  static SharedPreferencesStorePlatform get instance => _instance;

  static set instance(SharedPreferencesStorePlatform instance) {
    if (!instance.isMock) {
      PlatformInterface.verify(instance, _token);
    }
    _instance = instance;
  }

  static SharedPreferencesStorePlatform _instance =
      MethodChannelSharedPreferencesStore();

其中 MethodChannelSharedPreferencesStore 必然是 SharedPreferencesStorePlatform 的实现类。可以看出定义了 MethodChannel 全局常量作为平台共同的渠道方法,在具体实现中通过 MethodChannel#invokeMethod 来触发平台方法:


3. windows 和 linux 平台的功能实现

windows 和 linux 平台本身并没有 xml 配置文件的写入和读取工具。所以对于这两个平台,会通过 shared_preferences.json 来存储数据,实现 SharedPreferencesStorePlatform 中定义的存取等接口功能:

windows

linux

下面是 windows 和 linux 对于 SharedPreferencesStorePlatform 的实现。可以看出在 registerWith 方法中,会将 SharedPreferencesStorePlatform 接口中的静态实例设为当前类对象:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
---->[windows]----
class SharedPreferencesWindows extends SharedPreferencesStorePlatform {
  static void registerWith() {
    SharedPreferencesStorePlatform.instance = SharedPreferencesWindows();
  }
  static const String _defaultPrefix = 'flutter.';
}

---->[linux]----
class SharedPreferencesLinux extends SharedPreferencesStorePlatform {
  static const String _defaultPrefix = 'flutter.';
  static void registerWith() {
    SharedPreferencesStorePlatform.instance = SharedPreferencesLinux();
  }

下面代码可以看出 windows 和 linux 会将配置文件放在 getApplicationSupportPath 之下,名称为 shared_preferences.json :

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
---->[windows]----
Future<File?> _getLocalDataFile() async {
  if (_localDataFilePath != null) {
    return _localDataFilePath!;
  }
  final String? directory = await pathProvider.getApplicationSupportPath();
  if (directory == null) {
    return null;
  }
  return _localDataFilePath =
      fs.file(path.join(directory, 'shared_preferences.json'));
}

---->[linux]----
Future<File?> _getLocalDataFile() async {
  final String? directory = await pathProvider.getApplicationSupportPath();
  if (directory == null) {
    return null;
  }
  return fs.file(path.join(directory, 'shared_preferences.json'));
}

拿设置值来说,会先通过 _readPreferences 得到 map 对象,然后添加键值对。通过 _writePreferences 将新的 map 对象写入到文件中:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@override
Future<bool> setValue(String valueType, String key, Object value) async {
  final Map<String, Object> preferences = await _readPreferences();
  preferences[key] = value;
  return _writePreferences(preferences);
}

Future<bool> _writePreferences(Map<String, Object> preferences) async {
  try {
    final File? localDataFile = await _getLocalDataFile();
    if (localDataFile == null) {
      debugPrint('Unable to determine where to write preferences.');
      return false;
    }
    if (!localDataFile.existsSync()) {
      localDataFile.createSync(recursive: true);
    }
    final String stringMap = json.encode(preferences);
    localDataFile.writeAsStringSync(stringMap);
  } catch (e) {
    debugPrint('Error saving preferences to disk: $e');
    return false;
  }
  return true;
}

最后看一下 windows 中 pubspec.yaml 的声明。它在 futter 节点下增加了 plugin 节点,来描述当前插件包。另外 shared_preferences_windows 是一个独立的包,他可以依赖其他的类库。比如这里的 path_provider_windows, 用于获取路径。 Linux 也是类似的:


4. shared_preferences 库

shared_preferences 是面向开发者的类库,其中提供了我们日常开发中所用到的所有方法。他通过 SharedPreferences._ 私有化构造,通过 getInstance 获取 SharedPreferences 实例。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class SharedPreferences {
  SharedPreferences._(this._preferenceCache);
  
  static Future<SharedPreferences> getInstance() async {
  if (_completer == null) {
    final Completer<SharedPreferences> completer =
        Completer<SharedPreferences>();
    _completer = completer;
    try {
      final Map<String, Object> preferencesMap =
          await _getSharedPreferencesMap();
      completer.complete(SharedPreferences._(preferencesMap));
    } catch (e) {
      completer.completeError(e);
      final Future<SharedPreferences> sharedPrefsFuture = completer.future;
      _completer = null;
      return sharedPrefsFuture;
    }
  }
  return _completer!.future;
}

该实例的核心是 _preferenceCache 映射数据,在构造时会作为入参。比如 getString 方法会从 _preferenceCache 中检索对应的值; setString 会更新 _preferenceCache 映射关系,并通过 _store 存储值。而这个 _store 正是各个平台提供的数据访问接口 SharedPreferencesStorePlatform

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
final Map<String, Object> _preferenceCache;

String? getString(String key) => _preferenceCache[key] as String?;

Future<bool> setString(String key, String value) =>
    _setValue('String', key, value);
    
Future<bool> _setValue(String valueType, String key, Object value) {
  ArgumentError.checkNotNull(value, 'value');
  final String prefixedKey = '$_prefix$key';
  if (value is List<String>) {
    _preferenceCache[key] = value.toList();
  } else {
    _preferenceCache[key] = value;
  }
  return _store.setValue(valueType, prefixedKey, value);
}

最后看一下 shared_preferences 中的 pubspec.yaml 文件。在 flutter 节点下对各个平台的类库实现进行描述。可以看出 iOSMacos 都是通过 shared_preferences_foundation 首先的:


5. Android、iOS、MacOS 平台

Android、iOS、MacOS 平台有相关的 xml 配置数据的存取功能。比如 Android 中使用 SharedPreferences 对象,这也是该库名称的由来:

iOS、MacOS 平台的提供的功能是一样的,代码在 shared_preferences_foundation 中。可以看到是通过 UserDefaults 进行数据持久化的。

最后说一下,这三个平台涉及到渠道方法来沟通原生平台,这里使用了 pigeons 工具自动生成相关代码,这一点以后有机会再开一篇细讲一下:


6. Web 平台

最后看一下 Web 平台的实现,其中依赖了 web 类库:

作为存储的实现层,web 平台肯定也需要实现 SharedPreferencesStorePlatform 的接口功能。

从设置和存储值可以看出 web 平台是基于 localStorage 实现的:


到这里,shared_preferences 六端的插件的结构就已经分析完毕了。以后自己需要编写多平台插件也可以按照这种结构。每个类库职责分离,通过一个类库集成各个分库的功能。那本文就到这里,谢谢观看 ~

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-06-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【Flutter】shared_preferences 本地存储 ( 简介 | 安装 shared_preferences 插件 | 使用 shared_preferences 流程 )
shared_preferences 是 Flutter 提供的 本地数据存取 插件 ;
韩曙亮
2023/03/29
2.4K0
【Flutter】shared_preferences 本地存储 ( 简介 | 安装 shared_preferences 插件 | 使用 shared_preferences 流程 )
Flutter中使用shared_preferences本地存储
https://pub.flutter-io.cn/packages/shared_preferences
越陌度阡
2021/01/29
1.7K0
Flutter 构建完整应用手册-持久化
如果我们有一小部分我们想要保存的键值,我们可以使用shared_preferences插件。
南郭先生
2018/08/14
1.7K0
Flutter的两种本地存储方式之 SharedPreferences(1)
缓存少量的键值对信息(比如记录用户是否阅读了公告,或是简单的计数),可以使用 SharedPreferences。
徐建国
2021/08/06
1.4K0
Flutter中的本地存储
在上一篇文章中我们学习了在Dart中的异步操作,你以为我没事啊还特地给你们专门写一篇文章啊,当然是有用的啊。
flyou
2019/08/06
5.5K0
Flutter中的本地存储
Flutter 本地存储实用教程
在这篇文章中,我将向大家分享Flutter 本地存储的一些实用知识和技巧。首先会带你一起认识什么是shared_preferences、如何使用shared_preferences、以及shared_preferences有那些常用的API?,最后会通过一个计数器的例子来巩固Flutter 中本地存储的知识点等。
CrazyCodeBoy
2019/12/10
1.2K0
Flutter 本地存储实用教程
【Flutter】简单数据持久化
保存数据到本地磁盘是应用程序常用功能之一,比如保存用户登录信息、用户配置信息等。而保存这些信息通常使用 「shared_preferences」,它保存数据的形式为 Key-Value(键值对),支持 Android 和 iOS。shared_preferences 是一个第三方插件,在 Android 中使用 SharedPreferences,在 iOS中使用 NSUserDefaults。
老孟Flutter
2021/09/27
1K0
Flutter开发-常用的第三方库
地址:https://pub.dev/packages/shared_preferences
码客说
2020/05/16
5120
蹭个热门:Flutter Plugin数据传递通信实例梳理
今天突然翻到放置大概4个月的Flutter笔记--Flutter Plugin数据传递通信实例梳理
大话swift
2019/07/04
1K0
Flutter 本地存储之shared_preferences
提供简单数据的持久性存储,同时支持Android和IOS,键值对的方式,异步存储。
yechaoa
2022/06/10
5560
Flutter 应用数据持久化指南
数据持久化是指将应用程序中的数据保存在持久存储介质(如硬盘、数据库等)中的过程。在计算机科学领域,持久化数据是指数据在程序退出或系统关机后仍然存在的能力。这种持久性使得数据可以在不同的应用程序运行周期之间保持不变,以便稍后进行检索、处理和使用。
繁依Fanyi
2024/04/05
8900
Flutter 中的本地存储
在Flutter中,我们使用shared_preferences组件来实现本地数据的存储。
拉维
2019/09/16
2.7K0
Flutter for Web:跨平台移动与Web开发的新篇章
Flutter是Google推出的一款开源的UI工具包,用于构建高性能、高保真度的跨平台应用程序。Flutter最初专注于移动平台,但随着Flutter for Web的推出,它也扩展到了Web开发领域。本文将深入解析Flutter for Web的架构、核心概念、开发流程、性能优化以及与传统Web开发框架的比较。
天涯学馆
2024/06/13
9310
Flutter 简易新闻项目目标效果对比简介代码代码地址
使用flutter快速开发 Android 和 iOS 的简易的新闻客户端 API使用的是 showapi(易源数据) 加载热门微信文章
gwk_iOS
2018/12/05
1.4K0
Flutter 入门指北之数据持久化
博客:https://www.jianshu.com/p/97c2dbcac3af
陈宇明
2020/12/16
1.6K0
[-Flutter插件篇 -] 从自定义插件开始说起
Flutter可以为你提供一个强大华丽简洁高效的跨平台UI界面, 但无论外表多么绚丽美女,没有内在也只是空壳,你会喜欢她吗?(还用问,当然会) 使用插件可以让Flutter轻松与当前平台进行联系,
张风捷特烈
2020/04/30
1.9K0
[-Flutter插件篇 -] 从自定义插件开始说起
从零开始的Flutter之旅: MethodChannel
在flutter_github有这么一个场景:通过authorization认证方式进行登录。而authorization的具体登录形式是,通过跳转一个网页链接进行github授权登录,成功之后会携带对应的code到指定客户端中,然后客户端可以通过这个code来进行oauth授权登录,成功之后客户端可以拿到该账户的token,所以之后的github操作都可以通过该token来进行请求。由于token是有时效性,同时也可以手动解除授权,所以相对于在客户端进行账户密码登录来说更加安全。
Rouse
2020/07/13
1.3K0
Flutter | Image 源码分析与优化方式
Image 是 Flutter 用于显示图像的小组件,它可以加载网络,本地,文件或者内存中的图像,支持 JPEG、PNG、GIF、动画 GIF、WebP、动画 WebP、BMP 和 WBMP 格式。Flutter Image 本身也实现了内存缓存的机制,可以很大的提高图片展示速度等。
345
2022/02/11
2.7K0
Flutter | Image 源码分析与优化方式
有赞Flutter插件开发与发布
随着 Flutter 生态越来越完善,以及 Flutter 在性能上的高光表现,越来越多的模块将会通过 Flutter 来进行实现。为了更方便的与原生工程进行对接以及降低整体工程的耦合,Flutter 的开发模式也需要做成组件化的模式,拥有独立调试以及可拆卸的特性。原生工程在接入 Flutter 模块时,只需要在 gradle(pod) 中添加依赖,即可与 Flutter 模块进行交互。
有赞coder
2020/08/25
2.1K0
有赞Flutter插件开发与发布
Flutter Android 端 FlutterEngine Java 相关流程源码分析
我们在 Flutter Android 端的 Java 层代码中经常看到 FlutterEngine、FlutterEngineGroup、FlutterEngineCache 等相关类的使用,你是不是也经常搞不清他们的关系和作用?本文就是对他们的一个解剖分析,由于 Flutter 2 版本对这块做了大调整,所以我们的分析以 2.2.3 版本为例分析。
工匠若水
2021/08/22
1.5K0
推荐阅读
相关推荐
【Flutter】shared_preferences 本地存储 ( 简介 | 安装 shared_preferences 插件 | 使用 shared_preferences 流程 )
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档