The community edition of SQLCipher for Android is distributed via the AAR package format allowing usage in either Java or Kotlin-based Android projects. Integration within Gradle can be performed by adding the
following entry to the dependencies
section of the app/build.gradle
file:
implementation 'net.zetetic:sqlcipher-android:4.6.1@aar'
implementation 'androidx.sqlite:sqlite:2.2.0'
This tutorial will cover integrating the binaries of SQLCipher for Android into an existing Android application. This tutorial assumes the developer has the latest SQLCipher for Android commercial edition packages downloaded locally.
We need to copy the AAR library file over into the app libs
directory of our application. Execute the following commands:
% cp sqlcipher-android-4.6.1.aar app/libs
Next, modify the project’s settings.gradle
file, adding the following flatDir
element
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
flatDir {
dirs 'app/libs'
}
}
}
Within the app module build.gradle
, add the following to the dependencies
block:
implementation(name: 'sqlcipher-android-4.6.1', ext: 'aar')
implementation 'androidx.sqlite:sqlite:2.22.0'
For Commercial Edition only, the license code may be provided when opening a connection via SQLiteDatabaseHook
. Below is an example:
SQLiteDatabaseHook hook = new SQLiteDatabaseHook() {
public void preKey(SQLiteConnection connection) {
connection.executeForString(String.format("PRAGMA cipher_license = '%s';", LICENSE_CODE), new Object[]{}, null);
}
public void postKey(SQLiteConnection connection) {}
};
SQLiteDatabase database = SQLiteDatabase.openOrCreateDatabase(databasePath.getAbsolutePath(), password, null, null, hook);
Next we will modify the source of the activity to properly initialize the native libraries for SQLCipher and then create our database file inserting a record. The application should import the net.zetetic.database.sqlcipher
classes. The call to System.loadLibrary("sqlcipher")
must occur before any other database operation. Please note, if subclassing a SQLiteOpenHelper
, specify the constructor argument with true
to enable WAL journal mode and improve performance or call setWriteAheadLoggingEnabled(true)
in your constructor. WAL journal mode may be enabled on a SQLiteDatabase
instance using the method enableWriteAheadLogging()
.
package com.demo.sqlcipher
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import net.zetetic.database.sqlcipher.SQLiteDatabase;
public class HelloSQLCipherActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
InitializeSQLCipher();
}
private void InitializeSQLCipher() {
System.loadLibrary("sqlcipher");
File databaseFile = getDatabasePath("demo.db");
databaseFile.mkdirs();
SQLiteDatabaseHook hook = new SQLiteDatabaseHook() {
public void preKey(SQLiteConnection connection) {
// When using Commercial or Enterprise packages you must call PRAGMA cipher_license with a valid License Code.
// Failure to provide a license code will result in an SQLITE_AUTH(23) error.
// Trial licenses are available at https://www.zetetic.net/sqlcipher/trial/
connection.executeForString(String.format("PRAGMA cipher_license = '%s';", "YOUR LICENSE CODE HERE"),new Object[]{}, null);
}
public void postKey(SQLiteConnection connection) {}
};
SQLiteDatabase database = SQLiteDatabase.openOrCreateDatabase(databaseFile, password, null, null, hook);
database.execSQL("create table t1(a, b)");
database.execSQL("insert into t1(a, b) values(?, ?)", new Object[]{"row 1 column 1", "row 1 column 2"});
}
}
To perform operations on the database instance immediately before or after the keying operation is performed, provide a SQLiteDatabaseHook
instance when creating your database connection:
SQLiteDatabaseHook hook = new SQLiteDatabaseHook() {
public void preKey(SQLiteConnection connection) { }
public void postKey(SQLiteConnection connection) { }
};
SQLCipher for Android can be seamlessly used with Kotlin as well:
package com.demo.sqlcipher
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import net.zetetic.database.sqlcipher.SQLiteDatabase
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
initializeSQLCipher()
}
private fun initializeSQLCipher() {
System.loadLibrary("sqlcipher")
val databaseFile = getDatabasePath("test.db")
databaseFile.mkdirs()
val hook = object : SQLiteDatabaseHook {
override fun preKey(connection: SQLiteConnection) {
// When using Commercial or Enterprise packages you must call PRAGMA cipher_license with a valid License Code.
// Failure to provide a license code will result in an SQLITE_AUTH(23) error.
// Trial licenses are available at https://www.zetetic.net/sqlcipher/trial/
connection.executeForString( String.format("PRAGMA cipher_license = '%s';", "YOUR LICENSE CODE HERE"),arrayOf(), null)
}
override fun postKey(connection: SQLiteConnection) {}
}
val database = SQLiteDatabase.openOrCreateDatabase(databaseFile, password, null, null, hook)
if (database != null) {
database.execSQL("create table t1(a,b);")
database.execSQL(
"insert into t1(a,b) values(?, ?);",
arrayOf("one for the money", "two for the show")
)
}
}
}