(Datenbank-)Datei für App bereitstellen bzw. ins Dateisystem der APP kopieren

  • 33 Antworten
  • Letztes Antwortdatum
Danke, das leuchtet ein. Leider stürzt die App nach dieser Korrektur bei dem Freund immer noch ab. Gibt es da Möglichkeiten zur Diagnose? Dass irgend wie ein Logfile oder ein Absturzbericht erzeugt wird? Hier das komplette Javascript:
Code:
        window.addEventListener('click', event => {
            if (event.target.id == 'btn-pick-db-file') {
                exportsFilepicker.pickFiles({
                    types: ['application/octet-stream'],
                    multiple: false
                }).then(result => {
                    console.log(result.files[0]);
                    Capacitor.Plugins.Filesystem.readFile({ path: result.files[0].path })
                        .then(file => {
                            console.log(file.data);
                            fetch('data:application/octet-stream;base64,' + file.data)
                                .then(res => res.blob())
                                .then(blob => {
                                    console.log(blob);
                                    window.capacitor_blob_writer({
                                        // path: 'file:///data/user/0/com.substanzen.app/databases/SubstancesSQLite.db',
                                        path: '../databases/SubstancesSQLite.db',
                                        blob: blob,
                                        recursive: true,
                                        directory: 'DATA',
                                        fast_mode: false
                                    }).then(result => {
                                        alert('Datenbankdatei wurde erfolgreich eingelesen');
                                        displaySubstances();
                                    });
                                });
                        });
                });
            }
        });
        // function readDatabaseFile(event) {
        //     Capacitor.Plugins.Filesystem.requestPermissions().then((status) => {
        //         console.log(status);
        //         fetch('https://webentwicklung.ulrichbangert.de/_benni/db-cors.php')
        //             .then(response => response.blob())
        //             .then(blob => {
        //                 // console.log(blob);
        //                 window.capacitor_blob_writer({
        //                     path: 'file:///data/user/0/com.substanzen.app/databases/SubstancesSQLite.db',
        //                     blob: blob
        //                     // fast_mode: true
        //                 }).then(result => {
        //                     alert('Datenbankdatei wurde erfolgreich eingelesen');
        //                 });
        //             });
        //     });
        // }
        function displaySubstances() {
            conn = new exports.SQLiteConnection(exports.CapacitorSQLite);
            console.log(conn);
            conn.createConnection(
                "Substances", false, "no-encryption", 3, false
            ).then(db => {
                console.log(db);
                db.open("Substances", false, 'no-encryption', 3, true).then(() => {
                    const sql = 'select * from `Substanzen - Substanzen`';
                    db.query(sql).then(
                        result => {
                            console.log(result);
                            document.querySelector('section.substances').innerHTML = '';
                            result.values.forEach(row => {
                                console.log(row.Name + ' - ' + row.Art);
                                // HTML aus Template lesen und die Platzhalter ersetzen
                                let html = document.getElementById('substance-tpl').innerHTML
                                    .replace(/{{name}}/g, row.Name)
                                    .replace(/{{art}}/g, row.Art)
                                    .replace(/{{beschreibung}}/g, row.Beschreibung)
                                if (row.Bild) {
                                    console.log((typeof new Blob([new Uint8Array(row.Bild).buffer])))
                                    html = html.replace(/{{img}}/g, URL.createObjectURL(new Blob([new Uint8Array(row.Bild).buffer])));
                                } else {
                                    html = html.replace(/{{img}}/g, '""');
                                }
                                // HTML in section mit den Substanzen am Ende eintragen
                                document.querySelector('section.substances')
                                    .insertAdjacentHTML('beforeend', html)
                            });
                        });
                    db.close("Substances");
                });
            });
        }
Gibt auch ein Forum für Capacitor aber die Resonanz dort ist gering:
Installing of APK produced by capacitor fails
Deshalb habe ich das jüngste Problem dort noch nicht gepostet.
 
