尝试通过 ACTION_OPEN_DOCUMENT 为自定义 DocumentsProvider 获取 PersistableUriPermission() 失败 [英] Trying to takePersistableUriPermission() fails for custom DocumentsProvider via ACTION_OPEN_DOCUMENT
问题描述
我正在尝试编写一个自定义 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.Document 和 DocumentsContract.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屋!