Unity的安装数据库(SQLite)

Dis*_*ame 4 c# sqlite android unity-game-engine

我看了太多教程列表,他们都推荐相同的东西.但是,他们没有帮助解决我的问题.

我试图在我的项目中包含一个SQLite数据库,当构建PC,MAC和Linux Standalone(在Windows机器上测试)时,数据库按预期工作.在Android设备上进行测试时,出现以下错误.

   E/Unity: ArgumentException: Invalid ConnectionString format for parameter "/storage/emulated/0/Android/data/com.tbltools.tbl_project/files/TBLDatabase.db"
          at Mono.Data.Sqlite.SqliteConnection.ParseConnectionString (System.String connectionString) [0x00000] in <filename unknown>:0 
          at Mono.Data.Sqlite.SqliteConnection.Open () [0x00000] in <filename unknown>:0 
          at UIHandler+<RequestAllStudentNames>c__Iterator2.MoveNext () [0x00000] in <filename unknown>:0 
          at UnityEngine.SetupCoroutine.InvokeMoveNext (IEnumerator enumerator, IntPtr returnValueAddress) [0x00000] in <filename unknown>:0 
Run Code Online (Sandbox Code Playgroud)

我认为对connectionString进行修改应该很简单,但这并没有解决我的问题.这是我到目前为止:

   if (Application.platform != RuntimePlatform.Android)
        {
            // The name of the db.
             tblDatabase = "URI=file:" + Application.dataPath + "/TBLDatabase.db"; //returns the complete path to database file exist.
        }
        else
        {
              tblDatabase = Application.persistentDataPath + "/TBLDatabase.db";

            if (!File.Exists(tblDatabase))
            {
                // if it doesn't ->
                Debug.LogWarning("File \"" + tblDatabase + "\" does not exist. Attempting to create from \"" + Application.dataPath + "!/assets/" + "TBLDatabase.db");
                // open StreamingAssets directory and load the db ->

                // #if UNITY_ANDROID
                var loadDb = new WWW("jar:file://" + Application.dataPath + "!/assets/" + "TBLDatabase.db");  // this is the path to your StreamingAssets in android
                while (!loadDb.isDone) { }  // CAREFUL here, for safety reasons you shouldn't let this while loop unattended, place a timer and error check
                                            // then save to Application.persistentDataPath
                File.WriteAllBytes(tblDatabase, loadDb.bytes);
            }
        }
        //open db connection
        var connection = new SqliteConnection(tblDatabase);
        connection.Open();
        var command = connection.CreateCommand();
Run Code Online (Sandbox Code Playgroud)

我已经使用了adb shell并从我的Android设备中提取了数据库,所有内容都符合预期(数据库确实存在并且它不是空的).

我相信我有所有相关的DLL文件,但如果有人能给我一些指导我会很感激.

***************************************************编辑**********************************************

我根据给出的建议做了以下改动.

我现在调用以下方法来启动我的连接并处理数据库请求StartCoroutine(RunDbCode(dbFileName, jsonStudentID, jsonIndiNames, jsonIndiStudentNumbers));

然后我有以下方法:

IEnumerator RunDbCode(string fileName, List jsonStudentID, List jsonIndiNames, List jsonIndiStudentNumbers)
    {
        //Where to copy the db to
        string dbDestination = Path.Combine(Application.persistentDataPath, "data");
        dbDestination = Path.Combine(dbDestination, fileName);

        //Check if the File do not exist then copy it
        if (!File.Exists(dbDestination))
        {
            //Where the db file is at
            string dbStreamingAsset = Path.Combine(Application.streamingAssetsPath, fileName);

            byte[] result;

            //Read the File from streamingAssets. Use WWW for Android
            if (dbStreamingAsset.Contains("://") || dbStreamingAsset.Contains(":///"))
            {
                WWW www = new WWW(dbStreamingAsset);
                yield return www;
                result = www.bytes;
            }
            else
            {
                result = File.ReadAllBytes(dbStreamingAsset);
            }
            Debug.Log("Loaded db file");

            //Create Directory if it does not exist
            if (!Directory.Exists(Path.GetDirectoryName(dbDestination)))
            {
                Directory.CreateDirectory(Path.GetDirectoryName(dbDestination));
            }

            //Copy the data to the persistentDataPath where the database API can freely access the file
            File.WriteAllBytes(dbDestination, result);
            Debug.Log("Copied db file");
        }

        //Now you can do the database operation
        //open db connection
        var connection = new SqliteConnection(dbDestination);
        connection.Open();
        var command = connection.CreateCommand();

        // Drop the table if it already exists.
        command.CommandText = "DROP TABLE IF EXISTS existing_individual;";
        command.ExecuteNonQuery();

        var sql = "CREATE TABLE existing_individual (studentID VARCHAR(23), fullName VARCHAR(50), studentNumber VARCHAR(20))";
        command.CommandText = sql;
        command.ExecuteNonQuery();

        //Inserting the exisiting student names returned, into the SQLite DB 

        int count = 0;

        foreach (var individuals in jsonStudentID)
        {
            //looping through the existing students registered for the individual quiz - below has been written to avoid SQL injection
            sql = "INSERT INTO existing_individual (studentID, fullName, studentNumber) VALUES (@jsonStudentID, @jsonIndiNames, @jsonIndiStudentNumbers)";
            command.Parameters.AddWithValue("@jsonStudentID", jsonStudentID[count]);
            command.Parameters.AddWithValue("@jsonIndiNames", jsonIndiNames[count]);
            command.Parameters.AddWithValue("@jsonIndiStudentNumbers", jsonIndiStudentNumbers[count]);

            command.CommandText = sql;
            command.ExecuteNonQuery();

            count++;
        }

        //close the connection
        command.Dispose();
        command = null;
        connection.Close();
        connection = null; 
    }
