這是第一次在簡書上寫文章救欧,沒想到寫的就是純技術(shù)類的文章值戳,最近被這個小清新風格的網(wǎng)站吸引住了西篓,也想換換風格愈腾,平時一般都是逛逛技術(shù)類的博客,但是發(fā)現(xiàn)簡書這個網(wǎng)站污淋,特別是被灌了一些雞湯后顶滩,決定以后遷移到這個網(wǎng)站了,估計寫的話也是一些關(guān)于技術(shù)類的文章把寸爆,誰讓咱是一名不折不扣的攻城獅呢礁鲁。
好的,閑話不多說赁豆,下面進入主題仅醇。
公司的一些產(chǎn)品中采用了?SQLCipher?這個庫來來對數(shù)據(jù)庫中的數(shù)據(jù)進行加密,但是在Android5.0版本上SQLCipher會出現(xiàn)readonly database錯誤:
net.sqlcipher.database.SQLiteException: attempt to write a readonly database
一直以為這是SQLCipher的問題魔种,在Github上也有人提出過這個問題析二,但是這些方案沒能解決我遇到的問題。
https://github.com/sqlcipher/android-database-sqlcipher/issues/161
這個問題只有在Android5.0上才會出現(xiàn)节预,但是目前采用5.0版本的機型應(yīng)該不會很多(很多機型要么4.4要么就直接 >5.0)而且采用SQLCipher加密庫的App也不是很多叶摄,所以這個問題出現(xiàn)的幾率并不高,但是誰讓我們的用戶偏偏就用了Android5.0的機型呢安拟,所以不得不去啃這塊硬骨頭(攻城獅嘛蛤吓,攻不下城怎么能叫攻城獅呢)。
經(jīng)過不懈的努力后糠赦,終于找到了解決方案:
Workaround for Nexus 9 SQLite file write operations on external dirs?
其實這并不是SQLCipher的問題会傲,而是Android5.0的一個BUG锅棕,Google在Android的下一個版本中進行了修復,所以這個問題只有在Android5.0上才會出現(xiàn)淌山。
國外大神也給出了非官方的解決方案:
https://android-review.googlesource.com/#/c/115351/
Store inodes in unsigned long long
In 32 bit ABIs, ino_t is a 32 bit type, while the st_ino field
in struct stat is 64 bits wide in both 32 and 64 bit processes.
This means that struct stat can expose inode numbers that are
truncated when stored in an ino_t.
The SDCard fuse daemon (/system/bin/sdcard) uses raw pointer
values as inode numbers, so on 64 bit devices, we're very likely
to observe inodes that need > 32 bits to represent.
The fileHasMoved function in sqlite compares the stored
inode value with a new one from stat, and when the stored
value is truncated, this check will falsely indicate that
the file has been moved. When the fileHasMoved function
triggers, other functions start returning errors indicating
that the database is in read-only mode.
NOTE: Bionic differs from glibc in that struct stat's st_ino
is *always* 64 bits wide, and not the same width as ino_t.
如果要修復該BUG的話裸燎,肯定得自己下載SQLCipher源碼自己進行編譯了,源碼是C編寫的泼疑,所以需要下載NDK才能進行編譯德绿。
NDK環(huán)境的搭建這里就不再敘述了,網(wǎng)上有很多的教程王浴。
NDK環(huán)境搭建好之后脆炎,可以根據(jù)官方的教程進行編譯:
https://www.zetetic.net/sqlcipher/sqlcipher-for-android/
當然在編譯之前需要對源碼進行修改,打開
https://android-review.googlesource.com/#/c/115351/3/dist/sqlite3.c
可以看到?sqlite.c?文件需要修改的地方:
25322 ? ?ino_t ino; /* Inode number */
修改為:
25322 ? ?#ifdef ANDROID
25323 ? ?// Bionic's struct stat has a 64 bit st_ino on both 32 and
25324 ? ?// 64 bit architectures. ino_t remains 32 bits wide on 32 bit
25325 ? ?// architectures and can lead to inode truncation.
25326 ? ?unsigned long long ino; /* Inode number */
25327 ? ?#else
25328 ? ?ino_t ino; /* Inode number */
25329 ? ?#endif
修改完成后保存文件氓辣,然后按照官方教程進行編譯秒裕,編譯完成后得到的so文件和jar文件即可用在Android5.0版本上。
----
給需要的朋友分享一個我自己編譯的sqlcipher庫http://pan.baidu.com/s/1i47SQSd