如何在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
相关产品推荐
相关产品推荐

