Android Zugriff auf eine Datei, diese von einer anderen App erstellt wurde?

jackie05

Mitglied
Hallo zusammen.
Ich versuche schon seit Wochen das Problem zu lösen, leider ohne Erfolg.

Ich habe 2 Apps und ich möchte von der erste App ein Backup "von der SQLite Datenbank" erstellen und in der 2te App wieder Importieren.
Das mit dem erstellen und importieren ist kein Problem, nur kann ich mit der 2te App nicht auf die Datei zugreifen, diese ich mit der 1te App erstellt habe.

Früher hat es Problemlos funktioniert, aber seit Android 11 nicht mehr.
Ab November 2021 müssen alle Updates auf "targetSdkVersion" 30 eingestellt sein und jetzt muss ich mir natürlich überlegen, wie ich meine Apps weiterhin in Google Play behalten kann.
Ich möchte auch keine volle Rechte geben, da meine App sonst im Google Play abgelehnt wird.
Meine App braucht die Rechte um einen Backup zu erstellen und in der 2te App diese wieder zu Importieren.
Ich habe 2 Apps, da die erste App mit Werbung ist und die 2te App (Pro Version) ohne Werbung.

Hiermit erstelle ich einen Backup von der SQLite Datenbankdatei:
Code:
ContentResolver resolver = getApplicationContext().getContentResolver();
Uri file = Uri.fromFile(new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),"Database_Backup.db"));
try (ParcelFileDescriptor pfd = resolver.openFileDescriptor(file, "rw")) {
    try {
        InputStream in = new FileInputStream(getDatabasePath(DBHelper.DATABASE_NAME));
        OutputStream out = new FileOutputStream(pfd.getFileDescriptor());
        byte[] buffer = new byte[1024];
        int read;
        while ((read = in.read(buffer)) != -1) {
            out.write(buffer, 0, read);
        }
        in.close();
        out.flush();
        out.close();
    }
    catch (FileNotFoundException e) {
        Log.e("tag", e.getMessage());
    }
    catch (Exception e) {
        Log.e("tag", e.getMessage());
    }
} catch (IOException e) {
    e.printStackTrace();
}

Hiermit Importiere ich die Datei wieder:
Code:
try (ParcelFileDescriptor pfd = ParcelFileDescriptor.open(new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),"Database_Backup.db"), ParcelFileDescriptor.MODE_READ_WRITE);) {
    try {
        File fileTo = new File(getDatabasePath(DBHelper.DATABASE_NAME).getParent(), DBHelper.DATABASE_NAME);
        FileChannel src = new FileInputStream(pfd.getFileDescriptor()).getChannel();
        FileChannel dst = new FileOutputStream(fileTo).getChannel();
        dst.transferFrom(src, 0, src.size());
        src.close();
        dst.close();
    } catch (Exception e) {
        Log.d(TAG, "Import Failed!");
    }
} catch (IOException e) {
    e.printStackTrace();
}

Code:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" tools:ignore="ScopedStorage"/>

<application
    .......
    android:requestLegacyExternalStorage="true"
    .........

Ich würde mich sehr freuen, wenn mir da wer helfen kann und bedanke mich schon mal im Voraus.

Gruss
 
Zuletzt bearbeitet:
Hallo
Ist die Datei auch wirklich in dem App Ordner angekommen?
Hat sie auch die richtigen System Datei rechte (chmode)?

Geht es in der gleichen App die Datei zu exportieren und wieder einzulesen und dann zu öffnen?
 
Zuletzt bearbeitet:
Tipp hast du es mal versucht in der App mit Werbung die Datei auf Datei Systemebne ohne den ContentResolver zu exportieren.
Dann in der App ohne Werbung wider zu importieren .

Dazu solltest du einen Export und Import in der App anbieten.

Ps beim export und import muss die DB geschlossen sein.
 
Vielen Dank für die Antworten.
Hallo
Ist die Datei auch wirklich in dem App Ordner angekommen?
Hat sie auch die richtigen System Datei rechte (chmode)?

Geht es in der gleichen App die Datei zu exportieren und wieder einzulesen und dann zu öffnen?
In der gleiche App kann ich es wieder Importieren, nur nicht mit der anderen App.
Wenn ich mit der anderen App die Datei exportiere, dann kann ich mit diese dann auch wieder importieren.
Ich kann nur nicht auf die Datei zugreifen, wenn diese von der anderen App erstellt wurde, mit der gleiche App klappt das.

