尝试通过 ACTION_OPEN_DOCUMENT 为自定义 DocumentsProvider 获取 PersistableUriPermission() 失败 [英] Trying to takePersistableUriPermission() fails for custom DocumentsProvider via ACTION_OPEN_DOCUMENT

查看:38
本文介绍了尝试通过 ACTION_OPEN_DOCUMENT 为自定义 DocumentsProvider 获取 PersistableUriPermission() 失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写一个自定义 DocumentsProvider,它允许其他应用程序对其提供的 Uris 获取持久权限

I am trying to write a custom DocumentsProvider that allows other apps to take persistable permissions to the Uris it provides

我有一个 DocumentsProvider,我在 AndroidManufest.xml 中声明如下

I have a DocumentsProvider that I declare in my AndroidManufest.xml as follows

<provider
   android:name="com.cgogolin.myapp.MyContentProvider"
   android:authorities="com.cgogolin.myapp.MyContentProvider"
   android:grantUriPermissions="true"
   android:exported="true"
   android:permission="android.permission.MANAGE_DOCUMENTS"
   android:enabled="@bool/atLeastKitKat">
  <intent-filter>
    <action android:name="android.content.action.DOCUMENTS_PROVIDER" />
  </intent-filter>
</provider>

并且我的应用具有 MANAGE_DOCUMENTS 权限集

and my app has the MANAGE_DOCUMENTS permission set

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

(显然这不是必需的,但添加/删除它也无关紧要).然后,当我使用

(apparently this is not necessary but adding/removing it also doesn't matter). I can then see my provider when I open the ACTION_OPEN_DOCUMENT picker UI with

Intent openDocumentIntent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
openDocumentIntent.addCategory(Intent.CATEGORY_OPENABLE);
openDocumentIntent.setType("application/pdf");
openDocumentIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION|Intent.FLAG_GRANT_WRITE_URI_PERMISSION|Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
startActivityForResult(openDocumentIntent, EDIT_REQUEST);

并且,从我的提供者那里选择一个文件后,在我的应用程序的 onActivityResult() 方法中,我可以成功地打开我的 DocumentsProvider 提供的文件Uri 我从 intent.getData() 得到.

and, after picking a file from my provider there, in the onActivityResult() method of my App I can then successfully open the file provided by my DocumentsProvider via the Uri I get from intent.getData().

但是,尝试使用

getContentResolver().takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);

getContentResolver().takePersistableUriPermission(uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);

总是失败,像

No permission grant found for UID 10210 and Uri content://com.cgogolin.myapp.MyContentProvider/document/tshjhczf.pdf

如果我从谷歌驱动器中选择一个文件或在选择器 UI 中下载提供程序,则以这种方式获取权限.所以我认为问题出在我的供应商身上.

If I pick a file from the google drive or downloads provider in the picker UI taking permissions in this way works. So I think the problem is in my provider.

尽管我指定了 android:grantUriPermissions="true",但为什么没有创建权限授予?

Why is there no permission grant created despite me specifying android:grantUriPermissions="true"?

我如何说服 Android 为我创建这样的权限授予?

How can I convince Android to create such a permission grant for me?

毕竟我不认为我自己可以做到,因为我不知道打开选择器 UI 的进程的 UID,或者至少我不知道如何.

After all I don't think I can do it myself, as I cannot know the UID of the process that opened the picker UI, or at least not that I knew how.

推荐答案

我之前的回答不好.出于安全原因,您应该使用android.permission.MANAGE_DOCUMENTS".
只有系统界面选择器才能列出您的文档.

My previous answer wasn't good. You are suppose to use "android.permission.MANAGE_DOCUMENTS" for security reasons.
Only System UI picker will be able to list your documents.

但是您在打开文档的应用程序的清单不需要此权限.
其实你不应该获得这个权限,因为它是系统权限.

But you don't need this permission in the manifest of the application that opens documents.
Actually you should not to be able to gain this permission as it is system permission.

我刚刚对其进行了测试,并成功调用了 onActivityResult 的 takePersistableUriPermission 表单.

I've just tested it and call to takePersistableUriPermission form onActivityResult was successful.

我将 DocumentProvider 与模拟数据(一个根,3 个 txt 文档)一起使用.
如果它仍然不适合您,则可能是您的文档提供商存在问题.

I used DocumentProvider with mock data (one root, 3 txt documents).
If it still doesn't work for you there could be some issue with your document provider.

package com.example.test;

import android.database.Cursor;
import android.database.MatrixCursor;
import android.os.CancellationSignal;
import android.os.ParcelFileDescriptor;
import android.provider.DocumentsProvider;

