将 Android 11 中的文件保存到外部存储(SDK 30)

Rob*_*ert 6 permissions android file android-external-storage android-11

我正在 Android 11(SDK 版本 30)上编写一个新应用程序,但我根本找不到有关如何将文件保存到外部存储的示例。

我阅读了他们的文档,现在知道他们基本上忽略了清单权限(READ_EXTERNAL_STORAGEWRITE_EXTERNAL_STORAGE)。它们还会忽略android:requestLegacyExternalStorage="true"manifest.xml 应用程序标记中的 。

在他们的文档https://developer.android.com/about/versions/11/privacy/storage 中,他们写道您需要启用DEFAULT_SCOPED_STORAGEFORCE_ENABLE_SCOPED_STORAGE标志以在您的应用程序中启用范围存储。

我必须在哪里启用这些?当我完成此操作后,我如何以及何时获得写入外部存储的实际权限?有人可以提供工作代码吗?
我想保存 .gif、.png 和 .mp3 文件。所以我不想给画廊写信。

提前致谢。

bla*_*pps 10

您可以将文件保存到外部存储上的公共目录。

如文档、下载、DCIM、图片等。

与版本 10 之前一样。

  • 但是,卸载并重新安装应用程序后,应用程序无法识别这些文件。 (5认同)
  • saf是什么?应用程序如何识别卸载前、重新安装后创建的旧文件? (2认同)

Noo*_*ain 9

对应于所有 Api,包括 Api 30、Android 11 :

 public  static  File commonDocumentDirPath(String FolderName){
        File dir = null ;

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            dir = new File (Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS)+ "/"+FolderName );
        } else {
            dir = new File(Environment.getExternalStorageDirectory() + "/"+FolderName);
        }

    // Make sure the path directory exists.
   if (!dir.exists()) {
          // Make it, if it doesn't exit
         boolean success=dir.mkdirs();
         if(!success) {dir=null;}


   }
            
        return  dir ;

    }
Run Code Online (Sandbox Code Playgroud)

现在,使用它commonDocumentDirPath来保存文件。

  • getExternalStoragePublicDirectory 和 getExternalStorageDirectory 均已弃用... (3认同)
  • @BhaveshMoradiya,是的,但现在在 Android 11 中,上述方法适用于所有版本。感谢commonsware提示。 (2认同)

小智 7

**最简单的答案并经过测试(Java)**

private void createFile(String title) {
        Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("text/html");
        intent.putExtra(Intent.EXTRA_TITLE, title);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, Uri.parse("/Documents"));
    }
    createInvoiceActivityResultLauncher.launch(intent);
}

private void createInvoice(Uri uri) {
    try {
        ParcelFileDescriptor pfd = getContentResolver().
                openFileDescriptor(uri, "w");
        if (pfd != null) {
            FileOutputStream fileOutputStream = new FileOutputStream(pfd.getFileDescriptor());
            fileOutputStream.write(invoice_html.getBytes());
            fileOutputStream.close();
            pfd.close();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

/////////////////////////////////////////////////////
// You can do the assignment inside onAttach or onCreate, i.e, before the activity is displayed


    String invoice_html;
    ActivityResultLauncher<Intent> createInvoiceActivityResultLauncher;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

       invoice_html = "<h1>Just for testing received...</h1>";
       createInvoiceActivityResultLauncher = registerForActivityResult(
                new ActivityResultContracts.StartActivityForResult(),
                result -> {
                    if (result.getResultCode() == Activity.RESULT_OK) {
                        // There are no request codes
                        Uri uri = null;
                        if (result.getData() != null) {
                            uri = result.getData().getData();
                            createInvoice(uri);
                            // Perform operations on the document using its URI.
                        }
                    }
                });
Run Code Online (Sandbox Code Playgroud)