【问题标题】:takePersistableUriPermission via ACTION_OPEN_DOCUMENT fails on a custom documents provider but only for API < 26通过 ACTION_OPEN_DOCUMENT 的 takePersistableUriPermission 在自定义文档提供程序上失败,但仅适用于 API < 26
【发布时间】:2021-08-20 21:39:57
【问题描述】:

我有一个自定义 DocumentsProvider 实现,只要 Android API 为 26 或更高版本,用户就可以完美地选择应用使用的照片或视频。使用 API 21-25 时,我收到类似于this SO post 中描述的安全错误。但是,我已经在做那篇文章中提到的所有事情作为解决方案。

清单条目:

    <provider
        android:name=".storageproviders.FacebookProvider"
        android:authorities="${facebookDocumentsAuthority}"
        android:exported="true"
        android:grantUriPermissions="true"
        android:permission="android.permission.MANAGE_DOCUMENTS">
        <intent-filter>
            <action android:name="android.content.action.DOCUMENTS_PROVIDER" />
        </intent-filter>
    </provider>

我的 Intent 设置如下所示:

    Context context = InTouch.getInstance().getApplicationContext();
    Intent contentSelectionIntent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
    contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
    contentSelectionIntent.setType("*/*");

引用此意图的启动器如下所示:

    mLaunchFileChooserIntent = registerForActivityResult(
            new ActivityResultContracts.StartActivityForResult(),
            new ActivityResultCallback<ActivityResult>() {
                @Override
                public void onActivityResult(ActivityResult result) {
                    if ( result.getResultCode() == Activity.RESULT_OK) {
                        Intent initialIntent = result.getData();
                        if ( initialIntent != null) {
                            // This may have one or more files
                            ArrayList<Uri> uriList = new ArrayList<>();
                            Uri uri = initialIntent.getData();
                            if (uri != null) {
                                // Single file chosen
                                uriList.add(uri);
                            } else {
                            *
                            *
                            *
                            }
                            // I then call my utility method handleMediaClipData() passing the following as the argument for 'takeFlags':
                            // (initialIntent.getFlags() & URI_PERMISSIONS_FLAGS)
                            

使用该启动器作为对按钮按下的响应,如下所示:

    mFiles.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            closeFABMenu();                   
            mLaunchFileChooserIntent.launch(contentSelectionIntent);
        }
    });

我已经验证,使用运行 API 21 的模拟器,从 SAF 选择器(上面的initialIntent)返回的意图将其标志设置为 0x43,这是正确的 - 0x40 是 Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION,由我的提供者通过这篇文章顶部的清单条目,3 是值的组合 (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION)

然而,当我尝试使用 takePersistableUriPermission() API 时,使用该意图返回的关联 Uri 以及上面的 'takeFlags' 参数 (initialIntent.getFlags() &amp; URI_PERMISSIONS_FLAGS) 的 flags 参数,如下所示:

public static Disposable handleMediaClipData(final MediaCreate mediaCreate,
                                             final ArrayList<Uri> mediaUris,
                                             final int takeFlags,
                                             final String listId,
                                             final AppCompatActivity activity) {
    Context context = InTouch.getInstance().getApplicationContext();
    final ContentResolver resolver = context.getContentResolver();
    *
    *
    *
    resolver.takePersistableUriPermission(uri, takeFlags);
    *
    *
    *

我收到以下安全错误:

java.lang.SecurityException: No persistable permission grants found for UID 10084

使用 API 26 或更高版本的模拟器和物理设备上完全相同的代码流(应用程序 ui、自定义 DocumentsProvider)。

如果我使用 API 21 使用 SAF 尝试我的应用程序,并从应用程序特定区域之外的手机中选择一些东西(因此不包含我的自定义 DocumentsProvider),它也可以工作。

因此,我认为这是我在运行 API 21-25 的设备的自定义 DocumentsProvider 中没有做的事情,但我不知道这可能是什么。

实现自定义 DocumentsProvider 有什么不同,这可能会影响获取 API 21 到 25 与 26 及更高版本的持久权限的能力?

我假设从错误中进行某种协调以匹配从选择器返回的 Uri 与最初启动选择器的 Intent,但我不明白这种关系是如何工作的,在哪里开始寻找调试它,或者我什至在这个假设的正确轨道上。

【问题讨论】:

  • 代码太多。我们应该去哪里看。?哪个语句会产生该错误? URI_PERMISSIONS_FLAGS 为什么是你自己的宏?只需使用我们都知道的标志。你又添加了一个。很多复杂的代码。为什么需要两个 uri 数组列表来向我们展示您的问题?请发布最少的代码。
  • 但总的来说:您应该只尝试获取提供给您的权限。
  • 我使用自己的常量(不是宏),因为我在任何地方都使用相同的两个权限,实际上它比每次都拼出它们更简单。
  • 在 ACTION_OPEN_DOCUMENT 的意图中设置这些标志是没有意义的。他们什么都不做。您最好删除它们以获得更清晰的代码。
  • 你只是重复你的代码。为什么?我们已经看到了。把那些标志拿出来,看看它们没有效果。

标签: android android-contentprovider android-contentresolver storage-access-framework


【解决方案1】:

DocumentsProvider 的实现没有任何问题,这是使用 SAF 时 API 19-25 上的预期行为。

即使您在尝试获取持久 URI 权限时获得了 SecurityException,您仍然可以始终访问从您自己的 DocumentsProvider 公开的 URI。

因此,最好从您自己的 URI 中捕获并忽略 SecurityException

注意:如果您的应用包含 DocumentsProvider 并且还保留从 ACTION_OPEN_DOCUMENT、ACTION_OPEN_DOCUMENT_TREE 或 ACTION_CREATE_DOCUMENT 返回的 URI,请注意,您将无法通过 takePersistableUriPermission() 保留对您自己的 URI 的访问 - 尽管它失败了SecurityException,您将始终可以从您自己的应用程序访问 URI。如果您想在 API 23+ 设备上隐藏您自己的 DocumentsProvider(s) 以执行任何这些操作,您可以将布尔值 EXTRA_EXCLUDE_SELF 添加到您的 Intent。

这是来自官方 Android 开发者博客的注释,证实了这种行为 - https://medium.com/androiddevelopers/building-a-documentsprovider-f7f2fb38e86a

【讨论】:

  • 我之前在创建我的 DocumentsProvider 类时已经阅读了该博客的各个方面十几次,并且直到现在还没有正确连接该段落中“您自己的 URI”的实际含义:) 所以我已经修改了我的代码以在 URI 中测试我的“权限根”,以便在我的 DocumentsProvider 类正在运行并且不尝试获取权限时捕获。完美运行。谢谢!
猜你喜欢
  • 2016-03-23
  • 1970-01-01
  • 2014-02-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-23
  • 2011-09-07
  • 1970-01-01
相关资源
最近更新 更多