Flutter数据库加密插件sqlcipher_flutter_libs的使用

发布于 1周前 作者 ionicwang 来自 Flutter

Flutter数据库加密插件sqlcipher_flutter_libs的使用

Flutter 应用依赖此包后,将在 Android、iOS、macOS、Linux 和 Windows 平台上包含原生的 SQLCipher 库。由于 SQLCipher 与常规的 sqlite3 库具有兼容的 ABI,因此可以与未修改的 sqlite3 包一起使用。

使用此包

根据您的平台,可能需要进行一些设置工作和预防措施。特别是,请注意 iOS 和 macOS 上的兼容性问题!此外,在 Android 上也需要一个特殊的代码片段。

除了这些之外,这个包可以很好地与常规的 sqlite3 包一起使用。要打开一个加密的数据库,使用 sqlite3 包并运行一个 pragma 来解密它:

示例代码

import 'package:sqlcipher_flutter_libs/sqlcipher_flutter_libs.dart';
import 'package:sqlite3/open.dart';
import 'package:sqlite3/sqlite3.dart';

void main() {
  // 如果是Android平台,重写默认的sqlite3打开方法为SQLCipher打开方法
  open.overrideFor(OperatingSystem.android, openCipherOnAndroid);
  
  // 打开数据库文件
  final db = sqlite3.open('path/to/your/database/file');

  // 检查是否成功使用了SQLCipher库
  if (db.select('PRAGMA cipher_version;').isEmpty) {
    throw StateError('SQLCipher library is not available, please check your dependencies!');
  }

  // 设置数据库的加密密钥
  db.execute("PRAGMA key = 'your passphrase';");

  // 从现在开始,您可以像使用任何其他 sqlite3 数据库一样使用这个加密数据库。
}

编译注意事项

根据目标平台的不同,可能需要额外的依赖项:

  • Android: 使用预编译库,无需额外设置。
  • macOS 和 iOS: 依赖于 SQLCipher pod重要提示: 如果依赖于其他链接常规 sqlite3 库的包,可能会导致问题。请确保阅读重要建议
  • Linux: SQLCipher 链接了一个静态 OpenSSL 库(例如在 Debian 上使用 apt install libssl-dev)。OpenSSL 链接到生成的 .so 文件中,因此用户不需要安装 OpenSSL。
  • Windows: SQLCipher 链接了一个静态 OpenSSL 库(使用 Chocolatey 的 choco install openssl)。OpenSSL 静态链接到生成的 .dll 文件中,因此用户不需要安装 OpenSSL。

在 Android 上使用此包时,您需要告诉 sqlite3 包如何打开 sqlcipher,因为它将尝试默认打开常规的 sqlite3 二进制文件:

import 'package:sqlcipher_flutter_libs/sqlcipher_flutter_libs.dart';
import 'package:sqlite3/open.dart';

// 在使用任何 sqlite3 API 之前执行此操作
open.overrideFor(
    OperatingSystem.android, openCipherOnAndroid);

当使用 driftsqflite_common_ffi 等包装 sqlite3 包的包时,也需要这样做!对于其他平台,不需要 Dart 代码更改。如果在后台 isolate 中使用 package:sqlite3(即使通过 package:drift 间接使用),也应在该 isolate 中调用 overrideFor

更多关于如何在 Flutter 应用中实际使用此包的详细信息,请参阅 sqlite3

iOS 和 macOS 上的 sqlite3 不兼容问题

对于 iOS 和 macOS 构建,依赖此包将安装 SQLCipher pod。当依赖于另一个链接常规 sqlite3 pod 或库的包时,这可能导致未定义行为,这意味着 SQLCipher 可能在您的应用中不可用。例如,google_mobile_adsfirebase_messaging 包可能会导致此问题。

要解决此问题,可以在 XCode 项目设置中的 “Other Linker Flags” 添加 -framework SQLCipher。有关更多详细信息,请参阅:

为了尽早捕获这些错误,建议在打开数据库后选择 PRAGMA cipher_version,并在返回空字符串时抛出异常,因为在这种情况下您没有使用 SQLCipher。

不同平台上的不同行为

在 Android、iOS 和 macOS 上,此包依赖 Zetetic(SQLCipher 的作者)管理的依赖项来在应用程序中包含 SQLCipher。由于 Windows 和 Linux 没有这样的解决方案,因此使用自定义构建脚本。此构建脚本灵感来自 sqlite3_flutter_libs 中使用的脚本,并禁用了 双引号字符串 功能。官方 SQLCipher 构建不这样做。

为了避免应用程序依赖于 SQL 中的双引号字符串,如果您针对这些平台,请在发布前在 Linux 或 Windows 上测试您的应用程序。

