[英]Persistable URI Permissions for a Document Provider
不确定我正在尝试做的事情是否可行。 我有一个“代理”文档提供者,意思是使用 SAF 为其他内容导出别名的文档提供者。 我有一个对话框片段,它允许用户通过呈现 OPEN_DOCUMENT_TREE 意图、捕获 URI、授予对该 URI 的持久权限,然后将该 URI 传递给文档提供者以呈现该内容来设置别名。
对话片段能够读/写它从意图接收的 URI,但提供者部分不能。 我总是得到的错误是:
java.lang.SecurityException: Permission Denial: reading com.android.externalstorage.ExternalStorageProvider uri
我已经阅读了许多相关问题和人们发布的关于使用这些持久性 READ_URI_PERMISSIONS 的相应回复,并尝试了这些帖子中建议的所有变体。 但我无法让它发挥作用。 我开始认为持久性 URI 权限在提供商中不可用。 是这样吗? 我是否需要让提供者调用意图以便我可以授予这些权限? 也许让提供商调用主要活动来访问内容。 我当然更愿意直接从提供商那里访问内容。 我还没有找到任何地方说明一旦授予持久权限,他们将授予谁? 应用程序的提供者部分是一个单独的过程吗?这就是问题所在吗?
让我提供相关的代码片段:
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.connectedway.connectedsmb">
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<application
...
<activity ...>
...
</activity>
<provider ...
android:permission="android.permission.MANAGE_DOCUMENTS">
</provider>
</application>
</manifest>
获取 URI 的对话片段在主活动中,使用 URI 的代码在提供程序中。
主要活动的对话片段使用以下方式调用 OPEN_DOCUMENT_TREE 意图:
StorageManager sm = (StorageManager)
getContext().getSystemService(Context.STORAGE_SERVICE);
StorageVolume sv = sm.getPrimaryStorageVolume();
Intent intent = sv.createOpenDocumentTreeIntent();
intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
onCreateResultLauncher.launch(intent);
带有 aswsociatd onActivityResult 回调的“onCreateResultLauncher”class 是:
ActivityResultLauncher<Intent> onCreateResultLauncher =
registerForActivityResult
(new ActivityResultContracts.StartActivityForResult(),
new ActivityResultCallback<ActivityResult>() {
@Override
public void onActivityResult(ActivityResult result) {
if (result.getResultCode() == Activity.RESULT_OK) {
Intent data = result.getData();
Uri uri = data.getData() ;
getActivity().grantUriPermission(
getActivity().getPackageName(), uri,
Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION |
Intent.FLAG_GRANT_READ_URI_PERMISSION);
final int takeFlags =
data.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION);
getContext().getContentResolver().takePersistableUriPermission(
uri, takeFlags);
// PASS THE URI OFF TO THE PROVIDER
}
}
}
});
在对话框片段中,我测试了 URI 以查看我是否可以读取它:
DocumentFile file = DocumentFile.fromTreeUri(getContext(), uri);
if (file.canRead())
System.out.println ("Can Read");
我们总是可以阅读。 现在提供者尝试访问 URI,如下所示:
@Override
public Cursor queryDocument(String documentId, String[] projection)
throws FileNotFoundException {
// convert the documentId passed in to a uri. The conversion process
// results in the same URI as that received by the OPEN_DOCUMENT_TREE
// intent invoked and tested above.
DocumentFile file = DocumentFile.fromTreeUri(getContext(), uri);
if (file.canRead())
System.out.println ("Can Read");
提供者没有读取权限。 因此,当提供者最终对 URI 进行查询时,它将失败并出现如上所示的 SecurityException。
问题是:
感谢您阅读这篇文章。
我已经弄明白了。 我不得不改变一些东西,但我遇到的主要问题是我如何构建我传递的 URI。 以下是一些最相关的变化:
该应用程序读取一个 URI,该 URI 希望在属于该应用程序的自定义文档提供程序中公开。 启动时
Intent intent = sv.createOpenDocumentTreeIntent();
intent.addFlags
(Intent.FLAG_GRANT_READ_URI_PERMISSION |
Intent.FLAG_GRANT_WRITE_URI_PERMISSION |
Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION |
Intent.FLAG_GRANT_PREFIX_URI_PERMISSION);
然后启动意图。 用户选择导出到自定义文档提供者的目录后,应用会收到结果回调:
Uri uri = data.getData() ;
ContentResolver cr = getContext().getContentResolver();
cr.takePersistableUriPermission
(uri,
Intent.FLAG_GRANT_READ_URI_PERMISSION |
Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
然后将 URI 传递给为其创建根的文档提供者。 文档提供者不需要明确获取任何权限。 它只需要确保构建正确的 URI。 例如:
Uri treeUri = Uri.parse(otgMap.getPath().getPath());
String externalDocId = // DocId to query
Uri externalUri = DocumentsContract.buildDocumentUriUsingTree
(treeUri, externalDocId);
ContentResolver cr = getContext().getContentResolver();
Cursor cursor = cr.query(externalUri, projection,
null, null, null);
一切都如我所愿。 它只需要在桌子上砸我的头几次。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.