You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中如何实现SharedPreferences的XML导出与导入

Flutter 实现SharedPreferences XML导出与导入方案

shared_preferences官方插件没有提供XML导出/导入的内置API,但该功能完全可以实现,不需要依赖Java侧的原生专属方案,可同时兼容Android、iOS双端。

核心实现思路

Android端原生SharedPreferences本身就是以XML格式存储在应用私有目录下,iOS端对应存储为plist格式。如果需要统一导出为标准XML格式(和安卓原生SP格式兼容),直接在Dart层完成KV数据的XML序列化/反序列化即可,不需要编写大量原生代码;如果仅需要Android端直接导出系统生成的原生SP文件,也可以通过原生桥接直接拷贝对应文件。

前置依赖

在pubspec.yaml中添加以下依赖:

dependencies:
  shared_preferences: ^2.2.2
  xml: ^6.5.0
  path_provider: ^2.1.2
  permission_handler: ^11.3.0 # 仅导出到外部公共目录时需要

具体实现步骤

1. 导出SharedPreferences为XML文件

实现逻辑:

  • 获取SharedPreferences实例,遍历取出所有已存储的KV键值对,支持的类型包括bool、int、double、String、List<String>,和插件本身支持的类型完全对齐
  • 构建和Android原生SP完全一致的XML结构,根节点为<map>,每个存储项对应一个带类型标识的子节点
  • 将生成的XML字符串写入目标路径,导出到应用私有目录无需权限,导出到公共存储目录需先申请对应存储权限

核心实现代码:

import 'package:shared_preferences/shared_preferences.dart';
import 'package:xml/xml.dart';
import 'dart:io';
import 'package:path_provider/path_provider.dart';

Future<File> exportSpToXml() async {
  final prefs = await SharedPreferences.getInstance();
  final xmlBuilder = XmlBuilder();
  xmlBuilder.processing('xml', 'version="1.0" encoding="utf-8" standalone="yes" ?>');
  xmlBuilder.element('map', nest: () {
    for (final key in prefs.getKeys()) {
      final value = prefs.get(key);
      switch (value.runtimeType) {
        case bool:
          xmlBuilder.element('boolean', nest: () {
            xmlBuilder.attribute('name', key);
            xmlBuilder.attribute('value', value.toString());
          });
          break;
        case int:
          xmlBuilder.element('int', nest: () {
            xmlBuilder.attribute('name', key);
            xmlBuilder.attribute('value', value.toString());
          });
          break;
        case double:
          xmlBuilder.element('float', nest: () {
            xmlBuilder.attribute('name', key);
            xmlBuilder.attribute('value', value.toString());
          });
          break;
        case String:
          xmlBuilder.element('string', nest: () {
            xmlBuilder.attribute('name', key);
            xmlBuilder.text(value as String);
          });
          break;
        case List<String>:
          xmlBuilder.element('set', nest: () {
            xmlBuilder.attribute('name', key);
            for (final item in value as List<String>) {
              xmlBuilder.element('string', nest: item);
            }
          });
          break;
      }
    }
  });
  final xmlDoc = xmlBuilder.buildDocument();
  // 此处默认导出到应用文档目录,可按需修改为公共存储路径
  final appDir = await getApplicationDocumentsDirectory();
  final backupFile = File('${appDir.path}/sp_backup_${DateTime.now().millisecondsSinceEpoch}.xml');
  await backupFile.writeAsString(xmlDoc.toXmlString(pretty: true));
  return backupFile;
}

2. 从XML文件导入还原SharedPreferences

实现逻辑:

  • 读取目标XML文件内容,解析为XML文档对象
  • 遍历根节点下的所有子节点,根据节点标签识别值类型,读取name属性作为存储key,解析对应节点值
  • 调用SharedPreferences的对应set方法写入所有KV对,完成后执行reload重载使配置生效

核心实现代码:

Future<void> importSpFromXml(File backupXmlFile) async {
  final prefs = await SharedPreferences.getInstance();
  final xmlStr = await backupXmlFile.readAsString();
  final xmlDoc = XmlDocument.parse(xmlStr);
  final rootNode = xmlDoc.rootElement;

  for (final node in rootNode.childElements) {
    final storageKey = node.getAttribute('name');
    if (storageKey == null) continue;
    switch (node.name.local) {
      case 'boolean':
        final val = node.getAttribute('value')?.toLowerCase() == 'true';
        await prefs.setBool(storageKey, val);
        break;
      case 'int':
        final val = int.tryParse(node.getAttribute('value') ?? '0') ?? 0;
        await prefs.setInt(storageKey, val);
        break;
      case 'float':
        final val = double.tryParse(node.getAttribute('value') ?? '0') ?? 0.0;
        await prefs.setDouble(storageKey, val);
        break;
      case 'string':
        final val = node.innerText;
        await prefs.setString(storageKey, val);
        break;
      case 'set':
        final val = node.childElements
            .where((e) => e.name.local == 'string')
            .map((e) => e.innerText)
            .toList();
        await prefs.setStringList(storageKey, val);
        break;
    }
  }
  await prefs.reload();
}

补充说明

  • 上述方案生成的XML格式和Android原生SharedPreferences的XML格式完全兼容,原生侧导出的SP文件无需额外转换即可直接导入,Flutter导出的文件也可直接给原生侧使用
  • 该方案为Dart层纯逻辑实现,不依赖原生平台专属接口,Android、iOS端均可正常运行
  • 如果仅需要Android端直接导出系统自动生成的原生SP文件,可通过MethodChannel调用原生代码,直接拷贝/data/data/[应用包名]/shared_prefs/目录下的对应XML文件即可,无需手动拼接XML结构,但该方式无法兼容iOS端
  • 若需要将文件导出到设备公共存储目录,需根据系统版本申请对应的存储权限,否则会出现文件写入失败问题

内容的提问来源于stack exchange,提问作者William Edward

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 07:12:27