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文件.
关于此主题的大多数教程都已过时.
看了一下代码,发现了一些问题,但我不知道这些是你收到这个错误的原因.WWW
应该在coroutine函数中使用,以便loadDb.isDone
通过yield return null
在while
循环内添加可以产生或等待完成.你也可以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.so
的Android ARM处理器并将其放入路径中.<ProjectName>\Assets\Plugins\Android\libs\armeabi-v7a
从
这里下载预编译libsqlite3.so
的Android 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要求您使用WWW
API而不是标准System.IO
API从StreamingAssets文件夹中读取.您必须将db文件从中复制Application.streamingAssetsPath/filename.db
到Application.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.db
用File.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)
归档时间: |
|
查看次数: |
2890 次 |
最近记录: |