如何在Android中请求MANAGE_EXTERNAL_STORAGE权限?

27

来自Android文档,https://developer.android.com/training/data-storage/manage-all-files#all-files-access

应用程序可以通过以下方式请求用户的全部文件访问权限:

在清单中声明 MANAGE_EXTERNAL_STORAGE 权限。

使用 ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION 意图操作将用户引导到系统设置页面,在该页面上,用户可以为您的应用启用“允许访问所有文件”的选项。

我尝试过的

我知道唯一请求权限的方法是使用 ActivityCompat。我已经尝试了以下代码:

ActivityCompat.requestPermissions(this, new String[]{Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION},1);

ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.MANAGE_EXTERNAL_STORAGE},1);

但两者都没有任何反应。

Android文档很全面,但对新手不太友好。我理解意图操作,并且知道它们可用于在活动之间切换,但我不知道“意图操作”是什么以及如何使用它来请求权限。

5个回答

25

在 Kotlin 中:

    val uri = Uri.parse("package:${BuildConfig.APPLICATION_ID}")

    startActivity(
      Intent(
        Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION,
        uri
      )
    )

(来自这个示例项目)

您可能已经习惯了隐式的Intent。文档要求您使用显式的Intent,其中包括一个操作字符串和在本例中是一个UriUriUri将具有package方案,并通过其应用程序ID标识您的应用程序。

该代码片段将启动一个系统提供的活动,在理论上,它将让用户选择授予您的应用程序MANAGE_EXTERNAL_STORAGE权限。


1
我一直在学习Udemy的Android课程,其中涉及到了Intents,但不是这种方式。 我尝试了以下代码:startActivity(new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION, foo));``` 但是遇到了致命错误,```Caused by: android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.settings.MANAGE_ALL_FILES_ACCESS_PERMISSION dat=package:com.example.storagecleaner }```。 - Chris A
2
抱歉,我误解了。我以为你创建了一个全新的项目。再次阅读后,发现它是最初链接的项目,但使用了一个新的模拟器。我注意到你的应用程序使用了 ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION,而不是 ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION。我在我的应用程序中进行了更改,效果非常好 :) - Chris A
1
目前这只是我尝试为自己开发的东西,用于执行存储上的某些清理任务以及作为一个练习项目。无论如何,感谢您提供的提示! - Chris A
2
由于APPLICATION_ID已被弃用,请将BuildConfig.APPLICATION_ID替换为BuildConfig.LIBRARY_PACKAGE_NAME - Fahad Alduraibi
1
@FahadAlduraibi:APPLICATION_ID 对于应用程序模块仍然有效。 - CommonsWare
显示剩余17条评论

20
您可以像这样创建一个意图:
Intent intent = new Intent(ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION, Uri.parse("package:" + BuildConfig.APPLICATION_ID));

现在,你可以使用startActivityForResult来启动这个意图。
final static int APP_STORAGE_ACCESS_REQUEST_CODE = 501; // Any value
startActivityForResult(intent, APP_STORAGE_ACCESS_REQUEST_CODE);    

在你的onActivityResult方法中,你可以检查用户是否授予了你的权限。
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
    super.onActivityResult(requestCode, resultCode, data);
    if(requestCode == APP_STORAGE_ACCESS_REQUEST_CODE && Environment.isExternalStorageManager())
        // Permission granted. Now resume your workflow.
    }
}

你还可以通过使用新的ActivityResultAPI来启动活动:
// Initialize the variable in before activity creation is complete.
val storagePermissionResultLauncher = registerForActivityResult(StartActivityForResult(),
            ActivityResultCallback<ActivityResult?> {
                if (Environment.isExternalStorageManager())
                {
                    // Permission granted. Now resume your workflow.
                }
            })
// launch the above intent.
storagePermissionResultLauncher.launch(intent)

此外,请确保在您的AndroidManifest.xml文件中添加此权限条目。
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" tools:ignore="ScopedStorage" />

Environment.isExternalStorageManager 无法解析。我应该升级 Gradle 版本吗?感谢您的帮助! - anL
您需要将最低编译和目标SDK版本设置为30。 - shubhamgarg1

19

如果Uri将在Intent中使用,可以使用Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION代替Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION。

if(SDK_INT >= 30){
if(!Environment.isExternalStorageManager()){
    Snackbar.make(findViewById(android.R.id.content), "Permission needed!", Snackbar.LENGTH_INDEFINITE)
            .setAction("Settings", new View.OnClickListener() {
                @Override
                public void onClick(View v) {

                    try {
                        Uri uri = Uri.parse("package:" + BuildConfig.APPLICATION_ID);
                        Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION, uri);
                        startActivity(intent);
                    } catch (Exception ex){
                        Intent intent = new Intent();
                        intent.setAction(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
                        startActivity(intent);
                    }
                }
            })
            .show();
}

3
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
    if (!Environment.isExternalStorageManager()) {
        try {
            var intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION,
                    Uri.parse("package:" + packageName))
            startActivityForResult(intent, REQUEST_PERMISSION)
        } catch (e: Exception) {
            Logger.d(TAG, e.message)
            var intent = Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION)
            startActivityForResult(intent, REQUEST_PERMISSION)
        }
    }
}

注意:ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION和ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION是不同的。
它们都可以引导用户到系统设置页面。 区别在于:
ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION,该操作将用户直接引导到应用程序 ("package:<package-name>") 的设置页面。
ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION,该操作将用户直接引导到应用程序列表。所有想要管理所有文件的应用程序都会显示在该列表中。

你几乎解决了我所有的问题。我已经寻找你这种答案三天了。所以,现在当我安装我的应用程序时,我调用getPermission flutter函数来调用MANAGE_EXTERNAL_STORAGE。然而,之前我无法列出emulated/storage/0中的所有文件夹,但现在什么也没有出现。在允许以下内容后: 是否需要进行任何更改? - user3698694

1

你是否在AndroidManifest.xml文件中添加了uses-permission权限声明?例如:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

2 您可以参考这个 GitHub 库: https://github.com/getActivity/XXPermissions
它包装了 Google SDK 的 api,并提供了一种简单的方式来申请权限。


  1. 根据文档规定,我已经为MANAGE_EXTERNAL_STORAGE做了处理。
  2. 我无法理解。
- Chris A
哦,也许它的README是中文的。但你可以尝试用谷歌翻译一下。它提供了一种更简单的方式来处理Android 11中的权限问题,你可以直接查看代码。你还可以在github上找到其他的Android权限库。 - Matrix
1
不要批评回答问题的人,如果您能够发布文档链接,我会非常感激。 - user3698694
文档:https://developer.android.com/about/versions/11/privacy/storage https://developer.android.com/training/data-storage/manage-all-files - Eugene Gr. Philippov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接