Unity的安装数据库(SQLite)

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

我试图在我的项目中包含一个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 :0 at Mono.Data.Sqlite.SqliteConnection.Open () [0x00000] in :0 at UIHandler+c__Iterator2.MoveNext () [0x00000] in :0 at UnityEngine.SetupCoroutine.InvokeMoveNext (IEnumerator enumerator, IntPtr returnValueAddress) [0x00000] in :0 

我认为对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(); 

我已经使用了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; } 

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

 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 :0 at Mono.Data.Sqlite.SqliteConnection.Open () [0x00000] in :0 at UIHandler+c__Iterator3.MoveNext () [0x00000] in :0 at UnityEngine.SetupCoroutine.InvokeMoveNext (IEnumerator enumerator, IntPtr returnValueAddress) [0x00000] in :0 UnityEngine.MonoBehaviour:StartCoroutineManaged2(IEnumerator) UnityEngine.MonoBehaviour:StartCoroutine(IEnumerator) 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 :0 at Mono.Data.Sqlite.SqliteConnection.Open () [0x00000] in :0 at UIHandler.CreateIndiButton () [0x00000] in :0 at UIHandler+c__Iterator2.MoveNext () [0x00000] in :0 at UnityEngine.SetupCoroutine.InvokeMoveNext (IEnumerator enumerator, IntPtr returnValueAddress) [0x00000] in :0 

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

在此处输入图像描述

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

在此处输入图像描述

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

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

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

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

设置MANAGED代码部分:

1.转到Unity安装路径

 \Editor\Data\Mono\lib\mono\2.0 

复制以下文件:

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

到项目的\Assets\Plugins路径。

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


设置UNMANAGED代码部分:

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

1.获取Windows的本机库

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

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


2.获取Android的本机库

从此处下载Android ARM处理器的预编译libsqlite3.so ,并将其放在\Assets\Plugins\Android\libs\armeabi-v7a路径中。

从此处下载libsqlite3.soAndroid Intel x86处理器的预编译libsqlite3.so ,并将其放在\Assets\Plugins\Android\libs\x86路径中。

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


3.获取UWP的本机库

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

B.\Assets路径中创建名为“mcs.rsp”“csc.rsp”的 2个文件。

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 

D.在构建UWP时,您必须将托管dll移动到项目的文件夹。 所以,将I18N.MidEast.dllI18N.Other.dllI18N.Rare.dllI18N.West.dllMono.Data.Sqlite.dllMono.Data.SqliteClient.dllSystem.Data.dll路径不是 \Assets\Plugins路径。


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


在Build中包含Database文件:

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

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


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

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

在某些平台上,您需要在Application.persistentDataPath创建一个文件夹,并将数据保存到该文件夹​​。 总是这样做。 下面示例代码中的文件夹是“data”,因此将成为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并使用WWWApplication.streamingAssetsPath/filename.db读取该文件。 使用File.ReadAllBytes在除Android之外的任何其他内容上读取它。 在您的示例中,您使用了Application.platform 。 在我的示例中,我将简单地检查路径是否包含"://":///来执行此操作。

5.一旦读取文件,使用File.WriteAllBytes将刚刚读取的数据写入Application.persistentDataPath/data/filename.db 。 现在,您可以使用此路径进行数据库操作。

6."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); } } 

用法

 string dbFileName = "TBLDatabase.db"; void Start() { StartCoroutine(RunDbCode(dbFileName)); }