【问题标题】:Having trouble implementing ACTION_OPEN_DOCUMENT to my project在我的项目中实施 ACTION_OPEN_DOCUMENT 时遇到问题
【发布时间】:2022-02-21 06:08:00
【问题描述】:

我有 AddActivity,它可以让您从可以从相机拍摄的图片或可以从图库中选择的图像中获取 URI。然后你可以去DetailsActivity查看图像。我现在可以正常工作,直到您重新启动设备。重新启动并尝试转到该图像的 DetailsActivity 后,出现以下错误:

Caused by: java.lang.SecurityException: Permission Denial: opening provider com.android.providers.media.MediaDocumentsProvider from ProcessRecord{3a5e86d 2915:jeremy.com.wineofmine/u0a321} (pid=2915, uid=10321) requires that you obtain access using ACTION_OPEN_DOCUMENT or related APIs

我访问了"Open Files Using Storage Access Framework" Android Development 页面并阅读了 Persist Permissions 部分。不过,我无法将它应用到我的项目中。

我认为我不明白的主要事情是您似乎需要调用一个意图(在我的情况下,在 DetailsActivity 中),但我什至没有意图。

这是让您选择图库图片的意图。这是在 AddActivity 中:

Intent intentGallery = new Intent(Intent.ACTION_OPEN_DOCUMENT);
            intentGallery.addCategory(Intent.CATEGORY_OPENABLE);
            intentGallery.setType("image/*");
            intentGallery.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            intentGallery.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
            startActivityForResult(intentGallery, SELECT_IMAGE);

在 DetailsActivity 中,这是它实际崩溃的地方:

imageURI = Uri.parse(cursor.getString(cursor.getColumnIndexOrThrow(WineContract.WineEntry.COLUMN_WINE_IMAGE)));

bitmap = null;
    try {
        //If the cursor does not have anything in the image column, set the image to null, with a height so the textviews look decent
        if (cursor.isNull(cursor.getColumnIndexOrThrow(WineContract.WineEntry.COLUMN_WINE_IMAGE))){
            mFullImage.setImageBitmap(null);
            mFullImage.setMaxHeight(300);
        }else{
            //remake the bitmap from the URI in the image column
      //********This next line is where the program crashes**********
            bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), imageURI);
            mFullImage.setImageBitmap(bitmap);

        }

我可以得到一些帮助来弄清楚如何将它应用到我的项目中吗?

【问题讨论】:

  • 从使用的意图中删除 addFlags() 开始。没有意义。
  • 之后你应该在 onActivityResult 中获得一个持久化的 uri 权限。你的代码在哪里?
  • imageURI = Uri.parse(cursor.getString(cursor.getColumnIndexOrThrow(WineContract.WineEntry.COLUMN_WINE_IMAGE)));。我的上帝...我们应该知道你在那里带什么uri吗?你应该使用每个人都能理解的代码。
  • @greenapps 抱歉,我只是不认为该行的结果对任何人都有帮助。也许我弄错了?这是从该行检索的日志标签:“DetailsActivity: imageURI: content://com.android.providers.media.documents/document/image%3A46421”
  • 是的,这样更好。您应该立即在代码中使用它。

标签: java android


【解决方案1】:

处理权限结果覆盖 onRequestPermissionsResult 如下

 @Override
 public void onRequestPermissionsResult (int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode) {
        case General.REQUESTPERMISSION:
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                //reload my activity with permission granted or use the features that required the permission

            } else {
                Messenger.makeToast(getContext(), R.string.noPermissionMarshmallow);
            }
            break;
    }
}

并在您的 onActivityResult 方法中保留如下所示的权限实现

@Override
public void onActivityResult (int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    //if ok user selected a file
    if (resultCode == RESULT_OK) {
        Uri sourceTreeUri = data.getData();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            getContext().getContentResolver().takePersistableUriPermission(sourceTreeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        }
    }
}

【讨论】:

  • ACTION_OPEN_DOCUMENT 不需要运行时权限。
  • 我刚刚从 onActivityResult 部分添加了“if (Build.VERSION...”语句并解决了问题。所以基本上这段代码(如果我理解正确的话)只是告诉它如果 Android 的版本高于 Lollipop,则需要获得该特定 URI 的持久权限,以便即使在重新启动后也可以打开。那是因为比 Lollipop 更新的版本将其切换为使用“内容:”,这有点锁定。(对不起,我只是想给自己多一点解释)
  • @Richard Muvirimi,我能否解释一下为什么它必须是 Lollipop 或更新版本?例如,这是否有理由不适用于 Kitkat?
  • 是的,完全正确。您应该将棒棒糖部分更改为 Kitkat,因为那是引入存储访问框架的时候
【解决方案2】:

onActivityResult()call takePersistableUriPermission() on a ContentResolver 中,传入你得到的Uri 以及指示你想要什么访问权限(读、写,两者)的模式标志。

【讨论】:

  • 收到java.lang.SecurityException: No persistable permission grants found for UID 10522 and Uri content://com.android.externalstorage.documents/document/primary:Pictures/___.jpg [user 0]
  • @PatLee:您可能想问一个单独的 Stack Overflow 问题,您可以在其中提供 minimal reproducible example,显示您是如何发出 ACTION_OPEN_DOCUMENT 请求的,以及您在哪里以及如何调用 takePersistableUriPermission() .
【解决方案3】:

有点晚了,但是... 我们需要提供持久的 Uri 权限。与其在onActivityResult 上执行与先前答案相反的操作,我更愿意将其添加为标志:

val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).also {
    it.addCategory(Intent.CATEGORY_OPENABLE)
    it.type = "image/*"
    it.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
    it.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}

另外,值得一提的是,持久权限仅适用于 Intent.ACTION_OPEN_DOCUMENT Intent.ACTION_GET_DOCUMENT,而后者就像一次性的东西。

【讨论】:

  • 要持续访问您仍然需要的“uri”:getContentResolver().takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION) in onActivityResult
【解决方案4】:

第一次收到 URI 时需要处理权限拒绝问题。如果您使用 registerForActivityResult() 而不是 startActivityForResult()

    // Kotlin
    private val pickImage = registerForActivityResult(
        ActivityResultContracts.StartActivityForResult()
    ) { result: ActivityResult ->
        if (result.resultCode == Activity.RESULT_OK) {
            //  you will get result here in result.data
            val uri = result.data?.data!!
            requireActivity().contentResolver.takePersistableUriPermission(
                uri,
                Intent.FLAG_GRANT_READ_URI_PERMISSION
            )
            // Do something else with the URI. E.g, save the URI as a string in the database
        }
    }

【讨论】:

    猜你喜欢
    • 2017-03-21
    • 2020-08-07
    • 2015-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-03
    • 1970-01-01
    相关资源
    最近更新 更多