在 Android、iOS、macOS 和 Windows 上,SQLCipher 使用操作系统自带的原生加密库。在 Linux 上,默认情况下会包含静态链接的 OpenSSL。如果您更喜欢静态链接 OpenSSL,请在 linux/CMakeLists.txt 中添加:

set(OPENSSL_USE_STATIC_LIBS OFF)

Android 6 上的问题

在 Android 6 上加载原生库时似乎存在一个问题(参见 此问题)。如果您遇到这些崩溃,可以尝试在 gradle.properties 文件中设置 android.bundle.enableUncompressedNativeLibs=false。请注意,这会增加应用程序安装后的大小。

或者,您可以使用此库中的 applyWorkaroundToOpenSqlCipherOnOldAndroidVersions 方法。它将尝试在 Java 中打开 sqlcipher,这似乎更可靠。在 Java 加载了原生库之后,我们也可以在 Dart 中打开它。该方法应在使用 sqlite3(直接或通过 package:driftNativeDatabase 间接使用)之前调用。

由于 applyWorkaroundToOpenSqlCipherOnOldAndroidVersions 使用平台通道,因此在后台 isolate 中使用时可能会出现问题。我们建议在主 isolate 中等待它, 启动可能使用数据库的后台 isolate 之前。

import 'package:sqlcipher_flutter_libs/sqlcipher_flutter_libs.dart';

void main() async {
  await applyWorkaroundToOpenSqlCipherOnOldAndroidVersions();
  // 其他初始化代码...
}

希望以上内容对您有所帮助!如果您有任何问题或需要进一步的帮助,请随时提问。


更多关于Flutter数据库加密插件sqlcipher_flutter_libs的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter数据库加密插件sqlcipher_flutter_libs的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何使用 sqlcipher_flutter_libs 插件在 Flutter 中对 SQLite 数据库进行加密和解密的代码示例。这个插件基于 SQLCipher,一个流行的开源 SQLite 扩展,用于加密数据库。

1. 添加依赖

首先,你需要在 pubspec.yaml 文件中添加 sqlcipher_flutter_libs 依赖:

dependencies:
  flutter:
    sdk: flutter
  sqlcipher_flutter_libs: ^x.y.z  # 请使用最新版本号替换 x.y.z

2. 导入插件并初始化

在你的 Dart 文件中导入 sqlcipher_flutter_libs 插件,并初始化数据库。以下是一个基本的示例:

import 'package:flutter/material.dart';
import 'package:sqlcipher_flutter_libs/sqlcipher_flutter_libs.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('SQLCipher Flutter Demo'),
        ),
        body: Center(
          child: DatabaseDemo(),
        ),
      ),
    );
  }
}

class DatabaseDemo extends StatefulWidget {
  @override
  _DatabaseDemoState createState() => _DatabaseDemoState();
}

class _DatabaseDemoState extends State<DatabaseDemo> {
  late Database _db;

  @override
  void initState() {
    super.initState();
    initDatabase();
  }

  Future<void> initDatabase() async {
    // 打开或创建一个加密数据库
    String dbPath = await getDatabasesPath();
    String encryptedDbPath = '$dbPath/encrypted.db';

    // 设置密钥
    String key = 'mysecretkey';

    // 打开数据库
    _db = await openDatabase(
      encryptedDbPath,
      key: key,
      version: 1,
      onCreate: (Database db, int version) async {
        await db.execute('CREATE TABLE test (id INTEGER PRIMARY KEY, name TEXT)');
      },
      onConfigure: (Database db) async {
        await db.execute('PRAGMA cipher_version');
      },
    );
  }

  Future<void> insertData() async {
    await _db.insert('test', {'name': 'Alice'});
    await _db.insert('test', {'name': 'Bob'});
  }

  Future<List<Map<String, dynamic>>> queryData() async {
    return await _db.query('test');
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        ElevatedButton(
          onPressed: () async {
            await insertData();
            setState(() {});
          },
          child: Text('Insert Data'),
        ),
        ElevatedButton(
          onPressed: () async {
            List<Map<String, dynamic>> result = await queryData();
            print(result); // 打印查询结果
          },
          child: Text('Query Data'),
        ),
      ],
    );
  }
}

3. 注意事项

  1. 密钥管理:密钥的存储和管理非常重要,请确保不要硬编码在代码中,使用安全的密钥管理服务。
  2. 性能:加密和解密操作会引入额外的性能开销,请根据实际需求评估性能影响。
  3. 平台支持:确保插件在你使用的平台上已经过充分测试,并遵循其文档和最佳实践。

这个示例展示了如何使用 sqlcipher_flutter_libs 插件创建一个加密的 SQLite 数据库,并进行基本的数据插入和查询操作。根据你的实际需求,你可以进一步扩展和优化代码。

回到顶部