Qt Creator: include additional files inside Android apk

Developing an app for Android frequently require to include some additional files containing custom data used by the app itself (in majority of cases sqlite database files). Android provide a standard way by using a special folder called assets where these kind of files need to be stored. Qt Creator provide a instructions to use for copy these files during apk creation.



Full project example here

Basically you have to instruct qmake tool used by Qt Creator to copy specific files inside assets folder during compilation phase. What you have to do is to add the following instruction inside the Qt Creator project file .pro:

android
{
my_files.path = /assets
my_files.files = $$PWD/myfolder/*
INSTALLS += my_files
}

path is the path where the files will be copied. In case of Android this have to be assets folder but you can add subfolders if you need it. files is the list of files to copy. In the example $$PWD is the root where .pro file is located and using asterisk at the end mean copy entire subfolder structure (files and subfolders). In case you need to specify a list of files located in different paths you can add manually as follow:

my_files.files += $$PWD/path_to_file1/file1
my_files.files += $$PWD/path_to_file2/file2
my_files.files += $$PWD/path_to_file3/file3
...
...

Once finished compilation you can verify if your files has been added correctly by open the apk file using some archive tool like the free 7-zip software (apk is basically a compressed file containing all required data used by Android). Now you need a way to access these files by code. Qt have a special way to access assets folder as explained in official documentation below:

Qt for Android provides a special, virtual file system which is based on the assets mechanism in Android. Files that are put under assets in the android folder created by Qt Creator, will be packaged as part of your application package. These can be accessed in Qt by prefixing the paths with assets:/. For instance, to access the image logo.png in the folder assets/images, you can use QPixmap("assets:/images/logo.png").

Please note, in case you plan to use assets folder for store sqlite database files you have to know that, unfortunately, you can not use these database directly from assets folder itself. The reason is assets folder is read only but sqlite engine require read/write access also if you plan to use your database file only for read data without any write. In this case you have to copy these files in the app data writable folder as showed in the example below:

QFile DbFile;
QString DatabaseDataStoragePath = QStandardPaths::writableLocation(QStandardPaths::StandardLocation::AppDataLocation);
DbFile.setFileName("assets:/MyDatabase.sqlite");
DbFile.copy(DatabaseDataStoragePath + "/MyDatabase.sqlite")
QFile::setPermissions(DatabaseDataStoragePath + "/MyDatabase.sqlite", QFile::WriteOwner | QFile::ReadOwner);

Once done you can use the database from data folder you just copied to. Be carefully since this "problem" of assets folder have significant consequence to the space occupied by your app cause the space of database files is duplicated as consequence of copy operation (Android calculate app space by sum apk content size of app data folder size).

Comments

  1. nice article ... with an obvious question ... where is defined the name "my_files" in pro ?
    the compiler is giving me this error: -1: error: [install_my_files] Error 3 (ignored)

    ReplyDelete
    Replies
    1. my_files is defined in the same time you declared my_files.path and my_files.files as in the first snippet. Are you sure you used the correct syntax inisde the pro file?

      Delete
    2. thank you ... seems the error insist ... i have not any clue ... without the assets file the project is working right ... i could send you the pro file in case you want in your email

      Delete
    3. Create a project example on the fly. I added the link to the project at the begining of the post. Please try to test this working example for check if work on your environment.

      Delete
    4. configuration Qt5.10.1 on tablet Android API25 V7.1

      Yes the test project is working as expected ... thank you
      digging deeper i came to the following conclusion:

      The assets file system is not compatible (as expected) to the rest android file system.

      The result of my tests: (maybe there are even more issues)
      ----------------------------------------------------
      "assets:/logo.png" ok
      "assets:/logo.PNG" error (case sensitive)

      "assets:/set_tings.ini" error (not acceptable underscore char)
      "assets:/settings.ini" ok

      FILE *file; error (C object opens nothing)
      QFile file("assets:/settings.ini"); ok

      ifnt = QFontDatabase::addApplicationFont("assets:/main.ttf"); error (returns -1)

      db = QSqlDatabase::addDatabase("QSQLITE", "db");
      db.setDatabaseName("assets:/airnavigation.db"); error (doesn't open the database)
      ----------------------------------------------------

      1) The above 'errors' are not compile errors, means doesn't work with the "assets:/" path file.
      2) Under the "/sdcard/" path, all are working as expected .
      3) Reading the relative documentations in Internet there are no such references, notices etc, i think would be good this information and results to be included here in this article.

      Unfortunately for my own project the mission seems to be impossible,
      speaking for an "air navigation system" with a hundred of external files wanting to include all of them in one apk file, will be a painful story,
      not mentioning the 50 MB limit of "Google Play Store", so i have not idea how to publish easily for customers this free appl. If you have a good idea how to handle the 1GB needed external files, am here to listen.

      again many thanks
      Artemis

      Delete
    5. From what I remeber Google increase the apk file size limit but surely not to 1GB. The reasons qslite database file doesn't work by opening directly from assets virtual file system is explained in the post (basically because assets is a read only file system). The only solution you have is to use some online storage service from where download all required files at first initialization. This is the way followed by all major navigator app for download maps as you surely know. However, cause the large amount of byte do download, I don't think it will be possible to find some free service. I guess you'll have to pay for it...

      Delete
    6. I recommend the next article to be Qt for Android and "Google Play Store APK Expansion Files 2GB" :) ... if you search this topic there is almost nothing, just scattered information, no clear guides, and would be really helpful.
      https://developer.android.com/google/play/expansion-files.html

      Delete
    7. If you still are interested in this solution I just released a library allowing to manage apk expansion files in an easier way. You can find the library here:

      https://github.com/FalsinSoft/QtAndroidTools

      Delete
  2. This seems to be a good solution, however, my files don't get into the APK. I tried to place the files in another folder and they were there. Something about androiddeployqt.exe is deleting the folder first and then I lose my files.

    ReplyDelete
    Replies
    1. I tried this again, by first deleting all contents of my build folder. I did the above fix to the pro file and this time I used a different folder name, instead of assets. I know that androiddeployqt.exe will remove that folder every time. It hurled the first time, deleted build contents and voila my new folder and files are in the build area. But it doesn't seem to place my folders in the assets folder nor does it get into the APK file. I tried to incorporate a build step to move the files to the assets folder, but once again androiddeployqt.exe removed the files. So I tried to do the copy after the androiddeployqt.exe step and then call androiddeployqt.exe again. Still no files in assets folder. I had to make a change to build.gradle by adding my "new folder" into the assets.srcDirs variable. Sorry for the long comment but I wanted others to know that aside from the above mentioned fix, you also need to tweek the gradle file too.

      Delete
    2. Hi, sorry for delay in reply but didn't node the new comment. It seem very strange about all these problems. have you tried the example linked on top of the post as base to start from for your tests?

      Delete
    3. I did use your example. It is working now based on fixing the gradle file.

      Delete
  3. If you a have question like that how to build an app? Then you should know that there are some popular names like Weebly, Wix, and Squarespace which let you create a website with just a drag-and-drop option. While using sites like Woocommerce and Shopify, you can easily develop a web store in no time.

    ReplyDelete

Post a Comment

Popular posts from this blog

Access GPIO from Linux user space

Android: adb push and read-only file system error

Tree in SQL database: The Nested Set Model