Android 11 ACTION_OPEN_DOCUMENT_TREE: Anfangs-URI auf den Ordner „Dokumente“ setzen [duplicate]

Lesezeit: 5 Minuten

Benutzer-Avatar
Kenobi

Mit dem Scoped Storage-Modell in Android 11 möchte ich dem Benutzer die Möglichkeit geben, einen Ordner auszuwählen, beginnend im Dokumentenordner:

val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI,    ???     )
startActivityForResult(intent, OPEN_DIRECTORY_REQUEST_CODE,null)

Das Problem ist, wie kann ich eine korrekte URI des Dokumentenordners des Telefons generieren? (Es befindet sich nur in root / ) In der offiziellen Dokumentation werden keine Beispiele angegeben. Ich hoffe wirklich, dass es einige nette Konstanten für alle Standardstandorte gibt?

  • “Das Problem ist, wie kann ich eine korrekte URI des Dokumentenordners des Telefons generieren?” – AFAIK, dafür gibt es keine Option, sorry. EXTRA_INITIAL_URI ist so konzipiert, einige zu sein Uri von denen Sie zuvor bezogen haben ACTION_OPEN_DOCUMENT_TREE.

    – CommonsWare

    15. Mai 2021 um 23:44 Uhr

  • @CommonsWare, bitte schau dir meine Antwort an.

    – Blackapps

    16. Mai 2021 um 8:51 Uhr

Benutzer-Avatar
schwarze Apps

Wir werden manipulieren INITIAL_URI erhalten von StorageManager..getPrimaryStorageVolume().createOpenDocumentTreeIntent().

if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
    StorageManager sm = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);

    Intent intent = sm.getPrimaryStorageVolume().createOpenDocumentTreeIntent();
    //String startDir = "Android";
    //String startDir = "Download"; // Not choosable on an Android 11 device
    //String startDir = "DCIM";
    //String startDir = "DCIM/Camera";  // replace "/", "%2F"
    //String startDir = "DCIM%2FCamera";
    String startDir = "Documents";

    Uri uri = intent.getParcelableExtra("android.provider.extra.INITIAL_URI");

    String scheme = uri.toString();

    Log.d(TAG, "INITIAL_URI scheme: " + scheme);

    scheme = scheme.replace("/root/", "/document/");

    scheme += "%3A" + startDir;

    uri = Uri.parse(scheme);

    intent.putExtra("android.provider.extra.INITIAL_URI", uri);

    Log.d(TAG, "uri: " + uri.toString());

    ((Activity) context).startActivityForResult(intent, REQUEST_ACTION_OPEN_DOCUMENT_TREE);

    return;
}

  • Sie machen Annahmen über die Uri Format; Diese Annahmen sind möglicherweise nicht über Android-Versionen hinweg stabil.

    – CommonsWare

    16. Mai 2021 um 10:25 Uhr


  • Vielen Dank, das werde ich ausprobieren. Es ist gut genug, wenn es für die meisten Telefone funktioniert, solange es auf den anderen nicht abstürzt. Es ist der “besser als nichts”-Ansatz.

    – Kenobi

    16. Mai 2021 um 11:36 Uhr

  • Funktioniert dies in Android-9 und niedrigeren Versionen?

    – K Pradeep Kumar Reddy

    18. Mai 2021 um 5:12 Uhr

  • if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q)

    – Blackapps

    18. Mai 2021 um 6:52 Uhr

  • Hoffentlich wird das Android-Team dies mit einer Standardimplementierung in einer zukünftigen Android-Version beheben, wenn die obige Lösung kaputt geht.

    – Benutzer1608385

    18. August 2021 um 15:35 Uhr

Benutzer-Avatar
verrückter_junge

Wie kann ich eine korrekte URI des Dokumentenordners des Telefons generieren?

Getestet am:

  1. Xiaomi M2102J20SI
  2. Emulator Pixel 4 XL API 30

Funktion askPermission() öffnet das Zielverzeichnis.

@RequiresApi(Build.VERSION_CODES.Q)
private fun askPermission() {
    val storageManager = application.getSystemService(Context.STORAGE_SERVICE) as StorageManager
    val intent =  storageManager.primaryStorageVolume.createOpenDocumentTreeIntent()

    val targetDirectory = "WhatsApp%2FMedia%2F.Statuses" // add your directory to be selected by the user
    var uri = intent.getParcelableExtra<Uri>("android.provider.extra.INITIAL_URI") as Uri
    var scheme = uri.toString()
    scheme = scheme.replace("/root/", "/document/")
    scheme += "%3A$targetDirectory"
    uri = Uri.parse(scheme)
    intent.putExtra("android.provider.extra.INITIAL_URI", uri)
    startActivityForResult(intent, REQUEST_CODE)
}