a) auch unter Javascript gibt es ein try/catch - die Exception fängt ab und gibt Dir dann den Grund aus
b) Was da Capacitor intern macht , vermag ich nicht zu beurteilen - unter der nativen Entwicklung ermittelt man sich das Envoirment mit getFilesDir() / getCacheDir() - In der API Doku von Capacitor müsste sowas bestimmt nachzulesen sein.
 
Welche android Version hat dein handy und welche hat dein freund.

path: 'file:///data/user/0/com.substanzen.app/databases/SubstancesSQLite.db', path: '.

Ist der externe speiche der seit A11 und seit A13 noch stärker eingeschränkt ist.
 
Android-Version des Freundes habe ich schon abgefragt aber keine Antwort. Ich werde noch Mal nachhaken. Hersteller ist Xiaomi.
Selber habe ich Android 11.
 
@jogimuc

Kleine Info :
data/user/0/[Package][/files] ist sein App Verzeichnis , worauf die App-Instanz ohne Permissions Zugriff hat.

ABER : Wie schon mehrfach ( auch im anderen Thread ) erklärt, wird er um einen lokalen Proxy nicht drumrum kommen.
 
Zuletzt bearbeitet:
@swa00 ja bei dem paht habe ich mich vertan.

Aber in den Capacitor wird es auch eine Methode geben die den path zurückgibt. Damit er nicht hart Codet ist.

Interessant wäre aber erstmal Fehlermeldung warum es bei deinem Freund albricht. Ligt es wichtig am Path. Oder doch was anderes.
 
