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

如何在Android原生NDK中通过JNI使用SQLCipher操作加密数据库

NDK侧操作SQLCipher 4.4.3加密数据库实现方案

问题原因

  • 报错file is not a database是因为你调用了系统原生未加密的SQLite接口操作SQLCipher加密后的数据库文件,格式不匹配导致识别失败。
  • 找不到头文件是因为没有引入SQLCipher对应的原生开发头文件,SQLCipher的原生API头文件和SQLite一致,但需要单独引入对应版本的包。

具体实现步骤

1. 导入SQLCipher原生依赖

从SQLCipher 4.4.3官方发布包中提取对应架构的libsqlcipher.so库文件,以及sqlite3.h、sqlite3ext.h头文件,引入到你的NDK项目中:

  • 将头文件放到JNI模块的头文件搜索路径下
  • 将对应ABI的libsqlcipher.so放到项目的jniLibs对应目录下

2. 配置NDK编译脚本

以CMake为例,修改CMakeLists.txt配置,确保编译时链接SQLCipher库而非系统原生SQLite库:

cmake_minimum_required(VERSION 3.22.1)

project("your_native_module")

# 配置SQLCipher头文件搜索路径
include_directories(${CMAKE_SOURCE_DIR}/sqlcipher/include)

# 导入SQLCipher动态库
add_library(sqlcipher SHARED IMPORTED)
set_target_properties(sqlcipher PROPERTIES IMPORTED_LOCATION
        ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libsqlcipher.so)

# 你的原生模块编译配置
add_library(${CMAKE_PROJECT_NAME} SHARED
        native_lib.cpp)

# 链接库时优先链接sqlcipher,避免调用到系统sqlite3接口
target_link_libraries(${CMAKE_PROJECT_NAME}
        sqlcipher
        android
        log)

3. 原生侧操作加密数据库代码示例

SQLCipher原生API和普通SQLite API完全兼容,仅需要在打开数据库后先执行密钥设置即可:

// 引入SQLCipher提供的sqlite3.h,注意不要引入系统原生的sqlite3.h
#include <sqlite3.h>
#include <string.h>
#include <stdio.h>

/**
 * 打开并验证加密数据库
 * @param db_path 数据库文件绝对路径
 * @param password 加密密钥,和Java侧传入的密码保持一致
 * @param out_db 输出参数,打开成功的数据库句柄
 * @return 操作错误码,SQLITE_OK表示成功
 */
int open_encrypted_database(const char* db_path, const char* password, sqlite3** out_db) {
    sqlite3* db = NULL;
    int rc = sqlite3_open(db_path, &db);
    if (rc != SQLITE_OK) {
        sqlite3_close(db);
        return rc;
    }

    // 设置解密密钥,必须在所有数据库操作之前执行
    char pragma_key[512];
    snprintf(pragma_key, sizeof(pragma_key), "PRAGMA key = '%s';", password);
    rc = sqlite3_exec(db, pragma_key, NULL, NULL, NULL);
    if (rc != SQLITE_OK) {
        sqlite3_close(db);
        return rc;
    }

    // 验证密钥是否正确,可选但推荐执行
    rc = sqlite3_exec(db, "SELECT 1 FROM sqlite_master LIMIT 1;", NULL, NULL, NULL);
    if (rc != SQLITE_OK) {
        sqlite3_close(db);
        return rc;
    }

    *out_db = db;
    return SQLITE_OK;
}

注意事项

  • 如果Java侧创建数据库时修改过默认加密配置(比如PRAGMA cipher_page_size、PRAGMA kdf_iter等),原生侧设置密钥后必须执行完全相同的PRAGMA配置,否则依然无法打开数据库。
  • 后续数据库的增删改查操作和普通SQLite操作完全一致,直接使用sqlite3_exec、sqlite3_prepare_v2等原生函数即可。
  • 所有操作完成后记得调用sqlite3_close关闭数据库句柄,释放资源。

内容的提问来源于stack exchange,提问作者A.ahmadi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 19:15:04