实施 SQLCipher 时将 Couchbase Lite 数据库存储在自定义目录中时出错

Error while storing Couchbase Lite database in a custom directory while implementing SQLCipher

所以,

我想要的:

能够告诉 Couchbase Lite (CB Lite) 在哪里存储数据并对其执行 SQLCipher 加密。

我的问题是什么:

即使我在默认目录上进行了加密,但只要我告诉管理器使用自定义目录,它就会在尝试创建数据库时抛出异常: 留言:

"Error 8, 1032 (attempt to write a readonly database) executing sql ' CREATE INDEX docs_docid ON docs(docid)'"

来源:

"Couchbase.Lite.Storage.SQLCipher"

堆栈跟踪:

"at Couchbase.Lite.Storage.SQLCipher.SqlitePCLRawStorageEngine.ExecSQL (System.String sql, SQLitePCL.sqlite3 db, System.Object[] paramArgs) [0x00079] in /Users/jenkins/jenkins/workspace/couchbase-lite-net-build@2/1.4/Android/couchbase-lite-net/src/StorageEngines/SQLiteCommon/storage.sqlite.common/src/DatabaseUpgraderFactory_Upgraders.cs:249 \n at Couchbase.Lite.Storage.SQLCipher.SqlitePCLRawStorageEngine.ExecSQL (System.String sql, System.Object[] paramArgs) <0xd70821f8 + 0x0005f> in <223c4357c0d44faaaa01c387793a30cc>:0 \n at Couchbase.Lite.Storage.SQLCipher.SqlitePCLRawStorageEngine.Open (System.String path, System.Boolean readOnly, System.String schema, Couchbase.Lite.Store.SymmetricKey encryptionKey) [0x00065] in /Users/jenkins/jenkins/workspace/couchbase-lite-net-build@2/1.4/Android/couchbase-lite-net/src/StorageEngines/SQLiteCommon/storage.sqlite.common/src/DatabaseUpgraderFactory.cs:87 "

现在,奇怪的是当 运行 我的代码在模拟器上时,它没有抛出异常。只有当 运行 我的代码在真实设备上(Lenovo TAB 2A 系列,Android 5.0.1)时才会出现问题。

注意:虽然抛出异常,但是创建了custom文件夹,couchbase lite文件夹也创建了,但是里面只有一个叫db的文件。 sqlite3。通常创建三个文件和一个文件夹:

注意 2: 我已将 WRITE_EXTERNAL_STORAGE 权限添加到 Android 清单。

运行没有问题的代码:

public async Task<Database> OpenDatabaseOnEncryptedWayAsync(string encryptionPassword)
    {
        Database encryptedDatabase = null;

        try
        {
            SymmetricKey Key;
            DatabaseOptions options = new DatabaseOptions();
            await Task.Run(() =>
            {
                Key = new SymmetricKey(encryptionPassword);
                options.EncryptionKey = Key;
                options.Create = true;
                options.StorageType = StorageEngineTypes.SQLite;
            });

            // Database stored in default directory
            encryptedDatabase = Manager.SharedInstance.OpenDatabase(database, options);
        }
        catch (CouchbaseLiteException e)
        {
            LogWriterMethod.TryWriteLog(String.Format("Error while creating encrypted database: {0}", e)); 
            Console.WriteLine("Encryption Message: {0}", e);
        }
        catch (Exception e)
        {
            LogWriterMethod.TryWriteLog(String.Format("Unhandled Exception on OpenDatabaseOnEncryptedWayAsync method: {0}", e));
            Console.WriteLine("Unhandled Exception Message: {0}", e);
        }

        App.SettingsViewModel.isDatabaseOpen = encryptedDatabase != null;

        return encryptedDatabase;
    }

抛出(CouchbaseLite)异常的代码:

    public async Task<Database> OpenDatabaseOnEncryptedWayAsync(string encryptionPassword)
    {            
        Database encryptedDatabase = null;

        try
        {
            SymmetricKey Key;
            DatabaseOptions options = new DatabaseOptions();
            await Task.Run(() =>
            {
                Key = new SymmetricKey(encryptionPassword);
                options.EncryptionKey = Key;
                options.Create = true;
                options.StorageType = StorageEngineTypes.SQLite;
            });

            // Custom directory
            var path = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads).Path;
            var dir = Directory.CreateDirectory(path);
            Manager manager = new Manager(dir, Manager.DefaultOptions);
            encryptedDatabase = manager.GetDatabase(database);
        }
        catch (CouchbaseLiteException e)
        {
            LogWriterMethod.TryWriteLog(String.Format("Error while creating encrypted database: {0}", e)); 
            Console.WriteLine("Encryption Message: {0}", e);
        }
        catch (Exception e)
        {
            LogWriterMethod.TryWriteLog(String.Format("Unhandled Exception on OpenDatabaseOnEncryptedWayAsync method: {0}", e));
            Console.WriteLine("Unhandled Exception Message: {0}", e);
        }

        App.SettingsViewModel.isDatabaseOpen = encryptedDatabase != null;

        return encryptedDatabase;
    }

那么,有人知道如何处理这个问题吗?提前致谢:)

回到主题,我在抛出 (CouchbaseLite)Exception 的代码中发现了一个非常简单的错误。我分享它以防有人阅读这篇文章时遇到同样的错误:

我正在创建目录,然后使用新路径创建管理器,但我从未将数据库选项分配给新创建的管理器

SymmetricKey Key;
DatabaseOptions options = new DatabaseOptions();
await Task.Run(() =>
{
    Key = new SymmetricKey(encryptionPassword);
    options.EncryptionKey = Key;
    options.Create = true;
    options.StorageType = StorageEngineTypes.SQLite;
});
var path = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads).Path;
var dir = Directory.CreateDirectory(path);
Manager manager = new Manager(dir, Manager.DefaultOptions);
encryptedDatabase = manager.GetDatabase(database);

所以,我们要做的就是把代码改成read

encryptedDatabase = manager.OpenDatabase(database, options);

就是这样!