Wenn ich diese Berechtigung hinzufüge:
Code:
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" tools:ignore="ScopedStorage" />
Code:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
    if (Environment.isExternalStorageManager()) {
        localBackupSave();
    } else {
        Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
        Uri uri = Uri.fromParts("package", getPackageName(), null);
        intent.setData(uri);
        startActivity(intent);
    }
}
und den Zugriff auf alle Dateien erlaube, dann klappt ja alles wieder, nur wird mein Update auf Google Play dann abgelehnt, nach einer kurzen Überprüfung von Google.

Tipp hast du es mal versucht in der App mit Werbung die Datei auf Datei Systemebne ohne den ContentResolver zu exportieren.
Dann in der App ohne Werbung wider zu importieren .

Dazu solltest du einen Export und Import in der App anbieten.

Ps beim export und import muss die DB geschlossen sein.
Ich habe es auch ohne ContentResolver versucht, leider klappt das nicht.
Die Datenbank ist geschlossen und wird nur verbunden, wenn ich eine Abfrage mache um etwas auszulesen.

Im Anhang befindet sich ein Bild von Google, warum die App abgelehnt wurde.

Ich brauche die Rechte auf alle Dateien, damit ich mit der anderen App auch auf diese Datei zugreifen kann.

Laut Google:
Code:
Aufgrund der momentanen Situation können Apps für Android 11 (API-Level 30), die Zugriff auf alle Dateien anfordern, erst wieder im Mai 2021 bei Google Play hochgeladen werden. Das gilt sowohl für neue Apps als auch für Updates bestehender Apps. Diese temporäre Upload-Einschränkung betrifft nur Apps, die sowohl für Android 11 (API-Level 30) bestimmt sind als auch die Berechtigung "Zugriff auf alle Dateien" erfordern.
Deswegen verstehe ich nicht, wieso meine App mit dieser Berechtigung abgelehnt wurde oder ich muss einfach mal eine richtige erklärung abgeben, warum ich diese Berechtigung brauche.

Oder hat jemand eine Idee, wie ich das Problem noch lösen könnte?

Mal was andere:
In meiner App hat man auch die Möglichkeit sein Backup direkt auf Google Drive zu sichern unter den Einstellungen "verborgene Dateien", das klappt auch Wunderbar, nur wäre es Super, wenn ich mit der 2te App auch darauf zugreifen könnte, dann hätte sich das mit dem Backup auf den Telefonspeicher erledigt.
Würde das denn gehen?
Also, das ich mit 2 verschiedene App eine einzige Google Drive Backup habe und mit den 2 Apps ohne Probleme darauf zugreifen könnte?

Gruss
 

Anhänge

  • Google.png
    Google.png
    120,4 KB · Aufrufe: 3
Welche Fehlermeldung kommt den eigentlich nach dem Import der DB Datei.
Bei einen Zugriff oder beim öffnen der DB?

Mall von dem Kopieren abgesehen kannst du eigentlich die DB auch auf ineinem externen Verzeichnis öffnen? Früher ging das.

Auch das erstellen eine DB auf einem anderen Speicherbereich ging.


Zugreifen auf externen Speicher geht seit API 30 nur noch mit SAF (Storage Access Framework)

Edit
Bis API 29 war nur die echte Physikalische SD Karte davon betroffen jetzt auch die Internen SD Karte.
Mit SAF musst du dir ja die Erlaubnis vom User holen.
 
Zuletzt bearbeitet:
Welche Fehlermeldung kommt den eigentlich nach dem Import der DB Datei.
Bei einen Zugriff oder beim öffnen der DB?
Beim Importieren von der 2ten App erhalte ich folgende Fehlermeldung:
Code:
open failed: EACCES (Permission denied)
Wenn ich mit der App Importiere, mit diese ich die Backupdatei erstellt habe, da klappt es ohne Probleme.

Hab keine wirkliche Ahnung von Android, aber das klingt zumindest nicht ganz falsch: https://developer.android.com/training/secure-file-sharing
Das habe ich auch schon versucht und es funktioniert einfach nicht.
Es soll ja möglich sein, auf Dateien zuzugreifen, diese mit einer anderen App erstellt wurde mit FileProvider, nur klappt es bei mir irgendwie nicht.

Versuche es doch mal mit Firebase. Du kannst ja da verschiedene Paketnamen für eine DB angeben.
In meiner App ist Firebase integriert um Push-Nachrichten zu senden.
Ich habe mich da noch nicht so beschäftigt, ob ich auch Backups von der App auf Firebase sichern kann.