Uri der Datei wird zurückgegeben onActivityResult()

 override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (resultCode == RESULT_OK && requestCode == REQUEST_CODE) {
            if (data != null) {
                data.data?.let { treeUri ->

                    // treeUri is the Uri of the file
                    
                   // if life long access is required the takePersistableUriPermission() is used

                    contentResolver.takePersistableUriPermission(
                            treeUri,
                            Intent.FLAG_GRANT_READ_URI_PERMISSION or
                                    Intent.FLAG_GRANT_WRITE_URI_PERMISSION
                    )

                  readSDK30(treeUri)
                }
            }
        }
    }

Funktion readSDK30() wird zum Lesen von Dateien und Ordnern verwendet Uri

  private fun readSDK30(treeUri: Uri) {
        val tree = DocumentFile.fromTreeUri(this, treeUri)!!

        thread {
            val uriList  = arrayListOf<Uri>()
            listFiles(tree).forEach { uri ->
                 
                // Collect all the Uri from here
            }
            
        }
    }

Funktion listFiles() gibt alle Dateien und Ordner in der angegebenen zurück Uri

fun listFiles(folder: DocumentFile): List<Uri> {
            return if (folder.isDirectory) {
                folder.listFiles().mapNotNull { file ->
                    if (file.name != null) file.uri else null
                }
            } else {
                emptyList()
            }
        }

  • Danke, das sagt im Grunde, wie man Scoped Storage für ein zufälliges Startverzeichnis verwendet. Danke für den sauberen Code. Meine Frage war leider, wie man Scoped Storage für ein FIXED Startverzeichnis nutzt, das der User nicht selbst wählen darf.

    – Kenobi

    16. Mai 2021 um 11:31 Uhr


  • @Kenobi, wie man ACTION_OPEN_DOCUMENT_TREE verwendet…….. Es hat nichts mit bereichsbezogener Speicherung zu tun …

    – Blackapps

    18. Mai 2021 um 6:42 Uhr


  • Wie können wir Eigenschaften wie Dauer, Auflösung (wenn es sich bei der Datei um ein Video handelt) aus dem documentfile-Objekt abrufen?

    – Himanshu

    22. Januar um 11:01 Uhr

Benutzer-Avatar
Kenobi

Der gesamte Verdienst geht an die obige Antwort von @blackapp!

Hier ist der gleiche Code in Kotlin-Sprache:

if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
    val sm =  getSystemService(Context.STORAGE_SERVICE) as StorageManager
    intent = sm.primaryStorageVolume.createOpenDocumentTreeIntent()
    //String startDir = "Android";
    //String startDir = "Download"; // Not choosable on an Android 11 device
    //String startDir = "DCIM";
    //String startDir = "DCIM/Camera";  // replace "/", "%2F"
    //String startDir = "DCIM%2FCamera";
    val startDir = "Documents"
    var uriroot = intent.getParcelableExtra<Uri>("android.provider.extra.INITIAL_URI")    // get system root uri
    var scheme = uriroot.toString()
    Log.d("Debug", "INITIAL_URI scheme: $scheme")
    scheme = scheme.replace("/root/", "/document/")
    scheme += "%3A$startDir"                        //change uri to Documents folder
    uriroot = Uri.parse(scheme)
    intent.putExtra("android.provider.extra.INITIAL_URI", uriroot)                        // give changed uri to Intent
    Log.d("Debug", "uri: $uriroot")
  
    startActivityForResult(intent, OPEN_DIRECTORY_REQUEST_CODE);
}

Wie einige Kommentatoren erwähnt haben, könnte dieser Code brechen und in Zukunft nicht mehr funktionieren, was wahr ist. In Anbetracht der Vergangenheit von Android werden sie die Speicher-API jedoch sowieso alle zwei Jahre ändern.

  • Bitte posten Sie Ihren Kotlin-Code erneut an dem oben genannten Posten ‘Frage hat hier bereits eine Antwort: ‘ Besucher dieser Seite hier werden nicht weiter suchen, also denke ich, dass Ihr Code dort besser ist.

    – Blackapps

    28. Mai 2021 um 10:26 Uhr


1014060cookie-checkAndroid 11 ACTION_OPEN_DOCUMENT_TREE: Anfangs-URI auf den Ordner „Dokumente“ setzen [duplicate]

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy