SQLCipher 与Room的结合方式同上面的情形是类似,也是通过代理的方式实现。由于Room需要的类跟SQLCipher 提供的类包名不一致,所以这里需要对SQLCipher 提供的类进行一下代理然后传递给Room架构使用就可以了。
fun init(context: Context) { ? val ?mDataBase1 = Room.databaseBuilder( ? ? ? ? context.applicationContext, ? ? ? ? TestDb::class.java, ? ? ? ? "user_login_info_db" ? ? ).openHelperFactory(SafeHelperFactory("".toByteArray())) ? ? ? .build() }
这里主要需要自定义一个SupportSQLiteOpenHelper.Factory也就是SafeHelperFactory 这个SafeHelperFactory 完全是仿照Room架构默认的Factory 也就是FrameworkSQLiteOpenHelperFactory 实现。主要是用户创建一个用于打开数据库的SQLiteOpenHelper,主要的区别是自定义的Facttory 需要一个用于加密与解密的密码。
我们首先需要定义一个自己的OpenHelperFactory
public class SafeHelperFactory implements SupportSQLiteOpenHelper.Factory { ? public static final String POST_KEY_SQL_MIGRATE = "PRAGMA cipher_migrate;"; ? public static final String POST_KEY_SQL_V3 = "PRAGMA cipher_compatibility = 3;"; ? final private byte[] passphrase; ? final private Options options; ? ? public SafeHelperFactory(byte[] passphrase, Options options) { ? ? this.passphrase = passphrase; ? ? this.options = options; ? } ? /** ? ?* {@inheritDoc} ? ?*/ ? @Override ? public SupportSQLiteOpenHelper create( ? ? SupportSQLiteOpenHelper.Configuration configuration) { ? ? return(create(configuration.context, configuration.name, ? ? ? configuration.callback)); ? } ? public SupportSQLiteOpenHelper create(Context context, String name, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? SupportSQLiteOpenHelper.Callback callback) { ? ? ?//创建一个Helper ? ? return(new Helper(context, name, callback, passphrase, options)); ? } ? private void clearPassphrase(char[] passphrase) { ? ? for (int i = 0; i < passphrase.length; i++) { ? ? ? passphrase[i] = (byte) 0; ? ? } ? }
SafeHelperFactory 的create创建了一个Helper,这个Helper实现了Room框架的SupportSQLiteOpenHelper ,实际这个Helper 是个代理类被代理的类为OpenHelper ,OpenHelper 用于操作SQLCipher 提供的数据库类。
class Helper implements SupportSQLiteOpenHelper { ? private final OpenHelper delegate; ? private final byte[] passphrase; ? private final boolean clearPassphrase; ? Helper(Context context, String name, Callback callback, byte[] passphrase, ? ? ? ? ?SafeHelperFactory.Options options) { ? ? SQLiteDatabase.loadLibs(context); ? ? clearPassphrase=options.clearPassphrase; ? ? delegate=createDelegate(context, name, callback, options); ? ? this.passphrase=passphrase; ? } ? private OpenHelper createDelegate(Context context, String name, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? final Callback callback, SafeHelperFactory.Options options) { ? ? final Database[] dbRef = new Database[1]; ? ? return(new OpenHelper(context, name, dbRef, callback, options)); ? } ? /** ? ?* {@inheritDoc} ? ?*/ ? @Override ? synchronized public String getDatabaseName() { ? ? return delegate.getDatabaseName(); ? } ? /** ? ?* {@inheritDoc} ? ?*/ ? @Override ? @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN) ? synchronized public void setWriteAheadLoggingEnabled(boolean enabled) { ? ? delegate.setWriteAheadLoggingEnabled(enabled); ? } ? @Override ? synchronized public SupportSQLiteDatabase getWritableDatabase() { ? ? SupportSQLiteDatabase result; ? ? try { ? ? ? result = delegate.getWritableSupportDatabase(passphrase); ? ? } ? ? catch (SQLiteException e) { ? ? ? if (passphrase != null) { ? ? ? ? boolean isCleared = true; ? ? ? ? for (byte b : passphrase) { ? ? ? ? ? isCleared = isCleared && (b == (byte) 0); ? ? ? ? } ? ? ? ? if (isCleared) { ? ? ? ? ? throw new IllegalStateException("The passphrase appears to be cleared. This happens by" + ? ? ? ? ? ? ? "default the first time you use the factory to open a database, so we can remove the" + ? ? ? ? ? ? ? "cleartext passphrase from memory. If you close the database yourself, please use a" + ? ? ? ? ? ? ? "fresh SafeHelperFactory to reopen it. If something else (e.g., Room) closed the" + ? ? ? ? ? ? ? "database, and you cannot control that, use SafeHelperFactory.Options to opt out of" + ? ? ? ? ? ? ? "the automatic password clearing step. See the project README for more information."); ? ? ? ? } ? ? ? } ? ? ? throw e; ? ? } ? ? if (clearPassphrase && passphrase != null) { ? ? ? for (int i = 0; i < passphrase.length; i++) { ? ? ? ? passphrase[i] = (byte) 0; ? ? ? } ? ? } ? ? return(result); ? } ? /** ? ?* {@inheritDoc} ? ?* ? ?* NOTE: this implementation delegates to getWritableDatabase(), to ensure ? ?* that we only need the passphrase once ? ?*/ ? @Override ? public SupportSQLiteDatabase getReadableDatabase() { ? ? return(getWritableDatabase()); ? } ? /** ? ?* {@inheritDoc} ? ?*/ ? @Override ? synchronized public void close() { ? ? delegate.close(); ? } ? static class OpenHelper extends SQLiteOpenHelper { ? ? private final Database[] dbRef; ? ? private volatile Callback callback; ? ? private volatile boolean migrated; }
真正操作数据库的类OpenHelper,OpenHelper 继承的SQLiteOpenHelper 是net.sqlcipher.database 包下的
static class OpenHelper extends SQLiteOpenHelper { ? ? private final Database[] dbRef; ? ? private volatile Callback callback; ? ? private volatile boolean migrated; ?OpenHelper(Context context, String name, final Database[] dbRef, final Callback callback, ? ? ? ? ? ? ? ?final SafeHelperFactory.Options options) { ? ? ? super(context, name, null, callback.version, new SQLiteDatabaseHook() { ? ? ? ? @Override ? ? ? ? public void preKey(SQLiteDatabase database) { ? ? ? ? ? if (options!=null && options.preKeySql!=null) { ? ? ? ? ? ? database.rawExecSQL(options.preKeySql); ? ? ? ? ? } ? ? ? ? } ? ? ? ? @Override ? ? ? ? public void postKey(SQLiteDatabase database) { ? ? ? ? ? if (options!=null && options.postKeySql!=null) { ? ? ? ? ? ? database.rawExecSQL(options.postKeySql); ? ? ? ? ? } ? ? ? ? } ? ? ? }, new DatabaseErrorHandler() { ? ? ? ? @Override ? ? ? ? public void onCorruption(SQLiteDatabase dbObj) { ? ? ? ? ? Database db = dbRef[0]; ? ? ? ? ? if (db != null) { ? ? ? ? ? ? callback.onCorruption(db); ? ? ? ? ? } ? ? ? ? } ? ? ? }); ? ? ? this.dbRef = dbRef; ? ? ? this.callback=callback; ? ? } ? ? synchronized SupportSQLiteDatabase getWritableSupportDatabase(byte[] passphrase) { ? ? ? migrated = false; ? ? ? SQLiteDatabase db=super.getWritableDatabase(passphrase); ? ? ? if (migrated) { ? ? ? ? close(); ? ? ? ? return getWritableSupportDatabase(passphrase); ? ? ? } ? ? ? return getWrappedDb(db); ? ? } ? ? synchronized Database getWrappedDb(SQLiteDatabase db) { ? ? ? Database wrappedDb = dbRef[0]; ? ? ? if (wrappedDb == null) { ? ? ? ? wrappedDb = new Database(db); ? ? ? ? dbRef[0] = wrappedDb; ? ? ? } ? ? ? return(dbRef[0]); ? ? } ? ? /** ? ? ?* {@inheritDoc} ? ? ?*/ ? ? @Override ? ? public void onCreate(SQLiteDatabase sqLiteDatabase) { ? ? ? callback.onCreate(getWrappedDb(sqLiteDatabase)); ? ? } ? ? /** ? ? ?* {@inheritDoc} ? ? ?*/ ? ? @Override ? ? public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) { ? ? ? migrated = true; ? ? ? callback.onUpgrade(getWrappedDb(sqLiteDatabase), oldVersion, newVersion); ? ? } ? ? /** ? ? ?* {@inheritDoc} ? ? ?*/ ? ? @Override ? ? public void onConfigure(SQLiteDatabase db) { ? ? ? callback.onConfigure(getWrappedDb(db)); ? ? } ? ? /** ? ? ?* {@inheritDoc} ? ? ?*/ ? ? @Override ? ? public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { ? ? ? migrated = true; ? ? ? callback.onDowngrade(getWrappedDb(db), oldVersion, newVersion); ? ? } ? ? /** ? ? ?* {@inheritDoc} ? ? ?*/ ? ? @Override ? ? public void onOpen(SQLiteDatabase db) { ? ? ? if (!migrated) { ? ? ? ? // from Google: "if we've migrated, we'll re-open the db so we ?should not call the callback." ? ? ? ? callback.onOpen(getWrappedDb(db)); ? ? ? } ? ? } ? ? /** ? ? ?* {@inheritDoc} ? ? ?*/ ? ? @Override ? ? public synchronized void close() { ? ? ? super.close(); ? ? ? dbRef[0] = null; ? ? } ? }
这里的OpenHelper 完全是仿照Room 框架下的OpenHelper 实现的。
标签:SQLite
相关阅读 >>
Sqlitestudio优雅调试android手机数据库Sqlite(推荐)
更多相关阅读请进入《Sqlite》频道 >>
数据库系统概念 第6版
本书主要讲述了数据模型、基于对象的数据库和XML、数据存储和查询、事务管理、体系结构等方面的内容。