216 lines
7.7 KiB
Plaintext
216 lines
7.7 KiB
Plaintext
|
<h1>
|
||
|
SQLite Android Bindings
|
||
|
</h1>
|
||
|
|
||
|
<p> The SQLite library is a core part of the Android environment. Java
|
||
|
applications and content providers access SQLite using the interface in
|
||
|
the
|
||
|
<a href="http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html">android.database.sqlite</a> namespace.
|
||
|
|
||
|
<p> One disadvantage of using Android's built-in SQLite support is that the
|
||
|
application is forced to use the version of SQLite that the current version of
|
||
|
Android happened to ship with. If your application happens to require a newer
|
||
|
version of SQLite, or a build with a custom extension or
|
||
|
<a href=http://www.sqlite.org/vfs.html>VFS</a> installed, you're out of luck.
|
||
|
|
||
|
<p>The code in this project allows an application to use the
|
||
|
<a href=http://developer.android.com/tools/sdk/ndk/index.html>Android NDK</a>
|
||
|
to build a custom version of SQLite to be shipped with the application while
|
||
|
still continuing to use the standard Java interface.
|
||
|
|
||
|
<h2>Normal Usage</h2>
|
||
|
|
||
|
<h3>Installation</h3>
|
||
|
|
||
|
<p>
|
||
|
Android API levels 15 (Android 4.0.3) and greater are supported. If
|
||
|
targetting API level 16 or greater, use the default "trunk" branch of this
|
||
|
project. Or, for API level 15, use the "api-level-15" branch. It is not possible
|
||
|
to target an API level lower than 15.
|
||
|
|
||
|
<p>
|
||
|
Copy the following files from this project into the equivalent locations in
|
||
|
the application project.
|
||
|
|
||
|
<pre>
|
||
|
jni/Android.mk
|
||
|
jni/Application.mk
|
||
|
jni/sqlite/* (copy contents of directory recursively)
|
||
|
src/org/sqlite/database/* (copy contents of directory recursively)
|
||
|
</pre>
|
||
|
|
||
|
<p>
|
||
|
Following this, the directory structures should contain
|
||
|
[/tree?ci=trunk&re=%5ejni%7csrc/org/sqlite/data&expand | these files].
|
||
|
|
||
|
<p>
|
||
|
For API level 15 only, also copy the following:
|
||
|
|
||
|
<pre>
|
||
|
src/org/sqlite/os/* (copy contents of directory recursively)
|
||
|
</pre>
|
||
|
|
||
|
<p>
|
||
|
Directory "jni/sqlite/" contains copies of the sqlite3.h and sqlite3.c
|
||
|
source files. Between them, they contain the
|
||
|
<a href=http://www.sqlite.org/amalgamation.html>source code for the SQLite
|
||
|
library</a>. If necessary, replace these with the source for the specific
|
||
|
version of SQLite required. If SQLite is to be compiled with any special
|
||
|
pre-processor macros defined, add them to the "jni/sqlite/Android.mk" file
|
||
|
(not jni/Android.mk).
|
||
|
|
||
|
<p>
|
||
|
Once the files have been added to the project, run the command "ndk-build"
|
||
|
in the root directory of the project. This compiles the native code in
|
||
|
the jni/ directory (including the custom SQLite version) to shared libraries
|
||
|
that will be deployed to the device along with the application. Assuming
|
||
|
it is successful, unless you modify the sources or makefiles within the
|
||
|
jni/ directory structure, you should not need to run "ndk-build" again.
|
||
|
|
||
|
<h3>Application Programming</h3>
|
||
|
|
||
|
<p>
|
||
|
Before using any SQLite related methods or objects, the shared library
|
||
|
compiled using the ndk must be loaded into the application using the
|
||
|
following code:
|
||
|
|
||
|
<verbatim>
|
||
|
System.loadLibrary("sqliteX");
|
||
|
</verbatim>
|
||
|
|
||
|
<p>
|
||
|
One way to ensure that the shared library is loaded early enough is
|
||
|
to add it to a "static" block within the declaration of the application's
|
||
|
main Activity class.
|
||
|
|
||
|
<p>
|
||
|
The classes that make up the built-in Android SQLite interface reside in
|
||
|
the "android.database.sqlite" namespace. This interface provides all of
|
||
|
the same classes, except within the "org.sqlite.database.sqlite" namespace.
|
||
|
This means that to modify an application to use the custom version of
|
||
|
SQLite, all that is usually required is to replace all occurrences
|
||
|
"android.database.sqlite" within the source code with
|
||
|
"org.sqlite.database.sqlite". For example, the following:
|
||
|
|
||
|
<verbatim>
|
||
|
import android.database.sqlite.SQLiteDatabase;
|
||
|
</verbatim>
|
||
|
|
||
|
<p>should be replaced with:
|
||
|
|
||
|
<verbatim>
|
||
|
import org.sqlite.database.sqlite.SQLiteDatabase;
|
||
|
</verbatim>
|
||
|
|
||
|
<p>
|
||
|
As well as replacing all uses of the classes in the
|
||
|
android.database.sqlite.* namespace, the application must also be sure
|
||
|
to use the following two:
|
||
|
|
||
|
<verbatim>
|
||
|
org.sqlite.database.SQLException
|
||
|
org.sqlite.database.DatabaseErrorHandler
|
||
|
</verbatim>
|
||
|
|
||
|
<p>instead of:
|
||
|
|
||
|
<verbatim>
|
||
|
android.database.SQLException
|
||
|
android.database.DatabaseErrorHandler
|
||
|
</verbatim>
|
||
|
|
||
|
<p>Aside from namespace changes, there are other differences from the
|
||
|
stock Android interface that applications need to be aware of:
|
||
|
|
||
|
<ol>
|
||
|
<li> The SQLiteStatement.<a href="http://developer.android.com/reference/android/database/sqlite/SQLiteStatement.html#simpleQueryForBlobFileDescriptor()">simpleQueryForBlobFileDescriptor()</a>
|
||
|
API is not available.
|
||
|
|
||
|
<li> The collation sequence "UNICODE" is not available.
|
||
|
|
||
|
<li> The collation sequence "LOCALIZED", which normally changes with the
|
||
|
system's current locale, is always equivalent to SQLite's built
|
||
|
in collation BINARY.
|
||
|
</ol>
|
||
|
|
||
|
|
||
|
<h2>Using The SQLite Encryption Extension</h2>
|
||
|
|
||
|
<p>
|
||
|
To use the <a href=http://www.sqlite.org/see/doc/trunk/www/readme.wiki>
|
||
|
SQLite Encryption Extension</a> (SEE) on Android, replace the sqlite3.c
|
||
|
file at "jni/sqlite/sqlite3.c" with a SEE-enabled version (i.e. the
|
||
|
concatenation of sqlite3.c and see.c - refer to the link above for
|
||
|
details). Next, open the file jni/sqlite/Android.mk and locate the
|
||
|
following two lines:
|
||
|
|
||
|
<verbatim>
|
||
|
# If using SEE, uncomment the following:
|
||
|
# LOCAL_CFLAGS += -DSQLITE_HAS_CODEC
|
||
|
</verbatim>
|
||
|
|
||
|
<p>
|
||
|
Uncomment the second of them, then run "ndk-build" as described above to
|
||
|
generate the shared libraries.
|
||
|
|
||
|
<p>
|
||
|
After opening or creating an encrypted database, the application must
|
||
|
immediately execute a PRAGMA to configure the encryption key. This must
|
||
|
be done before any other database methods are called. For example:
|
||
|
|
||
|
<verbatim>
|
||
|
import org.sqlite.database.sqlite.SQLiteDatabase;
|
||
|
|
||
|
...
|
||
|
|
||
|
SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase("my.db", null);
|
||
|
db.execSQL("PRAGMA key = 'secretkey'");
|
||
|
</verbatim>
|
||
|
|
||
|
<p>
|
||
|
Or, if you are using the
|
||
|
<a href=http://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html>SQLiteOpenHelper</a>
|
||
|
helper class, the PRAGMA must be the first thing executed within the
|
||
|
onConfigure() callback. For example:
|
||
|
|
||
|
<verbatim>
|
||
|
import org.sqlite.database.sqlite.SQLiteDatabase;
|
||
|
import org.sqlite.database.sqlite.SQLiteHelper;
|
||
|
|
||
|
...
|
||
|
|
||
|
class MyHelper extends SQLiteOpenHelper {
|
||
|
...
|
||
|
void onConfigure(SQLiteDatabase db){
|
||
|
db.execSQL("PRAGMA key = 'secretkey'");
|
||
|
}
|
||
|
...
|
||
|
}
|
||
|
</verbatim>
|
||
|
|
||
|
<p>
|
||
|
Refer to the <a href=http://www.sqlite.org/see/doc/trunk/www/readme.wiki>
|
||
|
SEE documentation</a> for further details regarding encryption keys.
|
||
|
|
||
|
<p>Aside from supporting encrypted databases, SEE-enabled builds behave
|
||
|
differently in two more respects:
|
||
|
|
||
|
<ol>
|
||
|
<li> <p>The SQLiteDatabase.<a href="http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html#enableWriteAheadLogging()">enableWriteAheadLogging()</a> method does not enable
|
||
|
connection pooling. It is not possible for connection pooling to be
|
||
|
used with a SEE-enabled build (even if the database is unencrypted).
|
||
|
|
||
|
<li> <p>In Android, if database corruption is encountered, or if an attempt is
|
||
|
made to open a file that is not an SQLite database, the default
|
||
|
behaviour is to delete the file and create an empty database file in
|
||
|
its place. In a SEE-enabled build, the default behaviour is to throw
|
||
|
an exception.<br><br>
|
||
|
The reason for this is that supplying an incorrect encryption key
|
||
|
is indistinguishable from opening a file that is not a database file.
|
||
|
And it seems too dangerous to simply delete the file in this case.
|
||
|
<br><br>
|
||
|
The default behaviour can be overriden using the
|
||
|
<a href="http://developer.android.com/reference/android/database/DatabaseErrorHandler.html">DatabaseErrorHandler</a> interface.
|
||
|
|
||
|
</ol>
|