MST

星途 面试题库

面试题:Flutter 下 SharedPreferences 与 SQLite 结合的性能优化及安全考量

在大型 Flutter 应用中,大量使用 SharedPreferences 和 SQLite 结合进行数据存储,从性能优化和数据安全两个方面出发,阐述你会采取哪些策略。例如,如何避免 SQLite 频繁 I/O 操作对性能的影响,以及怎样确保 SharedPreferences 存储数据的安全性,防止数据泄露等。
42.5万 热度难度
前端开发Flutter

知识考点

AI 面试

面试题答案

一键面试

性能优化策略

  1. SQLite 性能优化
    • 批量操作:避免每次数据变更都进行单独的 I/O 操作,而是将多个相关操作合并成一个批量操作。例如,在插入多条数据时,使用事务(transaction)将所有插入语句包裹起来,这样只有在事务提交时才会真正进行 I/O 操作,减少磁盘 I/O 的频率。
    await database.transaction((txn) async {
      for (var item in dataList) {
        await txn.insert('table_name', item.toMap());
      }
    });
    
    • 缓存机制:在内存中创建一个缓存层,对频繁读取的数据进行缓存。当需要读取数据时,先从缓存中查找,如果存在则直接返回,避免直接查询 SQLite 数据库。可以使用 Dart 中的 Map 来实现简单的缓存。例如:
    Map<int, User> userCache = {};
    Future<User> getUser(int id) async {
      if (userCache.containsKey(id)) {
        return userCache[id];
      }
      var result = await database.query('users', where: 'id =?', whereArgs: [id]);
      if (result.isNotEmpty) {
        var user = User.fromMap(result.first);
        userCache[id] = user;
        return user;
      }
      return null;
    }
    
    • 索引优化:为经常用于查询条件的字段创建索引。例如,如果经常根据 name 字段查询用户数据,就在 name 字段上创建索引。
    await database.execute('CREATE INDEX idx_name ON users (name)');
    
  2. SharedPreferences 性能优化
    • 减少写入频率:由于 SharedPreferences 的写入操作会涉及到磁盘 I/O,尽量合并多个数据的写入操作,而不是每次数据变化都调用 set 方法。例如,可以在一个操作完成后,批量更新 SharedPreferences。
    final prefs = await SharedPreferences.getInstance();
    var batch = prefs.edit();
    batch.setString('key1', 'value1');
    batch.setInt('key2', 2);
    await batch.commit();
    

数据安全策略

  1. SQLite 数据安全
    • 加密存储:使用支持加密功能的 SQLite 库,如 sqflite 库配合 sqlite3_flutter_libs 插件可以实现 SQLite 数据库的加密。在打开数据库时设置加密密钥,这样数据库文件中的数据就会以加密形式存储。
    final database = await databaseFactoryFfi.openDatabase(
      'path/to/database.db',
      options: OpenDatabaseOptions(
        password: 'your_secret_password',
      ),
    );
    
    • 权限控制:确保应用对 SQLite 数据库文件的访问权限最小化。在 Android 中,可以通过设置文件权限使得只有应用本身可以访问数据库文件。在 AndroidManifest.xml 中设置 android:exported="false" 来限制外部应用对数据库文件的访问。
  2. SharedPreferences 数据安全
    • 数据加密:对于敏感数据,在存储到 SharedPreferences 之前先进行加密处理。可以使用 Dart 的加密库,如 pointycastle 库。例如,对用户密码进行加密后再存储。
    import 'package:pointycastle/pointycastle.dart';
    import 'package:convert/convert.dart';
    
    Future<String> encryptData(String data, String key) async {
      final keyUtf8 = utf8.encode(key);
      final iv = Uint8List(16);
      final keyParameter = KeyParameter(keyUtf8);
      final ivParameter = ParametersWithIV(keyParameter, iv);
    
      final aes = AESFastEngine();
      final encryptor = PaddedBlockCipherImpl(
        BlockCipherMode.cbc,
        aes,
        Pkcs7Padding(),
      );
      encryptor.init(true, ivParameter);
    
      final dataUtf8 = utf8.encode(data);
      final encrypted = encryptor.process(dataUtf8);
      return base64.encode(encrypted);
    }
    
    // 存储加密数据
    final prefs = await SharedPreferences.getInstance();
    String encryptedPassword = await encryptData('user_password', 'encryption_key');
    prefs.setString('encrypted_password', encryptedPassword);
    
    • 防止反编译获取数据:对应用进行混淆处理,在 Android 中可以使用 ProGuard 或 R8 进行代码混淆,使得反编译后的代码难以理解,增加攻击者获取 SharedPreferences 中数据的难度。在 build.gradle 文件中配置混淆:
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }