Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Mobile and Embedded
  4. How to set Local Storage path for Android for Sqlite

How to set Local Storage path for Android for Sqlite

Scheduled Pinned Locked Moved Solved Mobile and Embedded
14 Posts 2 Posters 4.7k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • E Offline
    E Offline
    edip
    wrote on 25 Mar 2019, 21:25 last edited by edip
    #3

    @Tom_H I have an existing sqlite database in asset folder of Android. In project path it looks like this:

    android
    |
     assets
     └── qml
        └── OfflineStorage
            └── Databases
                ├── e04d88072f90f86a07481418b8ff4b6b.ini
                └── e04d88072f90f86a07481418b8ff4b6b.sqlite
    

    I added sqlite and ini files to qrc. After compiling the app, I extracted apk file, and there are sqlite file in asset folder. I think the only problem is setting assets folder as default path in c++.
    On the other hand I am able to set asset path in QML. For example in the project, I have WebView.qml page that html and css files are in assets folder in project. When I set assets path as:

    WebView {
                id: webViewUrl
                url: "file:///android_asset/html/index.html" 
                width: parent.width
                height: parent.height
            }
    

    it is working on Android. But when I try the same path in c++ it doesn't recognize assets folder:

    QString filePath = "file:///android_asset/qml/OfflineStorage";
            QDir dir;
            if(dir.mkpath(QString(filePath))){
                    qDebug() << "Default storage path >> "+engine.offlineStoragePath(); 
    // Default storage path >> /data/user/0/org.project.surveyingcalculator/files/QML/OfflineStorage"
                    engine.setOfflineStoragePath(QString(filePath));
                    qDebug() << "New storage path >> "+engine.offlineStoragePath();
    // New storage path file:///android_asset/qml/OfflineStorage
                }
            engine.clearComponentCache();
    

    Is there any way to set assets folder as default storage path in c++?
    Thank you.
    Edit: The sqlite works with my app on desktop with this code in main.cpp:

    // Desktop storage path
        QString filePath = "./android/assets/qml/OfflineStorage";
            QDir dir;
            if(dir.mkpath(QString(filePath))){
                    engine.setOfflineStoragePath(QString(filePath));
                }
            engine.clearComponentCache();
    
    T 1 Reply Last reply 25 Mar 2019, 21:50
    0
    • E edip
      25 Mar 2019, 21:25

      @Tom_H I have an existing sqlite database in asset folder of Android. In project path it looks like this:

      android
      |
       assets
       └── qml
          └── OfflineStorage
              └── Databases
                  ├── e04d88072f90f86a07481418b8ff4b6b.ini
                  └── e04d88072f90f86a07481418b8ff4b6b.sqlite
      

      I added sqlite and ini files to qrc. After compiling the app, I extracted apk file, and there are sqlite file in asset folder. I think the only problem is setting assets folder as default path in c++.
      On the other hand I am able to set asset path in QML. For example in the project, I have WebView.qml page that html and css files are in assets folder in project. When I set assets path as:

      WebView {
                  id: webViewUrl
                  url: "file:///android_asset/html/index.html" 
                  width: parent.width
                  height: parent.height
              }
      

      it is working on Android. But when I try the same path in c++ it doesn't recognize assets folder:

      QString filePath = "file:///android_asset/qml/OfflineStorage";
              QDir dir;
              if(dir.mkpath(QString(filePath))){
                      qDebug() << "Default storage path >> "+engine.offlineStoragePath(); 
      // Default storage path >> /data/user/0/org.project.surveyingcalculator/files/QML/OfflineStorage"
                      engine.setOfflineStoragePath(QString(filePath));
                      qDebug() << "New storage path >> "+engine.offlineStoragePath();
      // New storage path file:///android_asset/qml/OfflineStorage
                  }
              engine.clearComponentCache();
      

      Is there any way to set assets folder as default storage path in c++?
      Thank you.
      Edit: The sqlite works with my app on desktop with this code in main.cpp:

      // Desktop storage path
          QString filePath = "./android/assets/qml/OfflineStorage";
              QDir dir;
              if(dir.mkpath(QString(filePath))){
                      engine.setOfflineStoragePath(QString(filePath));
                  }
              engine.clearComponentCache();
      
      T Offline
      T Offline
      Tom_H
      wrote on 25 Mar 2019, 21:50 last edited by
      #4

      @edip I think it has to be a valid writable location on Android. I suggest putting your database in a qrc file, then copying it to a writable location on app startup. I use this technique for certain files. I also call setOfflineStoragePath, but I specify a writable location. Try something like this:

      QString appdir()
      {
          QStringList dirs = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation);
          if (dirs.length() >= 2)
              return dirs[1];
          if (dirs.length() == 1)
              return dirs[0];
          return "";
      }
      
      QString dbpath = appdir() + "/my.db";
      QFile::copy(":/res/databases/my.db", dbpath);
      
      1 Reply Last reply
      1
      • E Offline
        E Offline
        edip
        wrote on 25 Mar 2019, 21:54 last edited by
        #5

        Thank you. I try now.

        1 Reply Last reply
        0
        • E Offline
          E Offline
          edip
          wrote on 26 Mar 2019, 23:59 last edited by edip
          #6

          @Tom_H Your technique worked on AppLocalDataLocation and AppDataLocation paths. ini and sqlite files are copied in the folder but sqlite file was empty database. *.ini file was copied properly. I deleted the empty sqlite file and I did copy-paste the original database , the app worked. But why is it copied empty sqlite file when running the app first time?

          My code in main.cpp:

          QString appdir()
          {
              QStringList dirs = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation);
              if (dirs.length() >= 2)
                  return dirs[1];
              if (dirs.length() == 1)
                  return dirs[0];
              return "";
          }
          QString dbpath = appdir() + "/QML/OfflineStorage/Databases/e04d88072f90f86a07481418b8ff4b6b.sqlite";
              QString dbpath_ini = appdir() + "/QML/OfflineStorage/Databases/e04d88072f90f86a07481418b8ff4b6b.ini";
              QString offline_path = appdir() + "/QML/OfflineStorage";
              engine.setOfflineStoragePath(QString(offline_path));
              qDebug() << "New storage path >> "+engine.offlineStoragePath();
          
              QDir dir(appdir() + "/QML/OfflineStorage/Databases");
              if (!dir.exists()){
                dir.mkdir(".");
              }
              qDebug() << "dbpath: >> " + dbpath;
              QFile::setPermissions(dbpath ,QFile::WriteOwner | QFile::ReadOwner);
              QFile::setPermissions(dbpath_ini ,QFile::WriteOwner | QFile::ReadOwner);
          
              if (QFile::exists(dbpath))
              {
                  QFile::remove(dbpath);
              }
              QFile::copy(":android/assets/qml/OfflineStorage/Databases/e04d88072f90f86a07481418b8ff4b6b.sqlite", dbpath);
              QFile::copy(":android/assets/qml/OfflineStorage/Databases/e04d88072f90f86a07481418b8ff4b6b.ini", dbpath_ini);
          

          Edit: When the app runs for the first time, the database isn't active. When the app runs second time the database works and sqlite file is created properly. copy process of sqlite file doesn't initialize by main.cpp

          T 1 Reply Last reply 27 Mar 2019, 00:54
          0
          • E edip
            26 Mar 2019, 23:59

            @Tom_H Your technique worked on AppLocalDataLocation and AppDataLocation paths. ini and sqlite files are copied in the folder but sqlite file was empty database. *.ini file was copied properly. I deleted the empty sqlite file and I did copy-paste the original database , the app worked. But why is it copied empty sqlite file when running the app first time?

            My code in main.cpp:

            QString appdir()
            {
                QStringList dirs = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation);
                if (dirs.length() >= 2)
                    return dirs[1];
                if (dirs.length() == 1)
                    return dirs[0];
                return "";
            }
            QString dbpath = appdir() + "/QML/OfflineStorage/Databases/e04d88072f90f86a07481418b8ff4b6b.sqlite";
                QString dbpath_ini = appdir() + "/QML/OfflineStorage/Databases/e04d88072f90f86a07481418b8ff4b6b.ini";
                QString offline_path = appdir() + "/QML/OfflineStorage";
                engine.setOfflineStoragePath(QString(offline_path));
                qDebug() << "New storage path >> "+engine.offlineStoragePath();
            
                QDir dir(appdir() + "/QML/OfflineStorage/Databases");
                if (!dir.exists()){
                  dir.mkdir(".");
                }
                qDebug() << "dbpath: >> " + dbpath;
                QFile::setPermissions(dbpath ,QFile::WriteOwner | QFile::ReadOwner);
                QFile::setPermissions(dbpath_ini ,QFile::WriteOwner | QFile::ReadOwner);
            
                if (QFile::exists(dbpath))
                {
                    QFile::remove(dbpath);
                }
                QFile::copy(":android/assets/qml/OfflineStorage/Databases/e04d88072f90f86a07481418b8ff4b6b.sqlite", dbpath);
                QFile::copy(":android/assets/qml/OfflineStorage/Databases/e04d88072f90f86a07481418b8ff4b6b.ini", dbpath_ini);
            

            Edit: When the app runs for the first time, the database isn't active. When the app runs second time the database works and sqlite file is created properly. copy process of sqlite file doesn't initialize by main.cpp

            T Offline
            T Offline
            Tom_H
            wrote on 27 Mar 2019, 00:54 last edited by
            #7

            @edip I don't know, but does your initial database contain data or is it just empty structure? If it's empty structure, then I recommend creating it on the fly, which is what I do. Then you don't have to copy anything. Something like this:

            [db.js]

            .pragma library
            .import QtQuick.LocalStorage 2.12 as Db
            
            function getdb()
            {
                return Db.LocalStorage.openDatabaseSync("MyDb", "1.0", "My Database", 1000000)
            }
            
            function init()
            {
                try {
                    var db = getdb()
                    db.transaction(function (tx) {
                        tx.executeSql('create table if not exists ...')
                    })
                }
                catch (err) {
                    console.log('Error creating database: ' + err)
                }
            }
            
            1 Reply Last reply
            0
            • E Offline
              E Offline
              edip
              wrote on 27 Mar 2019, 00:57 last edited by
              #8

              @Tom_H Unfortunately I have many data in sqlite which I collected them from json data. I should use existing database. If I knew c++ I would do it from QSQLITE driver but I don't know c++. That's why I try to use Local Storage's sqlite file on Android.

              T 1 Reply Last reply 27 Mar 2019, 02:52
              0
              • E edip
                27 Mar 2019, 00:57

                @Tom_H Unfortunately I have many data in sqlite which I collected them from json data. I should use existing database. If I knew c++ I would do it from QSQLITE driver but I don't know c++. That's why I try to use Local Storage's sqlite file on Android.

                T Offline
                T Offline
                Tom_H
                wrote on 27 Mar 2019, 02:52 last edited by
                #9

                @edip Are you copying the database before loading the main QML file?

                1 Reply Last reply
                1
                • E Offline
                  E Offline
                  edip
                  wrote on 27 Mar 2019, 10:40 last edited by
                  #10

                  @Tom_H Yes like this:

                  ...
                      QFile::copy(":android/assets/qml/OfflineStorage/Databases/e04d88072f90f86a07481418b8ff4b6b.sqlite", dbpath);
                      QFile::copy(":android/assets/qml/OfflineStorage/Databases/e04d88072f90f86a07481418b8ff4b6b.ini", dbpath_ini);
                      QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
                      db.setDatabaseName(dbpath);
                      db.open();
                      engine.load(QUrl(QStringLiteral("qrc:/main.qml"))
                  ....
                  
                  T 1 Reply Last reply 27 Mar 2019, 14:41
                  0
                  • E Offline
                    E Offline
                    edip
                    wrote on 27 Mar 2019, 14:23 last edited by
                    #11

                    @Tom_H Here is a sample app that is unable to copy files in Android's local folder.

                    1 Reply Last reply
                    0
                    • E edip
                      27 Mar 2019, 10:40

                      @Tom_H Yes like this:

                      ...
                          QFile::copy(":android/assets/qml/OfflineStorage/Databases/e04d88072f90f86a07481418b8ff4b6b.sqlite", dbpath);
                          QFile::copy(":android/assets/qml/OfflineStorage/Databases/e04d88072f90f86a07481418b8ff4b6b.ini", dbpath_ini);
                          QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
                          db.setDatabaseName(dbpath);
                          db.open();
                          engine.load(QUrl(QStringLiteral("qrc:/main.qml"))
                      ....
                      
                      T Offline
                      T Offline
                      Tom_H
                      wrote on 27 Mar 2019, 14:41 last edited by
                      #12

                      @edip I don't think the C++ QSqlDatabase has any affect on QML LocalStorage, but I don't know. I'd have to look at the Qt source code. The question boils down to "How do we tell LocalStorage to use an existing database?". Surely there must be a way. If not, you'll either have to do your database access in C++, or import your data in LocalStorage (you can export the required DDL and DML from either sqlite command line or sqlitebrowser). Or, since it works on the 2nd startup, find a graceful way to do that.

                      But before doing that, try to get in touch with a Qt developer on IRC or the mailing list. I'm out of ideas. Good luck. Please post the solution here when you get a chance.

                      1 Reply Last reply
                      1
                      • E Offline
                        E Offline
                        edip
                        wrote on 27 Mar 2019, 14:52 last edited by edip
                        #13

                        Thank you @Tom_H . I think when running Local Storage db it first look for its database, when it doesn't find any database, it creates an empty database. In github sample I just tried to copy two files to Android's path, it didn't work. Actually the question is how to copy a file to Android's path? I will research about it and I will write the solution here.
                        This record shows the problem :
                        https://streamable.com/vkhy0

                        1 Reply Last reply
                        0
                        • E Offline
                          E Offline
                          edip
                          wrote on 28 Mar 2019, 06:31 last edited by edip
                          #14

                          This code in main.cpp worked. I know there should be better way, sorry I don't know c++ :) I will make it a class later. The code sets default storage path and it copies ini and sqlite files to Android App Data location.
                          @Tom_H thanks for solutions!

                          // set default Local Storage path:
                          qDebug() << "Default storage path >> "+engine.offlineStoragePath();
                              QString localPath = QStandardPaths::writableLocation( QStandardPaths::AppDataLocation );
                              QString dbpath = appdir() + "/OfflineStorage/Databases/e04d88072f90f86a07481418b8ff4b6b.sqlite";
                              QString offline_path = appdir() + "/OfflineStorage";
                              engine.setOfflineStoragePath(QString(offline_path));
                              qDebug() << "New storage path >> "+engine.offlineStoragePath();
                              
                              // Copy sqlite file
                              QString dbName = "e04d88072f90f86a07481418b8ff4b6b.sqlite";
                              // determine source path
                              QString dbSourcePath = ":android/assets/qml/OfflineStorage/Databases/e04d88072f90f86a07481418b8ff4b6b.sqlite";
                              QFileInfo dbSourceInfo(dbSourcePath);
                          
                              // determine destination path
                              QDir writableLocation(appdir() + "/OfflineStorage/Databases/");
                              if (!writableLocation.exists()) {
                                  writableLocation.mkpath(".");
                              }
                              QString dbDestPath = writableLocation.filePath(dbName);
                              QFileInfo dbDestInfo(dbDestPath);
                          
                              // determine if the source db has changed
                              bool dbSourceUpdated = dbSourceInfo.lastModified() > dbDestInfo.lastModified();
                          
                              // copy or replace db if needed
                              if ((!dbDestInfo.exists()) || dbSourceUpdated) {
                                  QFile::remove(dbDestPath);
                                  if (!QFile::copy(dbSourcePath, dbDestPath)) {
                                      qCritical() << "ERROR: source db " << dbSourcePath << " not copied to "<< dbDestPath;
                                      //return false;
                                  } else {
                                      qDebug() << "db successfully copied or replaced to " << dbDestPath;
                                  }
                          
                              } else {
                                  qDebug() << "dest db " << dbDestPath << " already exists";
                              }
                          
                              // make db writable
                              QFile::setPermissions(dbDestPath, QFile::WriteOwner | QFile::ReadOwner);
                              qDebug() << "current db: " << dbDestPath;
                          
                              // Copy ini file
                              QString dbName_ini = "e04d88072f90f86a07481418b8ff4b6b.ini";
                              QString dbSourcePath_ini = ":android/assets/qml/OfflineStorage/Databases/e04d88072f90f86a07481418b8ff4b6b.ini";
                              QFileInfo dbSourceInfo_ini(dbSourcePath_ini);
                              QDir writableLocation_ini(appdir() + "/OfflineStorage/Databases/");
                              if (!writableLocation_ini.exists()) {
                                  writableLocation_ini.mkpath(".");
                              }
                              QString dbDestPath_ini = writableLocation_ini.filePath(dbName_ini);
                              QFileInfo dbDestInfo_ini(dbDestPath_ini);
                              bool dbSourceUpdated_ini = dbSourceInfo_ini.lastModified() > dbDestInfo_ini.lastModified();
                              if ((!dbDestInfo_ini.exists()) || dbSourceUpdated_ini) {
                                  QFile::remove(dbDestPath_ini);
                                  if (!QFile::copy(dbSourcePath_ini, dbDestPath_ini)) {
                                      qCritical() << "ERROR: source db " << dbSourcePath_ini << " not copied to "<< dbDestPath_ini;
                                      //return false;
                                  } else {
                                      qDebug() << "db successfully copied or replaced to " << dbDestPath_ini;
                                  }
                              } else {
                                  qDebug() << "dest db " << dbDestPath_ini << " already exists";
                              }
                              QFile::setPermissions(dbDestPath_ini, QFile::WriteOwner | QFile::ReadOwner);
                              qDebug() << "current db: " << dbDestPath_ini;
                          
                          1 Reply Last reply
                          0

                          12/14

                          27 Mar 2019, 14:41

                          • Login

                          • Login or register to search.
                          12 out of 14
                          • First post
                            12/14
                            Last post
                          0
                          • Categories
                          • Recent
                          • Tags
                          • Popular
                          • Users
                          • Groups
                          • Search
                          • Get Qt Extensions
                          • Unsolved