SQLite在NDK中的重生

Posted Android群英传

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SQLite在NDK中的重生相关的知识,希望对你有一定的参考价值。

    这个问题的起因是,某项目需要在 NDK 中使用 SQLite,并且这个库同时也需要在 ios 端使用。一开始的开发均很顺利,已有文章予以总结,(http://rarnu.com/index.php/2017/03/17/sqlite_cross_platform/)。

    但是当程序运行到 android N 上时,情况就不对了,整个程序直接崩溃,报的错误是 Can not load dynamic library "libsqlite.so"。保险起见,我检查了一下 /system/lib/system/lib64,确保了 libsqlite.so 是存在的。那么问题就变成了,无法调用这个存在的库?

    经过一番搜索,找到了问题的原因,(http://ericsink.com/entries/sqlite_android_n.html),具体的原因是,Android N 以后,不再允许直接调用 /system/lib 内的内容,而允许调用的库,如 liblog.so,均被移至 vendor 下,并符号链接至 /system/lib

    所以,libsqlite.so 既便存在,也无法再直接调用了。再深入讲一句,其实 libdl.so 也无法再使用了,也就是说,在 NDK 中 dlopendlsym 这类函数也已被禁用。


    既然不能动态调用,那解决方案就是静态调用了,我们需要一个 libsqlite.a,并把它静态链接到目标库里。这一步很简单,下载 SQLite 源码后,将它编译成适用于 Android 的 libsqlite.a

    此时可以得到 SQLite 的源码,总共 4 个文件,写一个 Android.mk 来编译之:

SQLite在NDK中的重生

    同时还需要再写一个 Application.mk 来使用 STL:

SQLite在NDK中的重生

    执行一下 ndk-build 命令即可得到一个 libsqlite3.a


    要完成静态链接,可以很简单的使用 linklib 这个宏命令,同时修改 sqlite3.inc 文件,将 external 指令后的库名称全部删去。

    关于 external,详细的用法是:

SQLite在NDK中的重生

    关于 linklib,详细的用法是:

SQLite在NDK中的重生

    此处需要注意的是,我们仅针对 Andorid 平台进行入理,而其他平台上静态链接并没有意义,因此使用 Android 的定义宏将 linklib 包起来即可。这样在编译时,静态库就链接到目标文件里去了。


    到了这一步,可以说是成功了一半,这个时候运行程序,还是会崩的,主要会崩的地方有以下几个:

SQLite在NDK中的重生

    这两个函数的调用,须注释掉,在这里并不需要使用,而且放着会引起找不到函数的运行时异常。

    另一处崩溃在于 Android 老版本的兼容,在 Android M 以后,调用 NDK 时,不再检查 __aeabi_d2ulz__aeabi_d2lz(虽然这两个函数具体做了什么我也不知道,但是反编译看函数体,是可以直接留空的),而老版本的 Android 会在调用 NDK 时进行导出函数检查,从而引发一个崩溃。要解决这个问题,只需要造出这两个函数即可:

SQLite在NDK中的重生

    这样就完成了对老版本 Android 的兼容。到了这一步,在 Android N 以上以 NDK 调用 SQLite 即告完成。

优秀人才不缺工作机会,只缺适合自己的好机会。但是他们往往没有精力从海量机会中找到最适合的那个。

100offer 会对平台上的人才和企业进行严格筛选,让「最好的人才」和「最好的公司」相遇。

扫描下方二维码,注册 100offer,谈谈你对下一份工作的期待。一周内,收到 5-10 个满足你要求的好机会!


以上是关于SQLite在NDK中的重生的主要内容,如果未能解决你的问题,请参考以下文章

我的Android进阶之旅NDK开发之在C++代码中使用Android Log打印日志,打印出C++的函数耗时以及代码片段耗时详情

无法从片段中的 SQLite 获取数据

NDK: ant 错误 [javah] Exception in thread "main" java.lang.NullPointerException 多种解决办法(代码片段

Android:SQLite 中的自定义排序规则

当sqlite android片段中的数据更改或删除时如何刷新recyclerview?

如果 SQLite 为空或有记录,则更改片段中的视图