0

I am stuck at running unity3D android build in android device, it runs in editor but when I create an android build and try to run in my android device, I get errors in logcat like: no such file or directory and No such table when I try to access database through code, when checked my android file explorer I found database size is zero, which shouldn't be I guess. I have kept database in StreamingAssets folder, which is not empty. This is my C# code to setup db:

#if !UNITY_EDITOR
        var filepath = string.Format("{0}/{1}", Application.persistentDataPath, DatabaseName);
        if (!File.Exists(filepath))
        {
            Utils.Log(LogType.Debug, "Database does not exist");
            string DatabaseName = Constants.Settings.dbName;

#if UNITY_ANDROID
        // open StreamingAssets directory and load the db ->
        var filepath = string.Format("{0}/{1}", Application.persistentDataPath, DatabaseName);
        var loadDb = new WWW("jar:file://" + Application.dataPath + "!/assets/" + DatabaseName);
        while (!loadDb.isDone) { }
        File.WriteAllBytes(filepath, loadDb.bytes);
#endif
        }

Even I cannot see above log in logcat "Database does not exist", seems it never comes inside if block, but how come file already been existed in device's persistentDataPath.

Ashok Damani
  • 3,896
  • 4
  • 30
  • 48
  • Look at https://answers.unity.com/questions/1340555/problem-with-android-sqlite-in-apk-dont-run-in-and.html – Oleg Oct 12 '19 at 19:00
  • I already went through this link, that answer is about getting the database in place, his issue was he was not able to see the database itself, but in my case database is there but its empty, but in my streamingAssets folder db is not empty – Ashok Damani Oct 12 '19 at 19:03
  • May be loop while (!loadDb.isDone) { } is not waiting as you expected and write to file before load, as result is empty. – Oleg Oct 12 '19 at 19:10
  • but this is the only to hold on it, until it gets loaded, everybody does same way. – Ashok Damani Oct 12 '19 at 19:14
  • Can you log loadDb.bytes – Oleg Oct 12 '19 at 19:17

1 Answers1

1

I believe that your issue is that at some time when you ran the file didn't exist due to no such file or directory (may have been a cannot open ENOENT). This happens because the databases folder/directory doesn't exist and the file copy fails.

That is on Android databases are stored at data/data/the_package_name/databases/the_database_filename

When an App is created only the directory at data/data/the_package_name exists. The databases folder does not.

If an attempt is made to open/access the database, then the databases folder is created (the SDK/API does this) and a database will be opened BUT it's empty bar the sqlite_master table and android_metadata and hence the no such table.

From that point on you will continue to get the no such table as the database exists and is stored on disk but it hasn't been copied.

The fix is to

a) amend the code so that inside the if block, a check is made to see if the parent file (the databases directory exists) and if not to use the File's mkdirs method before the copy.

b) to either uninstall the App or b) to clear the App's data.

  • This is to delete the useless database that is preventing the actual database from being copied.

c) rerun.

However, considering comments and that Application.persistentDataPath returns /storage/emulated/0/Android/data/com.mygame.cars/files/db_original.d then instead of the databases folder it is the File folder that probably doesn't originally exist. So the above should be adjusted to suit the Files folder.

Another, issue may be that autobackup is turned on which can restore App data.

It's due to an auto-backup feature since Android 6.0. All your app data is automatically backed up to your linked Google account. You can find the back up in your Google Drive. By default the backed up data will be restored upon reinstall. Saved Android app files get automatically recovered from nowhere even after re-installing app.

You should turn of autobackup as per the link, uninstall and retry checking to see if the Files directory exists and if not creating the directory using mkdirs.

MikeT
  • 51,415
  • 16
  • 49
  • 68
  • I just logged filepath, which is `/storage/emulated/0/Android/data/com.mygame.cars/files/db_original.db` So you mean, I need to check `files` folder inside `com.mygame.cars`? I have tried uninstalling app and newly installing it but it didnt work anyway. – Ashok Damani Oct 12 '19 at 21:11
  • @AshokDamani that's not typically where database on android are store. Had a quick look and it appears you can't user the SDK/API built in. So you open and use a packaged dll. I think the issue is similar, basically nothing copied so you've opened an empty database, which then restricts the copy. You need to delete `/storage/emulated/0/Android/data/com.mygame.cars/files/db_original.db` and try again BUT this time look at and fix the `no such file or directory` (perhaps after the copy check the file size should be as large as copied file and at least 8k). Don't know unity or c# so limited. – MikeT Oct 12 '19 at 21:36
  • actually I just uninstalled app and verified `com.mygame.cars` was automatically deleled and newly installed app and debugged and found that `if (!File.Exists(filepath))` is still returns false on the first time execution as well i.e. when installing the app itself android copies db to corresponding folder before user opens the app thus condition never met and it never goes into if block. – Ashok Damani Oct 12 '19 at 21:42
  • Currently I am trying below code, lets see if its works: `if (!File.Exists (filepath) || (File.GetLastWriteTimeUtc(sourcePath) > File.GetLastWriteTimeUtc(filepath))) { // copy db.........` – Ashok Damani Oct 12 '19 at 21:44
  • @AshokDamani do you have autobackup=true (not sure how you'd do that via Unity you do it via Manifest in Android Studio), this might be recovering the database. Perhaps rather than checking time, check size size should be at least 4k per table. So if you have 1 table you expect size to be at least 8k (this assumes default 4k pages). That is if size < expected then assume copy needs to be done. Also log the size of the loadDB before the write. – MikeT Oct 12 '19 at 21:49
  • [Saved Android app files get automatically recovered from nowhere even after re-installing app.](https://answers.unity.com/questions/1341215/saved-android-app-files-get-automatically-recovere.html) might help re autobackup. – MikeT Oct 12 '19 at 21:52
  • I have put `autoBackup=false` also checking `size < 500` (bytes), lets see if it works. even if it works the question will remain unanswered that, is empty db coming from some backup (since once more I've removed and installed the app, still empty db is appeared, if its coming from backup, I dont know how since wifi/data is off) – Ashok Damani Oct 12 '19 at 22:32
  • or it is getting created by android while first time opening the app but before our code executes since it wasnt going into above if block, but db wasnt getting created without first time opening the app, means its getting created somewhere in middle b/w installing and opening app for the first time. – Ashok Damani Oct 12 '19 at 22:32
  • 500 bytes may be too small. If the file is opened via SQLite then it will create the sqlite_master table and be at least 4k in size. – MikeT Oct 13 '19 at 00:21
  • Well, I just gave a thought to keep the condition for minimum db size with atleaast one table created for game, so I created a test db with one empty table (15 columns) and size db size happened to be 16kb, so I changed the condition to `<16*1000` Do you have any thoughts on this?. – Ashok Damani Oct 13 '19 at 10:44