通过 ACTION_OPEN_DOCUMENT 的 takePersistableUriPermission 在自定义文档提供程序上失败,但仅适用于 API < 26

takePersistableUriPermission via ACTION_OPEN_DOCUMENT fails on a custom documents provider but only for API < 26

我有一个自定义的 DocumentsProvider 实现,只要 Android API 为 26 或更大,用户就可以完美地选择照片或视频供应用使用。使用 APIs 21-25 我得到一个类似于 this SO post 中描述的安全错误。但是,我已经在做 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>

我的意图设置如下所示:

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

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

    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 是我的提供商通过此 post 顶部的清单条目提供的 Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION,3 是值 (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION).

的组合

然而,当我尝试使用 takePersistableUriPermission() API 使用该意图返回的关联 Uri 以及上面的 flags 参数时 'takeFlags' 参数 (initialIntent.getFlags() & URI_PERMISSIONS_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)。

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

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

实施自定义 DocumentsProvider 有何不同,这可能会影响为 API 21 至 25 与 26 及更高级别获取持久权限的能力?

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

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

即使您在尝试获得持久 URI 许可时获得 SecurityException,您仍然始终可以访问从您自己的 DocumentsProvider.

公开的 URI

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

Note: If your app contains a DocumentsProvider and also persists URIs returned from ACTION_OPEN_DOCUMENT, ACTION_OPEN_DOCUMENT_TREE, or ACTION_CREATE_DOCUMENT, be aware that you won’t be able to persist access to your own URIs via takePersistableUriPermission() — despite it failing with a SecurityException, you’ll always have access to URIs from your own app. You can add the boolean EXTRA_EXCLUDE_SELF to your Intents if you want to hide your own DocumentsProvider(s) on API 23+ devices for any of these actions.

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