在Android 11上写入许多文件

问题描述

场景

我正在尝试创建许多文件,作为用户的功能。例如,我可能写了一个应用程序,该应用程序为过去几周内他们收听的每首歌都创建了一个文件(例如带有歌词的文本文件)。我无法让用户为我生成的每个文件选择目录和文件名,这将花费几个小时。用户应该可以从其他应用程序访问这些文档。

解决方案(不是真的)

在Android 11中,似乎Storage Access Framework没用。我注意到最初有2种有趣的选择:

  1. 创建新文件(创建与用户互动的启动活动,仅保存一个文件),here
  2. 授予访问目录内容的权限(允许进行读取访问,但无权编写任何文档),如here所述。
  3. 注意:如果您将Android 10作为目标并请求WRITE_EXTERNAL_STORAGE,则已经存在解决方案。不幸的是,此权限在Android 11上被拒绝。因此,我无法使用发布于here的解决方案。
  4. 使用Storage Access Framework(特别是ACTION_OPEN_DOCUMENT_TREE)来访问目录,以访问目录,但是我无法将文件写入该目录。 (我得到FileNotFoundException,因为这不是普通路径,而是树路径。)

判决

我猜想我需要遵循“管理存储设备上的所有文件”的路线,如here所述,其中涉及使用ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION启动额外的活动。我宁可不要请求读取 entire 驱动器的权限,也不要让用户进入设置应用程序以授予权限。写入文件不需要任何权限...

您将如何为用户保存许多(非媒体)文件?

解决方法

有2种方法,但是首先,我将定义文件和目录名称,稍后将其保存在外部(sdcard)Downloads文件夹中

struct ContentView: View {
    
    @State private var valueOfA: String?
    
    var body: some View {
        valueOfA = "Magic!" // ← Here(I know it is impossible but if there is a way of this coding?)
        
        Button("change") { valueOfA = "omid" }
        
        Button("nil") { valueOfA = nil }
        
        Text(valueOfA ?? "")
            .onAppear {
                valueOfA = "Some Value"
            }
    }
}

有效但不建议使用的方法

尽管val outputFilename = "my_file" val outputDirectory = "my_sub_directory" // The folder within the Downloads folder,because we use `DIRECTORY_DOWNLOADS` 已被弃用,但它仍可在以Android 11为目标并在其上运行的应用程序上运行。

Environment.getExternalStoragePublicDirectory

MediaStore方式:

或者,您可以使用MediaStore的Files collection,建议使用file = File(Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_DOCUMENTS),"$outputDirectory/$outputFilename" ) val outputStream = FileOutputStream(file) here。我不知道MediaStore Gaurav Mall集合...

我用kotlin重写了它,并对其进行了修改,以便在此处写入文件:

files

在以下两种情况下,对于Android 29及更高版本,您都不需要val resolver = context.contentResolver val values = ContentValues() // save to a folder values.put(MediaStore.MediaColumns.DISPLAY_NAME,outputFilename) values.put(MediaStore.MediaColumns.MIME_TYPE,"application/my-custom-type") values.put(MediaStore.MediaColumns.RELATIVE_PATH,Environment.DIRECTORY_DOWNLOADS + "/" + outputDirectory) val uri = resolver.insert(MediaStore.Files.getContentUri("external"),values) // You can use this outputStream to write whatever file you want: val outputStream = resolver.openOutputStream(uri!!) // Or alternatively call other methods of ContentResolver,e.g. .openFile

,

在Android 11上,您可以使用标准File类在公共目录Documents中创建子目录,就像在下面的10中一样。如果您知道如何,也可以在10中创建子目录。然后在该子目录中创建文件。不用大惊小怪。

您也具有对许多其他公共目录的写权限。

您不需要所有文件访问权限。

以这种方式创建的文件可由用户使用设备上的官方“文件”应用程序访问。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...