SQLite in Android-Service



  • Hallo,

    ich habe eine Datenbank, auf die ich über Qt zugreife, und eine C++-Funktion, in der auf die Datenbank zugegriffen wird. Die Funktion funktioniert auch einwandfrei, wenn ich sie von C++ aus aufrufe.
    Nur wenn ich sie von Java aus mit einem beim Boot gestarteten Service aufrufe, lässt sich die Datenbank nicht öffnen, weil der SQLite-Treiber nicht geladen wurde. Der Funktionsaufruf an sich funktioniert auch, ich bekomme nur meine eigenen Debug-Meldungen, dass sich die Datenbank nicht öffnen ließ.
    Die QSQLite-Library ist aber in dem Verzeichnis "/data/data/my.app.package.MyApp/qt-reserved-files/plugins/sqldrivers/libqsqlite.so".
    Ich habe nun also einmal in der Java-Datei Folgendes hinzugefügt:

    static {
            System.loadLibrary("MyAppLib");
            System.loadLibrary("qsqlite");    // Service-Absturz
        }
    

    Die libMyAppLib.so brauche ich für den Funktionsaufruf. Das funktioniert auch.
    Nur der Aufruf System.loadLibrary("qsqlite"); führt zu einem Service-Absturz.
    Testweise habe ich es auch einmal mit System.loadLibrary("sqlite"); versucht, das führte aber zu keinem Absturz und auch keiner Fehlermeldung in der Log-Datei, nur meine Debug-Meldungen erscheinen, dass die Datenbank nicht geöffnet werden konnte und das an nicht geladenen Treibern liegt.
    Wie gesagt, wenn ich aber die App öffne (nicht den Service; der startet ja direkt nach dem Boot) kann die Datenbank über die gleiche Funktion gelesen werden.

    Vielen Dank schon einmal für eure Hilfe!



  • Ich habe nun einmal libqsqlite.so direkt in "/path/to/build/android-build/libs/x86/" eingefügt, das .apk-Archiv neu erstellt und schon stürzt der Service nicht mehr ab. In "/data/data/my.app.package.MyApp/qt-reserved-files/plugins/sqldrivers/" scheint Java die nicht zu finden.
    Dennoch kann ich immer noch nicht die Datenbank öffnen - weiterhin ist der Treiber wohl nicht geladen worden.

    Hat noch jemand eine Idee?

    Edit:
    Durch den QtCreator wird die libsqlite.so anscheinend nur in libplugin_sqldrivers_libqsqlite.so umbenannt. System.loadLibrary("plugin_sqldrivers_libqsqlite"); funktioniert also.
    Allerdings wird auch so nichts geladen.
    Kann man die Treiber irgendwie manuell laden?

    Edit Nr. 2:
    Ich vermute, dass die Libraries nicht geladen werden können, weil es keine QCoreApplication gibt und die LibraryPaths deshalb nicht definiert sind.
    Wenn ich die aber über einen QPluginLoader mit einer absoluten Pfadangabe lade, kann ich die Datenbank immer noch nicht öffnen.

    Edit Nr. 3:
    Auch wenn das vermutlich eher eine Qt-Frage ist: kann man QCoreApplication irgendwie initialisieren ohne die Schleife (QCoreApplication::exec()) auszuführen? Damit eben die ganzen Pfade wie ApplicationDirPath, ApplicationFilePath und LibraryPath bereits gesetzt sind?

    Inzwischen, wenn ich mit QCoreApplication::addLibrary("/data/data/my.app.package.MyApp/qt-reserved-files/plugins"); und QCoreApplication::addLibrary("/data/app/my.app.package.MyApp/lib/architecture" die Pfade hinzufüge, kann ich die Datenbank öffnen. Es kann aber keine Abfrage ausgeführt werden, weil angeblich kein Treiber geladen ist. Wenn ich mir aber QSqlDatabase::drivers() ausgebe, habe ich eindeutig den Treiber geladen.
    Den Pfad der Datenbank musste ich natürlich auch absolut angeben, weil kein QCoreApplicationFilePath gesetzt ist. Das sind aber eigentlich keine schönen und dauerhaften Lösungen, weshalb es vermutlich das Beste wäre, wenn ich eine QCoreApplication verwende. Kann ich die sonst nicht auch in Java irgendwie initialisieren?

    Edit Nr. 4:
    Ich musste das alte QSqlQuery-Objekt löschen und ein neues erstellen, damit die Verbindung aktualisiert wird. Es sieht jetzt verkürzt so aus:

    Controller::Controller(QString databaseName, QObject *parent) : QObject(parent), db(QSqlDatabase::addDatabase("QSQLITE")), query(new QSqlQuery(db))
    {
    	if(!QSqlDatabase::drivers().contains(db.driverName()))
    	{
    		QCoreApplication::addLibraryPath("/data/data/my.app.package/qt-reserved-files/plugins/");
    		QCoreApplication::addLibraryPath("/data/app/my.app.package-1/lib/x86");
    
    		QSqlDatabase::removeDatabase(QSqlDatabase::defaultConnection);
    		delete query;
    		db = QSqlDatabase::addDatabase("QSQLITE");
    		query = new QSqlQuery(db);
    	}
    	db.setDatabaseName(QString("/data/data/my.app.package/files/") + databaseName);
    }
    

    Das ist aber natürlich mit den ganzen absoluten Pfadangaben sehr unschön, auch wenn es funktioniert (aber auch nicht sichergestellt, dass es immer funktioniert).
    Wie bestimmt denn eigentlich QCoreApplication die ganzen Pfade? Kann ich das nicht ansonsten selbst machen?



  • auf den Pfad : /data/data/my.app.package/files/

    kannst Du normal immer zugreifen. Der Pfad ist für deine App "reserviert"
    Auf alle anderen Pfade kannst Du nicht zugreifen (Sandbox-Prinzip), außer
    auf die SD Karte, wenn Du die Berechtigungen dazu hast (Manifest.xml) bzw.
    Dir vom Anwender hast geben lassen.

    QT auf Android habe ich nur kurz ausprobiert - das Installieren der Runtime
    in den globalen Temp Ordner erschien mir nicht so einfach, das es ein Anwender
    allein könnte und das ausliefern im apk erschien mir der Download zu groß.

    Die üblichen Nachteile wie bei Xamarin, daher nutze ich Java für Android, würde
    aber Qt vor Xamarin vorziehen, wenn ich entscheiden müsste 🙂