gpt4 book ai didi

android - 从现有 Room 数据库迁移到 Sqlcipher

转载 作者:行者123 更新时间:2023-12-03 19:17:51 30 4
gpt4 key购买 nike

我的应用程序目前正在使用房间数据库。我打算迁移以使用 Sqlcipher 数据库。我有 fallbackToDestructiveMigration()启用但仍然抛出以下错误

java.lang.RuntimeException: Exception while computing database live data.
at androidx.room.RoomTrackingLiveData$1.run(RoomTrackingLiveData.java:92)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
at java.lang.Thread.run(Thread.java:764)
Caused by: net.sqlcipher.database.SQLiteException: file is not a database: , while compiling: select count(*) from sqlite_master;
at net.sqlcipher.database.SQLiteCompiledSql.native_compile(Native Method)
at net.sqlcipher.database.SQLiteCompiledSql.compile(SQLiteCompiledSql.java:91)
at net.sqlcipher.database.SQLiteCompiledSql.<init>(SQLiteCompiledSql.java:64)
at net.sqlcipher.database.SQLiteProgram.<init>(SQLiteProgram.java:91)
at net.sqlcipher.database.SQLiteQuery.<init>(SQLiteQuery.java:48)
at net.sqlcipher.database.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:60)
at net.sqlcipher.database.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.java:2016)
at net.sqlcipher.database.SQLiteDatabase.rawQuery(SQLiteDatabase.java:1902)
at net.sqlcipher.database.SQLiteDatabase.keyDatabase(SQLiteDatabase.java:2673)
at net.sqlcipher.database.SQLiteDatabase.openDatabaseInternal(SQLiteDatabase.java:2603)
at net.sqlcipher.database.SQLiteDatabase.openDatabase(SQLiteDatabase.java:1247)
at net.sqlcipher.database.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:1322)
at net.sqlcipher.database.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:166)
at net.sqlcipher.database.SupportHelper.getWritableDatabase(SupportHelper.java:83)
at androidx.room.RoomDatabase.inTransaction(RoomDatabase.java:476)
at androidx.room.RoomDatabase.assertNotSuspendingTransaction(RoomDatabase.java:281)
at androidx.room.RoomDatabase.query(RoomDatabase.java:324)
at androidx.room.util.DBUtil.query(DBUtil.java:83)
at com.screenlocker.secure.room.MyDao_Impl$29.call(MyDao_Impl.java:1249)
at com.screenlocker.secure.room.MyDao_Impl$29.call(MyDao_Impl.java:1246)
at androidx.room.RoomTrackingLiveData$1.run(RoomTrackingLiveData.java:90)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162) 
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636) 
at java.lang.Thread.run(Thread.java:764) 

有什么方法可以销毁我所有的数据库并转移到 Sqlcipher?我也试过 database.delete("table_name",null,null)命令手动删除表 n 迁移,但它仍然无法正常工作。我的数据库创建代码如下。
DatabaseSecretProvider provider = new DatabaseSecretProvider(context);
byte[] passphrase = provider.getOrCreateDatabaseSecret().asBytes();
SupportFactory factory = new SupportFactory(passphrase);
instance = Room.databaseBuilder(context, MyAppDatabase.class, AppConstants.DATABASE_NAME)
.openHelperFactory(factory)
.fallbackToDestructiveMigration()
.build();

我正在使用以下版本的 Sqlcipher
implementation 'net.zetetic:android-database-sqlcipher:4.3.0'
implementation "androidx.sqlite:sqlite:2.1.0"

最佳答案

您可以使用 sqlcipher_export 加密未加密的数据库。来自 sqlcipher 的便捷方法。 所以你不必使用 fallbackToDestructiveMigration或花时间编写您的自定义迁移工具。
来自开发者的网站:

To use sqlcipher_export() to encrypt an existing database, first open up the standard SQLite database, but don’t provide a key. Next, ATTACH a new encrypted database, and then call the sqlcipher_export() function in a SELECT statement, passing in the name of the attached database you want to write the main database schema and data to.

$ ./sqlcipher plaintext.db
sqlite> ATTACH DATABASE 'encrypted.db' AS encrypted KEY 'newkey';
sqlite> SELECT sqlcipher_export('encrypted');
sqlite> DETACH DATABASE encrypted;

Finally, securely delete the existing plaintext database, and then open up the new encrypted database as usual using sqlite3_key or PRAGMA key.


来源: https://discuss.zetetic.net/t/how-to-encrypt-a-plaintext-sqlite-database-to-use-sqlcipher-and-avoid-file-is-encrypted-or-is-not-a-database-errors/868
@commonsguy还有一个如何在 Android 中执行此操作的示例:
  /**
* Replaces this database with a version encrypted with the supplied
* passphrase, deleting the original. Do not call this while the database
* is open, which includes during any Room migrations.
*
* @param ctxt a Context
* @param originalFile a File pointing to the database
* @param passphrase the passphrase from the user
* @throws IOException
*/
public static void encrypt(Context ctxt, File originalFile, byte[] passphrase)
throws IOException {
SQLiteDatabase.loadLibs(ctxt);

if (originalFile.exists()) {
File newFile=File.createTempFile("sqlcipherutils", "tmp",
ctxt.getCacheDir());
SQLiteDatabase db=
SQLiteDatabase.openDatabase(originalFile.getAbsolutePath(),
"", null, SQLiteDatabase.OPEN_READWRITE);
int version=db.getVersion();

db.close();

db=SQLiteDatabase.openDatabase(newFile.getAbsolutePath(), passphrase,
null, SQLiteDatabase.OPEN_READWRITE, null, null);

final SQLiteStatement st=db.compileStatement("ATTACH DATABASE ? AS plaintext KEY ''");

st.bindString(1, originalFile.getAbsolutePath());
st.execute();

db.rawExecSQL("SELECT sqlcipher_export('main', 'plaintext')");
db.rawExecSQL("DETACH DATABASE plaintext");
db.setVersion(version);
st.close();
db.close();

originalFile.delete();
newFile.renameTo(originalFile);
}
else {
throw new FileNotFoundException(originalFile.getAbsolutePath()+ " not found");
}
}
来源: https://github.com/commonsguy/cwac-saferoom/blob/v1.2.1/saferoom/src/main/java/com/commonsware/cwac/saferoom/SQLCipherUtils.java#L175-L224
您可以通过 context.getDatabasePath(DATABASE_NAME)originalFile范围。
另见 this comment from commonsguy它解释了如何将它与 getDatabaseState function 结合使用将您的数据从现有的纯文本数据库迁移到 sqlcipher 加密数据库。

关于android - 从现有 Room 数据库迁移到 Sqlcipher,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60204898/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com