我不确定我尝试做的事情是否可行。我有一个“代理”文档提供程序,它是指使用SAF导出其他内容别名的文档提供程序。我有一个对话框片段,它允许用户通过以下方式设置别名:显示OPEN_DOCUMENT_TREE Intent、捕获URI、授予对该URI的持久权限,然后将该URI传递给文档提供程序以显示该内容。
对话框片段可以在从Intent接收的URI上读/写,但提供程序部分不能。我总是得到的错误是:
java.lang.SecurityException: Permission Denial: reading com.android.externalstorage.ExternalStorageProvider uri
我已经阅读了很多关于使用这些持久性READ_URI_PERMISSIONS的相关问题和回复,并尝试了那些帖子中建议的所有变体。但是我无法让它工作。我开始认为持久性URI权限在提供者中是不可用的。是这样吗?我需要让提供者调用一个Intent来授予这些权限吗?也许让提供者调用主活动来访问内容。我当然更愿意直接从提供者访问内容。我还没有找到任何地方说明一旦授予持久权限,它们将被授予谁?应用程序的提供者部分是一个单独的进程吗?这是问题所在吗?
让我提供相关的代码片段:
Android信息清单. 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的对话片段位于主Activity中,而使用URI的代码位于提供程序中。
主Activity的对话框片段使用以下命令调用OPEN_DOCUMENT_TREE Intent:
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”类为:
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。
问题是:
- 这是否在体系结构上得到支持?
- 如果是这样的话,有人能在上面的片段中看到任何明显的错误吗?
- 如果没有,谁能想出一个方法来解决架构限制?
感谢您阅读全文。
1条答案
按热度按时间pdsfdshx1#
我已经能够解决这个问题了。我不得不改变一些东西,但主要的问题是我如何构建我传递的URI。下面是一些最相关的改变:
应用程序读入要在应用程序的自定义文档提供程序中公开的URI。启动
然后启动Intent。在用户选择要导出到自定义文档提供程序的目录后,应用将收到结果回调:
然后,URI被传递给文档提供程序,文档提供程序为其创建一个根。文档提供程序不需要显式地获取任何权限。它只需要确保生成正确的URI。例如:
这一切都像我希望的那样工作。它只需要把我的头撞在table上几次。