Aber in den Capacitor wird es auch eine Methode geben die den path zurückgibt. Damit er nicht hart Codet ist.
Ja, die gibt es und ich habe das bereits eingearbeitet:
Code:
                                    window.capacitor_blob_writer({
                                        // path: 'file:///data/user/0/com.substanzen.app/databases/SubstancesSQLite.db',
                                        path: '../databases/SubstancesSQLite.db',
                                        blob: blob,
                                        recursive: true,
                                        directory: 'DATA',
                                        fast_mode: false
                                    }).then(result => {
Durch die Übergabe des Strings 'DATA' statt eines absoluten Pfades sollte Capacitor veranlasst werden, den richtigen Pfad dynamisch zu ermitteln. Der führt dann nach "files" statt "databases", deshalb musste ich beim Parameter path zunächst einen Schritt nach oben gehen.
Zumindest auf meinem eigenen Handy funktioniert das.
Als nächste Maßnahme werde ich einen Versionshinweis ins HTML einbauen, um sicher zu stellen, dass der Freund auch wirklich die neueste Version installiert und Handlingfehler auf beiden Seiten auszuschließen.
Ich melde mich dann wieder wenn das abgeschlossen ist.
 
Bei aller Liebe :
Das wird so nichts, wenn du das für unterschiedliche Systeme/Hersteller/Versionen haben möchtest :)

Beispiel :
path: '../databases/SubstancesSQLite.db',

Hier gehst du zurück, dann wieder vor -

Das ist bei vielen Herstellern nicht mehr erlaubt , denn die geben z.b. vor , dass dein "databases" Subfolder , entweder im "files" oder im "cache" Folder sein muss.
Das ist dadurch bedingt , dass in den EInstellungen festgelegt sein muss , ob du den Cache oder den Arbeitsspeicher löschen magst
Ob der dann wirklich bei einem Gerät "files" oder "cache" heisst, bestimmt der Hersteller.

Du musst aktiv zur Runtime auslesen , dann den url-String zusammenbauen und dann erst schreiben.
 
Zuletzt bearbeitet:
Das ist nicht das was ich meinte. Du hast den Path immer noch hart gecodet.
Wie die Methoden gur die native Entwicklung heißen wurde schon gesagt.
Schaue ob du das findest.
 
Danke für diese Hinweise, doch leider sind mir da beim Einsatz von Capacitor ebenfalls die Hände gebunden weil das die einzige Möglichkeit ist, die ich in der Doku finde. Ich hatte auch schon daran gedacht, die Datenbankdatei ins Verzeichnis "files" zu legen um das Navigieren mit ".." zu vermeiden aber finde beim Sqlite-Plugin keine Möglichkeit, einen Pfad anzugeben, der scheint im Plugin fest eingebrannt zu sein:
Code:
            conn = new exports.SQLiteConnection(exports.CapacitorSQLite);
            console.log(conn);
            conn.createConnection(
                "Substances", false, "no-encryption", 3, false
            ).then(db => {
                console.log(db);
                db.open("Substances", false, 'no-encryption', 3, true).then(() => {
                    const sql = 'select * from `Substanzen - Substanzen`';
                    db.query(sql).then(
Das einzige was übergeben wird ist der Name "Substances" und das Plugin baut daraus offenbar den endgültigen Dateinamen zusammen.
Ich werde mal weiter in der Doku des Sqlite-Plugins suchen ob es eine Möglichkeit gibt, diesen Standardpfad zu ändern.
Beiträge automatisch zusammengeführt:

... gesagt, getan: Man kann offenbar die Datenbank auch aus JSON importieren, dann umgeht man das Handling mit den Pfaden:
sqlite/docs/ImportExportJson.md at master · capacitor-community/sqlite
Wenn ich sicher gestellt habe, dass der Freund auch die neueste Version installiert hat, werde ich darauf umstellen. Was mir dabei ein wenig Kopfschmerzen bereitet ist die Tatsache, dass die Datenbank Bilder in Form von Blobs enthält. Ob das funktionieren wird?
 
Zuletzt bearbeitet:
Grundsätzlich ist Sqlite ist nicht zur Speicherung von Rasterimages gedacht, da musst du schon was Anderes nehmen, oder dir einen Cachefolder bauen.
Sqlite macht im Prinzip nichts Anderes , als intern wieder xml's zu schreiben.

Komme mal bitte grundsätzlich von deinem "Desktop" denken weg .
Es handelt sich hier um eine Virtuelle Machine , die komplett Thread basierend aufgebaut ist und keine Fehler verzeiht.
Dein obiger Code ist eigentlich "tödlich" ohne Thread und try/catch - die UI (mainThread) muss Luft bekommen.

Zu deinen RasterImages :
SQLite kennt nur Blobs für die binäre Speicherung.
Du kannst alternativ ggf. mit Base64 arbeiten.
 
Zuletzt bearbeitet:
Genau, die Bilder sind als Blobs in der Datenbank.
 
Kleines Update: Die App läuft jetzt einwandfrei, sowohl auf meinem Handy als auch auf dem des Freundes. Ich habe sie auch auf einem Uralt-Tablet mit Android 5.1 getestet, das ich gerade zur Hand hatte, und sie läuft auch dort.
Hier der Code:
Code:
    <div id="feedback"></div>
    <button id="btn-pick-db-file">Datenbankdatei auswählen</button>
    <button id="btn-download-db-file">Datenbankdatei herunter laden</button>
    <section class="substances"></section>
    <script src="capacitor.js"></script>
    <script src="plugin-filesystem.js"></script>
    <script src="plugin-sqlite.js"></script>
    <script src="plugin-filepicker.js"></script>
    <script src="blob_writer.umd-debug.js"></script>
    <script>
        window.addEventListener('touchstart', event => {
            console.log('click fired');
            if (event.target.id == 'btn-pick-db-file') {
                exportsFilepicker.pickFiles({
                    types: ['application/octet-stream'],
                    multiple: false
                }).then(result => {
                    console.log(result.files[0]);

                    // This makes the app crash when file is large:
                    // Capacitor.Plugins.Filesystem.readFile({ path: result.files[0].path })
                    //     .then(file => {
                    //         console.log(file.data);
                    // fetch('data:application/octet-stream;base64,' + file.data)

                    // This is working:
                    fetch(Capacitor.convertFileSrc(result.files[0].path))
                        .then(res => res.blob())
                        .then(blob => {
                            console.log(blob);
                            window.capacitor_blob_writer({
                                // path: 'file:///data/user/0/com.substanzen.app/databases/SubstancesSQLite.db',
                                path: '../databases/SubstancesSQLite.db',
                                blob: blob,
                                recursive: true,
                                directory: 'DATA',
                                fast_mode: false
                            }).then(result => {
                                console.log('Datenbankdatei wurde erfolgreich eingelesen');
                                displaySubstances();
                            });
                        });
                });
            }
            if (event.target.id == 'btn-download-db-file') {
                readDatabaseFile();
            }
        });
        function readDatabaseFile(event) {
            Capacitor.Plugins.Filesystem.requestPermissions().then((status) => {
                console.log(status);
                fetch('https://webentwicklung.ulrichbangert.de/_benni/db-cors.php')
                    .then(response => response.blob())
                    .then(blob => {
                        console.log(blob);
                        window.capacitor_blob_writer({
                            // path: 'file:///data/user/0/com.substanzen.app/databases/SubstancesSQLite.db',
                            path: '../databases/SubstancesSQLite.db',
                            blob: blob,
                            recursive: true,
                            directory: 'DATA',
                            fast_mode: false
                        }).then(result => {
                            // alert('Datenbankdatei wurde erfolgreich eingelesen');
                            displaySubstances();
                        });
                    });
            });
        }
        async function displaySubstances() {
            conn = new exports.SQLiteConnection(exports.CapacitorSQLite);
            console.log(conn);
            conn.createConnection(
                "Substances", false, "no-encryption", 3, false
            ).then(db => {
                console.log(db);
                db.open("Substances", false, 'no-encryption', 3, true).then(() => {
                    document.getElementById('feedback').innerHTML = `Texte werden aus Datenbank gelesen ...`;
                    const sql = "select rowid, Name, Art, Beschreibung from `Substanzen - Substanzen`";
                    db.query(sql).then(result => {
                        console.log(result);
                        document.querySelector('section.substances').innerHTML = '';
                        let nr = 0, htmlTotal = '';
                        const nrRows = result.values.length;
                        result.values.forEach(row => {
                            console.log(row.Name + ' - ' + row.Art);
                            const sqlImg = "select Bild from `Substanzen - Substanzen` where rowid='" + row.rowid + "'";
                            let srcImg = '';
                            db.query(sqlImg).then(result => {
                                if (result.values[0]) {
                                    const img = result.values[0].Bild;
                                    if (img) {
                                        console.log((typeof new Blob([new Uint8Array(img).buffer])))
                                        srcImg = URL.createObjectURL(new Blob([new Uint8Array(img).buffer]));
                                    }
                                }
                                // HTML aus Template lesen und die Platzhalter ersetzen
                                let html = document.getElementById('substance-tpl').innerHTML
                                    .replace(/{{name}}/g, row.Name)
                                    .replace(/{{art}}/g, row.Art)
                                    .replace(/{{beschreibung}}/g, row.Beschreibung)
                                    .replace(/{{img}}/g, srcImg);
                                htmlTotal += html;
                                nr++;
                                document.getElementById('feedback').innerHTML = `Datensatz ${nr} von ${nrRows} wurde gelesen`;
                                if (nr % 10 == 0 || nr == nrRows) {
                                    // HTML in section mit den Substanzen am Ende eintragen
                                    document.querySelector('section.substances')
                                        .insertAdjacentHTML('beforeend', htmlTotal);
                                    htmlTotal = '';
                                }
                            });
                        });
                        // db.close("Substances");
                        return 'database read successfully';
                    });
                });
            });
        }
        // displaySubstances();
    </script>
Nicht besonders viele Zeilen aber weil ich neu in der Welt von Android bin, hat es mich viel Kopfzerbrechen und Recherche gekoster, um es zum Laufen zu bringen.
Der nächste Schritt ist, das HTML zu speichern, damit nicht bei jedem Start die Datenbank eingelesen werden muss.

Beste Grüße, Ulrich
 

Ähnliche Themen

E
Antworten
25
Aufrufe
1.688
evgkop
E
K
Antworten
3
Aufrufe
402
mezzothunder
mezzothunder
S
Antworten
2
Aufrufe
466
swa00
swa00
Zurück
Oben Unten