Android从非文件室版本迁移到加密文件室(带SafeRoom)失败

Android从非文件室版本迁移到加密文件室(带SafeRoom)失败,android,commonsware-cwac,Android,Commonsware Cwac,我有一个应用程序进行了多次迁移,其中一个是从使用Room之前的版本迁移到引入Room时的版本。我发现它与RoomOpenHelper.onUpgrade回调一起运行,但当我使用SafeHelperFactory时,它会创建一个SQLiteOpenHelper的实例,该实例本身包含对RoomOpenHelper的回调。我认为这在迁移过程中造成了冲突。奇怪的是,当我从一个已经有房间(没有加密)的应用程序版本迁移到一个有SafeRoom的版本时,这个问题并没有发生。当我从一个房间迁移到另一个房间(没有

我有一个应用程序进行了多次迁移,其中一个是从使用Room之前的版本迁移到引入Room时的版本。我发现它与
RoomOpenHelper.onUpgrade
回调一起运行,但当我使用
SafeHelperFactory
时,它会创建一个
SQLiteOpenHelper
的实例,该实例本身包含对
RoomOpenHelper
的回调。我认为这在迁移过程中造成了冲突。奇怪的是,当我从一个已经有房间(没有加密)的应用程序版本迁移到一个有SafeRoom的版本时,这个问题并没有发生。当我从一个房间迁移到另一个房间(没有加密)时,这个问题也能顺利运行。我得到的stacktrace如下(虽然不确定迁移需要多少上下文,但我认为迁移本身不是问题,因为它在从一个房间迁移到另一个房间的过程中起作用,并且已经工作了一段时间,当我尝试引入SafeRoom时,问题就出现了,请看正在进行的函数/方法调用的顺序)

没有空间的版本是15。我使用Dagger,所以集成SafeRoom的方法如下

    /**
     * Provide the single instance of our room database
     */
    @Singleton
    @Provides
    fun provideDatabase(@Named("app") context: Context): MyDatabase {
        val databaseState = SQLCipherUtils.getDatabaseState(context, "DatabaseName.db")
        Log.d("ROOM", "database status: $databaseState")
        if (databaseState == SQLCipherUtils.State.UNENCRYPTED) {
            Log.d("ROOM", "start encryption")
            val passphrase = "databasekey".toCharArray()
            SQLCipherUtils.encrypt(context, "DatabaseName.db", passphrase)
            Log.d("ROOM", "finish encryption")
        }

        val factory = SafeHelperFactory.fromUser(SpannableStringBuilder("databasekey"))

        return Room
                .databaseBuilder(
                        app,
                        MyDatabase::class.java,
                        "DatabaseName.db"
                )
                .openHelperFactory(factory)
                .allowMainThreadQueries()
                .addMigrations(*getMigrationList())
                .build()
    }

如果需要更多上下文,我可以提供。如果这是一个已知问题或已经有一个可行的解决方案,请重定向我。谢谢。

您确实不想运行
encrypt()
在主应用程序线程上,您现在无法控制在哪个线程上运行。此外,您的加密使用的是硬编码的密码短语,这是毫无意义的。如果这是您真正的代码所做的,只需删除SafeRoom即可。@Commonware是的,我知道硬编码的密码短语,这是检查SafeRoom是否可以执行加密的一部分被添加到应用程序中,它将决定其集成。关于
encrypt()
call,在通过Dagger提供房间的环境中,哪里是使用它的最佳位置?我认为在这种情况下,为数据库使用DI并不一定实用。环绕数据库的存储库可以使用DI,但存储库在获得密码短语之前无法打开数据库,这需要用户I交互。类似地,存储库不应该在没有该密码短语的情况下对数据库进行加密,此时存储库可以安排在后台线程上执行该加密。回到您的问题,您需要检查加密的数据库并查看它有哪些表。
    /**
     * Provide the single instance of our room database
     */
    @Singleton
    @Provides
    fun provideDatabase(@Named("app") context: Context): MyDatabase {
        val databaseState = SQLCipherUtils.getDatabaseState(context, "DatabaseName.db")
        Log.d("ROOM", "database status: $databaseState")
        if (databaseState == SQLCipherUtils.State.UNENCRYPTED) {
            Log.d("ROOM", "start encryption")
            val passphrase = "databasekey".toCharArray()
            SQLCipherUtils.encrypt(context, "DatabaseName.db", passphrase)
            Log.d("ROOM", "finish encryption")
        }

        val factory = SafeHelperFactory.fromUser(SpannableStringBuilder("databasekey"))

        return Room
                .databaseBuilder(
                        app,
                        MyDatabase::class.java,
                        "DatabaseName.db"
                )
                .openHelperFactory(factory)
                .allowMainThreadQueries()
                .addMigrations(*getMigrationList())
                .build()
    }