c# android sqlite unity3d

c# - Base de datos de configuración(SQLite) para Unity



android unity3d (1)

La mayoría de los tutoriales sobre este tema están desactualizados.

Miré el código y encontré algunos problemas, pero no puedo decir si esa es la razón por la que está recibiendo este error. WWW debe utilizar en una función de rutina para que pueda ceder o esperar a que loadDb.isDone se complete agregando un yield return null dentro del bucle while. También puede entregar la solicitud WWW sí misma y ese es el método que usaré en mi respuesta.

Además, jar:file://" + Application.dataPath es un código antiguo. Use Application.streamingAssetsPath para eso. Además, no necesita "URI=file:" + Application.dataPath . Simplemente use Application.persistentDataPath para eso .

Acabo de poner una instrucción sobre cómo hacer la configuración.

Configuración de la parte del código GESTIONADO:

1. Vaya a la ruta de instalación de Unity

<UnityInstallationDirecory>/Editor/Data/Mono/lib/mono/2.0

Copia los siguientes archivos:

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

a la ruta <ProjectName>/Assets/Plugins .

Esto le permitirá compilar la API desde el espacio de nombres Mono.Data.Sqlite sin ningún error.

Configuración de la parte del código UNMANAGED:

En este paso, deberá obtener la biblioteca nativa de Sqlite. Puede obtener el código fuente , compilarlo y usarlo o usar un binray ya compilado previamente.

1. Obtener la biblioteca nativa para Windows

Descargue el sqlite3.dll precompilado para Windows 64 bit desde here , y póngalo en la ruta <ProjectName>/Assets/Plugins/x86_64 .

Si usa Windows de 32 bits, obtenga la versión sqlite3.dll desde here y póngala en la ruta <ProjectName>/Assets/Plugins/x86 .

2. Obtenga la biblioteca nativa para Android

Descargue el procesador libsqlite3.so precompilado para Android ARM desde here y <ProjectName>/Assets/Plugins/Android/libs/armeabi-v7a ruta <ProjectName>/Assets/Plugins/Android/libs/armeabi-v7a .

Descargue el libsqlite3.so precompilado para el procesador Intel x86 de Android desde here y libsqlite3.so en la libsqlite3.so <ProjectName>/Assets/Plugins/Android/libs/x86 .

Esto cubre la mayoría de los processors utilizados en dispositivos Android.

3. Obtener la biblioteca nativa para UWP

A .Descargue la carpeta WSA y luego coloque la carpeta WSA en la ruta <ProjectName>/Assets/Plugins . Esa carpeta contiene la parte nativa.

B .Create 2 archivos llamados "mcs.rsp" y "csc.rsp" en la ruta <ProjectName>/Assets .

C. Agregue lo siguiente dentro de los archivos "mcs.rsp" y "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. Deberá mover las dll administradas a la carpeta raíz del proyecto cuando cree para UWP. Entonces, mueva I18N.MidEast.dll , I18N.Other.dll , I18N.Rare.dll , I18N.West.dll , Mono.Data.Sqlite.dll , Mono.Data.SqliteClient.dll , System.Data.dll al <ProjectName> ruta <ProjectName> no <ProjectName>/Assets/Plugins ruta.

4. Para iOS, Linux y Mac, parece que no tiene que descargar nada más para ellos ni hacer este paso. Por lo general, tienen las bibliotecas nativas de Sqlite precompiladas incorporadas.

Incluyendo el archivo de base de datos en la compilación:

1 .Cree una carpeta en su carpeta <ProjectName>/Assets y asígnele el nombre StreamingAssets . La ortografía cuenta y distingue entre mayúsculas y minúsculas.

2 .Ponga el archivo de base de datos ( TBLDatabase.db ) en esta carpeta StreamingAssets .

Accediendo al archivo de base de datos después de construir el proyecto

Sqlite no puede trabajar en archivos en la carpeta StreamingAssets en una compilación ya que es una ruta de solo lectura. Además, Android requiere que uses la WWW API en lugar de la API estándar de System.IO para leer desde la carpeta StreamingAssets . Debe copiar el archivo db de Application.streamingAssetsPath/filename.db a Application.persistentDataPath/filename.db .

En algunas plataformas, se requiere que cree una carpeta dentro de Application.persistentDataPath y guarde los datos en esa carpeta. Siempre hacer eso La carpeta en el código de ejemplo a continuación es "datos", por lo que se convertirá en Application.persistentDataPath/data/filename.db .

3. Debido a la declaración anterior, verifique si el archivo de base de datos existe en Application.persistentDataPath/data/filename.db . Si lo hace, use Application.persistentDataPath/data/filename.db como una ruta para la operación de su base de datos. Si no es así, continúe desde el # 4.

4 .Lea y copie el archivo de base de datos de la carpeta StreamingAssets a Application.persistentDataPath

En algunas plataformas, se requiere que cree una carpeta dentro de Application.persistentDataPath y guarde los datos en esa carpeta. Siempre hacer eso La carpeta en el ejemplo de abajo es "datos".

Detecte si se trata de Android y use la lectura WWW en el archivo de Application.streamingAssetsPath/filename.db . Use File.ReadAllBytes para leerlo en otra cosa que no sea Android. En tu ejemplo, usaste Application.platform para eso. En mi ejemplo, simplemente verificaré si la ruta contiene "://" o :/// para hacer eso.

5. Una vez que lea el archivo, escriba los datos que acaba de leer en Application.persistentDataPath/data/filename.db con File.WriteAllBytes . Ahora, puede utilizar esta ruta para la operación de su base de datos.

6 .Prefix "URI=file:" a la ruta Application.persistentDataPath/data/filename.db y esa es la ruta que debe usarse en la operación de su base de datos con la API de Sqlite.

Es muy importante que entiendas todo esto para solucionarlo cuando algo cambie, pero ya he hecho los pasos 3 a 6 a continuación.

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); } }

Uso

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

He visto demasiados tutoriales para enumerar y todos recomiendan lo mismo. Sin embargo, no han ayudado a resolver mi problema.

Estoy tratando de incluir en mi proyecto una base de datos SQLite, y al compilar para PC, MAC y Linux Standalone (pruebas en una máquina con Windows), la base de datos funciona como se esperaba. Al realizar pruebas en un dispositivo Android, obtengo los siguientes errores.

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

Pensé que hacer una enmienda a la cadena de conexión debería ser lo suficientemente simple, pero eso no ha resuelto mi problema. Esto es lo que tengo hasta ahora:

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();

He usado adb shell y extraje la base de datos de mi dispositivo Android y todo es como se esperaba (la base de datos existe y no está vacía).

Creo que tengo todos los archivos dll relevantes, pero si alguien me pudiera dar alguna orientación, lo apreciaría.

*************************************************** *EDITAR**********************************************

Desde entonces he hecho las siguientes modificaciones basadas en el consejo dado.

Ahora estoy llamando al siguiente método para iniciar mi conexión y manejar solicitudes de StartCoroutine(RunDbCode(dbFileName, jsonStudentID, jsonIndiNames, jsonIndiStudentNumbers)); datos StartCoroutine(RunDbCode(dbFileName, jsonStudentID, jsonIndiNames, jsonIndiStudentNumbers));

Entonces tengo el siguiente método:

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; }

Sin embargo, todavía estoy recibiendo los siguientes errores:

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

También agregué mi base de datos a la carpeta ''StreamingAssets'' como se muestra en la siguiente imagen:

A continuación también se muestra una imagen de la carpeta de mis complementos que contiene mis archivos dll.