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

升级SQLCipher至v4.5.6后,应用被杀重启报错‘file is not a database’

问题分析与解决方案

核心原因

你遇到的问题本质是SQLCipher 4.x与3.x的兼容配置未持续生效:虽然首次启动执行了cipher_migrate完成迁移,但后续启动时未设置必要的兼容参数,导致杀进程后重新打开数据库时,SQLCipher 4.x用默认的兼容级别(4)读取迁移后的数据库,无法识别格式,抛出“file is not a database”错误。

修复方案

不要区分首次/后续启动的构造函数,每次打开数据库都必须设置兼容参数——重复执行cipher_migrate不会有问题,SQLCipher会自动判断是否需要迁移。

  1. 定义公共的数据库Hook,统一处理兼容配置:
private static final SQLiteDatabaseHook COMMON_DB_HOOK = new SQLiteDatabaseHook() {
    @Override
    public void preKey(SQLiteConnection connection) {}

    @Override
    public void postKey(SQLiteConnection connection) {
        // 强制以3.x兼容模式读取数据库,确保4.x驱动能识别
        connection.executeRaw("PRAGMA cipher_compatibility=3;", null, null);
        // 自动判断并执行迁移(仅首次需要,重复执行无副作用)
        connection.executeRaw("PRAGMA cipher_migrate;", null, null);
        // 保留原有的KDF迭代配置(如果业务需要)
        connection.executeRaw("PRAGMA kdf_iter=1000;", null, null);
        connection.executeRaw("PRAGMA cipher_default_kdf_iter=1000;", null, null);
    }
};
  1. 修改所有构造函数,统一使用这个公共Hook:
private DbHelper(Context context) {
    super(context,
            databaseName,
            password,
            null,
            databaseVersion,
            1,
            null,
            COMMON_DB_HOOK,
            false);
}

private DbHelper(Context context, String secondLaunchCase) {
    super(context,
            databaseName,
            password,
            null,
            databaseVersion,
            1,
            null,
            COMMON_DB_HOOK,
            false);
}

额外排查点

  • 验证数据库完整性:用SQLCipher命令行工具打开数据库文件,确认文件未损坏(命令:sqlcipher your_database.db,输入密码后执行.tables看是否正常)。
  • 确认密码一致性:排查杀进程后密码解密逻辑是否异常,确保每次传入的密码完全相同。
  • 检查数据库版本号:确认databaseVersion设置正确,避免触发不必要的迁移导致数据库损坏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 18:17:27