我看了太多教程列表,他们都推荐相同的东西。但是,他们没有帮助解决我的问题。
我正在尝试在我的项目中包含一个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
我认为对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 <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
我还将我的数据库添加到了&#39; StreamingAssets&#39;文件夹如下图所示:
下面还显示了我的插件文件夹的图片,其中包含我的dll文件。
答案 0 :(得分:7)
关于此主题的大多数教程都已过时。
查看代码并发现一些问题,但我无法判断这些是否是您收到此错误的原因。 {/ 1}}应该在coroutine函数中使用,以便通过在WWW
循环中添加loadDb.isDone
来完成或等待yield return null
完成。您也可以自己提出while
请求以及我将在答案中使用的方法。
此外,WWW
是旧代码。请使用jar:file://" + Application.dataPath
。此外,您不需要Application.streamingAssetsPath
。只需使用"URI=file:" + Application.dataPath
即可。
我将简单介绍一下如何进行设置。
设置MANAGED代码部分:
1 。转到Unity安装路径
Application.persistentDataPath
复制以下文件:
<UnityInstallationDirecory>\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
路径。
这将允许您从<ProjectName>\Assets\Plugins
命名空间编译API而不会出现任何错误。
设置UNMANAGED代码部分:
在此步骤中,您需要获取本机Sqlite库。您可以获取source code,构建它并使用它或使用已预编译的binray。
1 。获取 Windows 的本地库
从here下载适用于Windows 64位的预编译Mono.Data.Sqlite
,并将其放在sqlite3.dll
路径中。
如果使用Windows 32位,则从here获取<ProjectName>\Assets\Plugins\x86_64
版本并将其放在sqlite3.dll
路径中。
2 。获取 Android 的原生图书馆
从中下载 Android ARM处理器的预编译<ProjectName>\Assets\Plugins\x86
here并将其放在libsqlite3.so
路径中。
从中下载 Android Intel x86处理器的预编译<ProjectName>\Assets\Plugins\Android\libs\armeabi-v7a
here并将其放在libsqlite3.so
路径中。
这涵盖Android设备上使用的大多数processors。
3 。获取 UWP的本地库
A 。下载WSA文件夹,然后将WSA文件夹放在<ProjectName>\Assets\Plugins\Android\libs\x86
路径中。该文件夹包含本机部分。
B 。创建名为&#34; mcs.rsp&#34; 和&#34; csc.rsp&#34; 在<ProjectName>\Assets\Plugins
路径中。
C 。在&#34; mcs.rsp&#34; 和&#34; csc.rsp&#34; 中添加以下内容em>文件:
<ProjectName>\Assets
D 。在构建UWP时,您必须将托管dll移动到项目的 root 文件夹。因此,将-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
,I18N.MidEast.dll
,I18N.Other.dll
,I18N.Rare.dll
,I18N.West.dll
,Mono.Data.Sqlite.dll
,Mono.Data.SqliteClient.dll
移至System.Data.dll
路径不 <ProjectName>
路径。
4 。对于iOS,Linux和Mac,看起来您不必为他们下载任何其他内容或执行此步骤。它们通常内置了本机预编译的Sqlite库。
在Build中包含数据库文件:
1 。在<ProjectName>\Assets\Plugins
文件夹中创建一个文件夹,并将其命名为 StreamingAssets 。拼写很重要且它区分大小写。
2 。在此 StreamingAssets 文件夹中输入数据库文件(<ProjectName>\Assets
)。
在构建项目后访问数据库文件
Sqlite无法处理构建中 StreamingAssets 文件夹中的文件,因为它是一个只读路径。此外,Android要求您使用TBLDatabase.db
API而不是标准WWW
API从 StreamingAssets 文件夹中读取。您必须将db文件从System.IO
复制到Application.streamingAssetsPath/filename.db
。
在某些平台上,您需要在Application.persistentDataPath/filename.db
中创建一个文件夹,然后将数据保存到该文件夹。总是这样做。以下示例代码中的文件夹是&#34; data&#34;这将成为Application.persistentDataPath
。
3 。由于上述说法,请检查数据库文件是否存在
Application.persistentDataPath/data/filename.db
。如果是,请使用Application.persistentDataPath/data/filename.db
作为数据库操作的路径。如果没有,请从#4继续。
4 。将数据库文件从 StreamingAssets 文件夹中复制并复制到Application.persistentDataPath/data/filename.db
在某些平台上,您需要在Application.persistentDataPath
中创建一个文件夹,然后将数据保存到该文件夹。总是这样做。以下示例中的文件夹是&#34;数据&#34;。
检测这是否为Android并使用Application.persistentDataPath
从WWW
读取文件。使用Application.streamingAssetsPath/filename.db
在Android以外的任何其他内容上阅读。在您的示例中,您使用了File.ReadAllBytes
。在我的示例中,我只是检查路径是否包含Application.platform
或"://"
来执行此操作。
5 。一旦您阅读该文件,请将您刚刚阅读的数据写入:///
Application.persistentDataPath/data/filename.db
。现在,您可以使用此路径进行数据库操作。
6 .Prefix File.WriteAllBytes
到"URI=file:"
路径,并且应该在使用Sqlite API的数据库操作中使用该路径。
了解所有这些是非常重要的,以便在某些事情发生变化时修复它但我已经完成了步骤#3 到#6 下面。
Application.persistentDataPath/data/filename.db
<强>用法强>:
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);
}
}