如何在Android应用中加载自定义编译的SQLite .so插件?
Android加载SQLite插件libsimple.so失败的解决方案
问题背景
开发Android应用时,使用sqlite-android加载自行编译的libsimple.so插件,将so文件放置在jniLibs对应ABI目录下,APK打包后确实包含该文件,但通过applicationInfo.nativeLibraryDir获取路径后,调用File.canRead()返回false,插件加载失败;但将so文件复制到应用cache目录后可正常加载。
解决方案
1. 跳过File.canRead()判断,直接尝试加载
Android 11(API 30)及以上版本中,应用nativeLibraryDir目录下的so文件受系统权限限制,File API无法直接读取,但系统动态链接器(dlopen)可正常加载这些库。无需用canRead()做前置判断,直接执行加载逻辑即可。
修改后的加载代码:
import io.requery.android.database.sqlite.SQLiteDatabase import io.requery.android.database.sqlite.SQLiteDatabaseConfiguration import io.requery.android.database.sqlite.SQLiteCustomExtension private val libsimplePath = "${context.applicationInfo.nativeLibraryDir}/libsimple.so" private val cfg = SQLiteDatabaseConfiguration(":memory:", SQLiteDatabase.OPEN_READWRITE) val ext = SQLiteCustomExtension(libsimplePath, null) cfg.customExtensions.add(ext) try { val db = SQLiteDatabase.openDatabase(cfg, null, null) // 加载成功,执行后续业务逻辑 } catch (e: Exception) { // 捕获异常并排查具体原因 e.printStackTrace() }
2. 将jniLibs中的so复制到Cache目录后加载
若直接加载nativeLibraryDir下的so仍有问题,可将APK中打包的so复制到应用cache目录,再加载该路径的so(已验证此方法可行)。
实现代码示例:
private fun getLibsimplePath(context: Context): String { val cacheDir = context.cacheDir val targetFile = File(cacheDir, "libsimple.so") if (!targetFile.exists()) { // 从APK的native库目录复制文件到cache val sourcePath = "${context.applicationInfo.nativeLibraryDir}/libsimple.so" val sourceFile = File(sourcePath) sourceFile.copyTo(targetFile, overwrite = true) } return targetFile.absolutePath } // 使用处理后的路径加载插件 private val libsimplePath = getLibsimplePath(context) private val cfg = SQLiteDatabaseConfiguration(":memory:", SQLiteDatabase.OPEN_READWRITE) val ext = SQLiteCustomExtension(libsimplePath, null) cfg.customExtensions.add(ext) val db = SQLiteDatabase.openDatabase(cfg, null, null)
3. 验证so文件的ABI兼容性
确保编译的libsimple.so的ABI与sqlite-android支持的ABI完全匹配:
- 确认sqlite-android支持的ABI列表(通常包含armeabi-v7a、arm64-v8a、x86、x86_64)
- 检查libsimple.so是针对对应ABI编译的,避免跨ABI加载导致失败
4. 更新sqlite-android到最新版本
使用最新版本的sqlite-android库,新版本通常会修复高API版本下的兼容性问题。
原因说明
Android 11及以上版本强化了应用私有目录权限,nativeLibraryDir下的so文件属于系统管理的应用库文件,普通File API无法直接读取,但系统动态链接器有权限加载这些库;而cache目录属于应用可完全控制的私有目录,File API和动态链接器都能正常访问。
内容的提问来源于stack exchange,提问作者HAL9000COM
相关产品推荐
相关产品推荐

