Как мне создавать файлы, когда все, что у меня есть, — это uri каталога? (Постоянное разрешение для каталога было предоставлено пользователем Android.)

#java #android #file #kotlin #file-permissions

#java #Android #файл #kotlin #файл-разрешения

Вопрос:

Я пытаюсь записывать и читать файлы, которые также видны и доступны для редактирования с ПК, когда устройство Android подключено к нему через USB. Эти файлы могут быть созданы через подключение к ПК.

Для достижения этой цели я пытаюсь получить постоянное разрешение URI для каталога, а затем создать или прочитать файлы в этом каталоге.

Я нахожусь на этапе «проверки концепции».

Внутри метода MainActivity onCreate у меня есть следующий код:

 startActivityForResult(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply {
    flags = Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
}, GET_PERSISTABLE_PERMISSION)
 

Когда я запускаю приложение, появляется средство выбора каталога, и я могу выбрать каталог.

В MainActivity у меня также есть:

 override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    if (requestCode == GET_PERSISTABLE_PERMISSION amp;amp; resultCode == Activity.RESULT_OK) {
        val uri = data?.data!!
        val contentResolver = applicationContext.contentResolver
        val takeFlags: Int = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
        contentResolver.takePersistableUriPermission(uri, takeFlags)

        val tmpFile = File(uri.path, "debugTestFile.txt")
        tmpFile.createNewFile()
        tmpFile.appendText("árvíztűrő tükörfúrógéprn")
    }
    super.onActivityResult(requestCode, resultCode, data)
}
 

Вещи, которые я пробовал:

  • uri.toString() вместо uri.path
  • flags = Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION при создании намерения
  • предоставление разных каталогов на устройстве Android в папках Downloads, Music, DCIM при запросе Android

Несмотря на все мои усилия, tmpFile.createNewFile() строка выдает исключение с сообщением «Нет такого файла или каталога».

     Process: hu.ibcs.android.scan, PID: 17309
    java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=1, result=-1, data=Intent { dat=content://com.android.externalstorage.documents/tree/primary:Music/GVtest flg=0xc3 }} to activity {hu.ibcs.android.scan/hu.ibcs.android.scan.MainActivity}: java.io.IOException: No such file or directory
        at android.app.ActivityThread.deliverResults(ActivityThread.java:4846)
        at android.app.ActivityThread.handleSendResult(ActivityThread.java:4887)
        at android.app.servertransaction.ActivityResultItem.execute(ActivityResultItem.java:51)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2017)
        at android.os.Handler.dispatchMessage(Handler.java:107)
        at android.os.Looper.loop(Looper.java:214)
        at android.app.ActivityThread.main(ActivityThread.java:7397)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:935)
     Caused by: java.io.IOException: No such file or directory
        at java.io.UnixFileSystem.createFileExclusively0(Native Method)
        at java.io.UnixFileSystem.createFileExclusively(UnixFileSystem.java:317)
        at java.io.File.createNewFile(File.java:1008)
        at hu.ibcs.android.scan.MainActivity.onActivityResult(MainActivity.kt:106)
        at android.app.Activity.dispatchActivityResult(Activity.java:8135)
        at android.app.ActivityThread.deliverResults(ActivityThread.java:4839)
 

Комментарии:

1. apply { flags = Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION Это не имеет смысла, поскольку вы ничего не можете предоставить, поскольку вы не являетесь поставщиком. Пожалуйста, удалите. Вместо этого вы должны быть рады, что в onActivityResult вы получаете uri и получаете разрешения, которые вы можете использовать постоянно. Ну, вы это делаете.

2. val tmpFile = File(uri.path, "debugTestFile.txt") Это бессмысленно, поскольку uri.path не является путем файловой системы, и вы не можете использовать для него класс File. Вместо этого вы должны использовать переменную DocumentFile для полученного uri и использовать методы SAF или Storage Access Framework для создания папок и файлов.

3. How do I use a persistable permission that was granted by the Android user? Вы имеете в виду: How do I use an uri of a file seleced by the Android user?

4. @blackapps Спасибо за помощь! URI относится к каталогу, а не к файлу. Я пытаюсь получить доступ ко всему каталогу и создать / прочитать в нем несколько разных файлов.

Ответ №1:

Большое спасибо @blackapps за предложения!

Я изменил код в MainActivity.onCreate на:

 startActivityForResult(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE), GET_PERSISTABLE_PERMISSION)
 

и код в MainActivity для:

 override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    if (requestCode == GET_PERSISTABLE_PERMISSION amp;amp; resultCode == Activity.RESULT_OK) {
        val uri = data?.data!!
        val contentResolver = applicationContext.contentResolver
        val takeFlags: Int = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
        contentResolver.takePersistableUriPermission(uri, takeFlags)

        val pickedDir = DocumentFile.fromTreeUri(this, uri)
        val tmpFile = pickedDir.createFile("text/csv", "debugTestFile")
        val out: OutputStream? = getContentResolver().openOutputStream(tmpFile!!.uri)
        out?.write(("uFEFF"   "árvíztűrő tükörfúrógéprn").toByteArray()) // adding BOM to the start for Excel to recognize utf8
        out?.close()
    }
    super.onActivityResult(requestCode, resultCode, data)
}
 

Это работает, и, похоже, я могу двигаться дальше.