Run Code Online (Sandbox Code Playgroud)

但是,我仍然收到以下错误:

06-08 15:26:56.498 16300-16315/? E/Unity: ArgumentException: Invalid ConnectionString format for parameter "/storage/emulated/0/Android/data/com.tbltools.tbl_project/files/data/TBLDatabase.db"
      at Mono.Data.Sqlite.SqliteConnection.ParseConnectionString (System.String connectionString) [0x00000] in <filename unknown>:0 
      at Mono.Data.Sqlite.SqliteConnection.Open () [0x00000] in <filename unknown>:0 
      at UIHandler+<RunDbCode>c__Iterator3.MoveNext () [0x00000] in <filename unknown>:0 
      at UnityEngine.SetupCoroutine.InvokeMoveNext (IEnumerator enumerator, IntPtr returnValueAddress) [0x00000] in <filename unknown>:0 
    UnityEngine.MonoBehaviour:StartCoroutineManaged2(IEnumerator)
    UnityEngine.MonoBehaviour:StartCoroutine(IEnumerator)
    <RequestAllStudentNames>c__Iterator2:MoveNext()
    UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr)

    (Filename:  Line: -1)
06-08 15:26:56.502 16300-16315/? E/Unity: ArgumentException: Invalid ConnectionString format for parameter "URI"
      at Mono.Data.Sqlite.SqliteConnection.ParseConnectionString (System.String connectionString) [0x00000] in <filename unknown>:0 
      at Mono.Data.Sqlite.SqliteConnection.Open () [0x00000] in <filename unknown>:0 
      at UIHandler.CreateIndiButton () [0x00000] in <filename unknown>:0 
      at UIHandler+<RequestAllStudentNames>c__Iterator2.MoveNext () [0x00000] in <filename unknown>:0 
      at UnityEngine.SetupCoroutine.InvokeMoveNext (IEnumerator enumerator, IntPtr returnValueAddress) [0x00000] in <filename unknown>:0 
Run Code Online (Sandbox Code Playgroud)

我还将我的数据库添加到'StreamingAssets'文件夹中,如下图所示:

在此输入图像描述

下面还显示了我的插件文件夹的图像,其中包含我的dll文件.

在此输入图像描述

Pro*_*mer 9

关于此主题的大多数教程都已过时.

看了一下代码,发现了一些问题,但我不知道这些是你收到这个错误的原因.WWW应该在coroutine函数中使用,以便loadDb.isDone通过yield return nullwhile循环内添加可以产生或等待完成.你也可以WWW自己产生请求,这就是我将在答案中使用的方法.

此外,jar:file://" + Application.dataPath是一个旧代码.使用Application.streamingAssetsPath了点.此外,你不需要"URI=file:" + Application.dataPath.只是用 Application.persistentDataPath它.

我将简单介绍一下如何进行设置.

设置MANAGED代码部分:

1.转到Unity安装路径

<UnityInstallationDirecory>\Editor\Data\Mono\lib\mono\2.0
Run Code Online (Sandbox Code Playgroud)

复制以下文件:

  • I18N.MidEast.dll
  • I18N.Other.dll
  • I18N.Rare.dll
  • I18N.West.dll
  • Mono.Data.Sqlite.dll
  • Mono.Data.SqliteClient.dll
  • System.Data.dll

到项目的<ProjectName>\Assets\Plugins路径.

这将允许您从Mono.Data.Sqlite命名空间编译API 而不会出现任何错误.


设置UNMANAGED代码部分:

在此步骤中,您将需要获取本机Sqlite库.您可以获取源代码,构建它并使用它或使用已经预编译的binray.

1.获取Windows的本机库

sqlite3.dll此处下载预编译的Windows 64位,并将其放在<ProjectName>\Assets\Plugins\x86_64路径中.

如果使用Windows 32位,sqlite3.dll则从此处获取版本并将其放入<ProjectName>\Assets\Plugins\x86路径中.


2.获取Android的本机库

此处下载预编译libsqlite3.soAndroid ARM处理器并将其放入路径中.<ProjectName>\Assets\Plugins\Android\libs\armeabi-v7a

这里下载预编译libsqlite3.soAndroid Intel x86处理器并将其放入路径中.<ProjectName>\Assets\Plugins\Android\libs\x86

这涵盖了Android设备上使用的大多数处理器.


3.获取UWP的本机库

A.下载WSA文件夹,然后将WSA文件夹放在<ProjectName>\Assets\Plugins路径中.该文件夹包含本机部分.

B.在路径中创建名为"mcs.rsp""csc.rsp"的 2个文件 <ProjectName>\Assets.

C."mcs.rsp""csc.rsp"文件中添加以下内容:

-r:I18N.MidEast.dll

-r:I18N.Other.dll

-r:I18N.Rare.dll

-r:I18N.West.dll

-r:Mono.Data.Sqlite.dll

-r:Mono.Data.SqliteClient.dll

-r:System.Data.dll
Run Code Online (Sandbox Code Playgroud)

D.在构建UWP时,您必须将托管dll移动到项目的文件夹.所以,移动I18N.MidEast.dll,I18N.Other.dll,I18N.Rare.dll,I18N.West.dll,Mono.Data.Sqlite.dll,Mono.Data.SqliteClient.dll,System.Data.dll<ProjectName>道路 <ProjectName>\Assets\Plugins路径.


4.对于iOS,Linux和Mac,看起来您不必为他们下载任何其他内容或执行此步骤.它们通常内置了本机预编译的Sqlite库.


在Build中包含Database文件:

1.在文件夹中创建一个文件<ProjectName>\Assets夹,并将其命名为StreamingAssets.拼写很重要,而且区分大小写.

2.TBLDatabase.db在此StreamingAssets文件夹中输入数据库文件().


在构建项目后访问数据库文件

Sqlite无法处理构建中StreamingAssets文件夹中的文件,因为这是一个只读路径.此外,Android要求您使用WWWAPI而不是标准System.IOAPI从StreamingAssets文件夹中读取.您必须将db文件从中复制Application.streamingAssetsPath/filename.dbApplication.persistentDataPath/filename.db.

在某些平台上,您需要在其中创建一个文件夹Application.persistentDataPath并将数据保存到该文件夹​​.总是这样做.下面的示例代码中的文件夹是"数据",因此将成为Application.persistentDataPath/data/filename.db.

3.由于上面的陈述,检查数据库文件是否存在于 Application.persistentDataPath/data/filename.db.如果是,请将其Application.persistentDataPath/data/filename.db用作数据库操作的路径.如果没有,继续#4.

4.StreamingAssets文件夹中读取并复制数据库文件Application.persistentDataPath

在某些平台上,您需要在其中创建一个文件夹Application.persistentDataPath并将数据保存到该文件夹​​.总是这样做.以下示例中的文件夹是"data".

检测这是否是Android并使用WWW从中读取的文件Application.streamingAssetsPath/filename.db.用于File.ReadAllBytes在Android以外的任何其他内容上阅读.在您的示例中,您使用Application.platform了它.在我的示例中,我将简单地检查路径是否包含"://":///执行此操作.

5.一旦你读文件,写你刚才读的数据Application.persistentDataPath/data/filename.dbFile.WriteAllBytes.现在,您可以使用此路径进行数据库操作.

6 .PREFIX "URI=file:"Application.persistentDataPath/data/filename.db路径,这就是对的路径应该在你的数据库操作与SQLite的API一起使用.


理解所有这些是非常重要的,以便在出现变化时修复它,但我已经完成了下面的步骤#3#6.

IEnumerator RunDbCode(string fileName)
{
    //Where to copy the db to
    string dbDestination = Path.Combine(Application.persistentDataPath, "data");
    dbDestination = Path.Combine(dbDestination, fileName);

    //Check if the File do not exist then copy it
    if (!File.Exists(dbDestination))
    {
        //Where the db file is at
        string dbStreamingAsset = Path.Combine(Application.streamingAssetsPath, fileName);

        byte[] result;

        //Read the File from streamingAssets. Use WWW for Android
        if (dbStreamingAsset.Contains("://") || dbStreamingAsset.Contains(":///"))
        {
            WWW www = new WWW(dbStreamingAsset);
            yield return www;
            result = www.bytes;
        }
        else
        {
            result = File.ReadAllBytes(dbStreamingAsset);
        }
        Debug.Log("Loaded db file");

        //Create Directory if it does not exist
        if (!Directory.Exists(Path.GetDirectoryName(dbDestination)))
        {
            Directory.CreateDirectory(Path.GetDirectoryName(dbDestination));
        }

        //Copy the data to the persistentDataPath where the database API can freely access the file
        File.WriteAllBytes(dbDestination, result);
        Debug.Log("Copied db file");
    }

    try
    {
        //Tell the db final location for debugging
        Debug.Log("DB Path: " + dbDestination.Replace("/", "\\"));
        //Add "URI=file:" to the front of the url beore using it with the Sqlite API
        dbDestination = "URI=file:" + dbDestination;

        //Now you can do the database operation below
        //open db connection
        var connection = new SqliteConnection(dbDestination);
        connection.Open();

        var command = connection.CreateCommand();
        Debug.Log("Success!");
    }
    catch (Exception e)
    {
        Debug.Log("Failed: " + e.Message);
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

string dbFileName = "TBLDatabase.db";

void Start()
{
    StartCoroutine(RunDbCode(dbFileName));
}
Run Code Online (Sandbox Code Playgroud)