import java.io.FileNotFoundException;

public class MyContentProvider extends DocumentsProvider {

    private final static String[] rootColumns = new String[]{
            "_id", "root_id", "title", "icon"
    };
    private final static String[] docColumns = new String[]{
            "_id", "document_id", "_display_name", "mime_type", "icon"
    };

    MatrixCursor matrixCursor;
    MatrixCursor matrixRootCursor;

    @Override
    public boolean onCreate() {

        matrixRootCursor = new MatrixCursor(rootColumns);
        matrixRootCursor.addRow(new Object[]{1, 1, "TEST", R.mipmap.ic_launcher});

        matrixCursor = new MatrixCursor(docColumns);
        matrixCursor.addRow(new Object[]{1, 1, "a.txt", "text/plain", R.mipmap.ic_launcher});
        matrixCursor.addRow(new Object[]{2, 2, "b.txt", "text/plain", R.mipmap.ic_launcher});
        matrixCursor.addRow(new Object[]{3, 3, "c.txt", "text/plain", R.mipmap.ic_launcher});

        return true;
    }

    @Override
    public Cursor queryRoots(String[] projection) throws FileNotFoundException {
        return matrixRootCursor;
    }

    @Override
    public Cursor queryDocument(String documentId, String[] projection)
            throws FileNotFoundException {

        return matrixCursor;
    }

    @Override
    public Cursor queryChildDocuments(String parentDocumentId, String[] projection,
                                      String sortOrder)
            throws FileNotFoundException {

        return matrixCursor;
    }

    @Override
    public ParcelFileDescriptor openDocument(String documentId, String mode,
                                             CancellationSignal signal)
            throws FileNotFoundException {

        int id;
        try {
            id = Integer.valueOf(documentId);
        } catch (NumberFormatException e) {
            throw new FileNotFoundException("Incorrect document ID " + documentId);
        }

        String filename = "/sdcard/";

        switch (id) {
            case 1:
                filename += "a.txt";
                break;
            case 2:
                filename += "b.txt";
                break;
            case 3:
                filename += "c.txt";
                break;
            default:
                throw new FileNotFoundException("Unknown document ID " + documentId);
        }

        return ParcelFileDescriptor.open(new File(filename),
                ParcelFileDescriptor.MODE_READ_WRITE);
    }
}

注意:
您可以使用 DocumentsContract.DocumentDocumentsContract.Root 中的常量.
我不确定是否需要_id".

更新了示例代码以从/sdcard 打开文档.
添加了读/写外部存储权限.

Updated sample code to open documents from /sdcard.
Added read/write external storage permissions.

<?xml version="1.0" encoding="utf-8"?>
<manifest
    package="com.example.test"
    xmlns:android="http://schemas.android.com/apk/res/android">

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

    <application
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name">

        <provider
            android:name="com.example.test.MyContentProvider"
            android:authorities="com.example.test.document"
            android:enabled="true"
            android:exported="@bool/atLeastKitKat"
            android:grantUriPermissions="true"
            android:permission="android.permission.MANAGE_DOCUMENTS">
            <intent-filter>
                <action android:name="android.content.action.DOCUMENTS_PROVIDER"/>
            </intent-filter>
        </provider>
    </application>

</manifest>

客户端应用

具有空活动的新项目,无权限添加.

Intent openDocumentIntent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
openDocumentIntent.addCategory(Intent.CATEGORY_OPENABLE);
openDocumentIntent.setType("text/plain");
openDocumentIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
                    | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
                    | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
startActivityForResult(openDocumentIntent, 1);

onActivityResult

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    switch (requestCode) {
        case 1: // TODO: Use constant
            if (resultCode == RESULT_OK) {
                if (data == null) return; // TODO: Show error
                Uri uri = data.getData();
                if (uri == null) return; // TODO: Show error
                getContentResolver().takePersistableUriPermission(uri,
                        Intent.FLAG_GRANT_READ_URI_PERMISSION);

                InputStream is = null;
                try {
                    is = getContentResolver().openInputStream(uri);

                    // Just for quick sample (I know what I will read)
                    byte[] buffer = new byte[1024];
                    int read = is.read(buffer);
                    String text = new String(buffer, 0, read);

                    ((TextView) findViewById(R.id.text)).setText(text);
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    if (is != null) try {
                        is.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            break;
    }
}

这篇关于尝试通过 ACTION_OPEN_DOCUMENT 为自定义 DocumentsProvider 获取 PersistableUriPermission() 失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