Gruss
 
Ich hab das mit dem Backup auf Google Drive jetzt hinbekommen.
Dazu habe ich einfach einen 2ten "OAuth 2.0-Client-IDs"erstellt für mein Projekt, nun kann ich mit meine 2 Apps auf das hochgeladene Backup zugreifen und herunterladen.
Also hat sich das erst einmal erledigt, mit dem Backup auf den Telefonspeicher.
Vielleicht füge ich das irgendwann mal hinzu.

Und vielen Dank für die Hilfe.

Gruss
 
open failed: EACCES (Permission denied)
Diesen Fehler müsstest du eigentlich schon beim exportieren der Datei bekommen haben. Du wirst da auch in dem chatch Block gekommen sein.
Mit den üblichen pemission.
Denn ohne die Zustimmung des users kommst du nicht auf denn öffentlichen Download Ordner.
 
Diesen Fehler müsstest du eigentlich schon beim exportieren der Datei bekommen haben. Du wirst da auch in dem chatch Block gekommen sein.
Mit den üblichen pemission.
Denn ohne die Zustimmung des users kommst du nicht auf denn öffentlichen Download Ordner.
Ja, das passiert ja auch beim importieren der Datei.
Ich sagte ja, das ich keinen Zugriff auf die Datei habe.

Aber das hat sich jetzt vorerst erledigt, da ich die Backups über Google Drive sichere.

Gruss
 
Ich hatte erst so verstanden das du es exportieren aber nicht wider lesen kannst.

Wie Ich schon sagte ist es ab API 30 nicht mehr möglich auf die öffentlichen Speicherbereiche der internen oder externen SD Karte zuzugreifen.

dies geht nur noch mit SAF dazu brauchst du die Premission im manifest nicht mehr.
Unter API 29 ist es noch möglich nach abfrage der SAF Premission vom User zugriff zur gesamtem Sd Karte zu bekommen.
Unter API 30 ist auch das vorbei es wird eine Liste der öffentlichen Verzeichnisse angezeigt und du musst da sogar einen neuen Ordner anlegen auf den du dann zugriff hast.

hier ein einfaches Beispiel mit SAF

Java:
  public class MainActivity extends AppCompatActivity {

        DocumentFile treeUrlDir;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);

            getSAF_Prermissions();

        }

        void getSAF_Prermissions() {
            SharedPreferences TreePref = getSharedPreferences("SAF_Premission", 0);
            String st = TreePref.getString("TreeURL", "");
            if (!st.equals("")) {
                treeUrlDir = DocumentFile.fromTreeUri(this, Uri.parse(st));
                premissionOK();
            } else {
                startActivityForResult(new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE), 42);
            }
        }

        void premissionOK() {

            DocumentFile dir1 = treeUrlDir.createDirectory("Hallo");
            DocumentFile dir2 = dir1.createFile("txt", "Hallo.txt");

            try {
                writeTextToUri(dir2.getUri());
            } catch (IOException e) {
                e.printStackTrace();
            }

            try {
                String text = readTextFromUri(dir2.getUri());
                Log.d("Saf-Test",text);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        private String readTextFromUri(Uri uri) throws IOException {
            InputStream inputStream = getContentResolver().openInputStream(uri);
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
            StringBuilder stringBuilder = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                stringBuilder.append(line);
            }
            reader.close();
            return stringBuilder.toString();
        }

        private void writeTextToUri(Uri uri) throws IOException {
            OutputStream outPutStream = getContentResolver().openOutputStream(uri);
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outPutStream));
            StringBuilder stringBuilder = new StringBuilder();
            String line;
            writer.write("Hallo das ist ein Text");
            writer.close();
        }

        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
            if ((requestCode == 42) && (resultCode == RESULT_OK) && (data != null)) {
                treeUrlDir = DocumentFile.fromTreeUri(this, data.getData());
                SharedPreferences TreePref = getSharedPreferences("SAF_Premission", 0);
                SharedPreferences.Editor TreeEd = TreePref.edit();
                TreeEd.putString("TreeURL", treeUrlDir.getUri().toString());
                TreeEd.commit();
                premissionOK();
            }
        }
    }

Java:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.jw.sdcard_saf_api23_extern">

    <application
        android:requestLegacyExternalStorage="true"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name="com.jw.sdcard_saf_api23_extern234.MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

    </application>

</manifest>
 

Zurück
Oben