如何将文件路径转换为treeUri

huangapple go评论73阅读模式
英文:

How to convert file path to treeUri

问题

在我的应用程序中,我有一个常规的设置界面,用户可以在他的安卓设备上选择一个视频目录,在该目录中找到的视频将在应用程序中的某个时候播放。现在,当用户通过偏好设置自己进行操作时,我会打开ACTION_OPEN_DOCUMENT_TREE,然后返回的Uri是treeUri,我稍后会在我的视频活动中使用DocumentsContract.buildChildDocumentsUriUsingTree来使用它。这部分非常好,它在运行,一切正常。

然而,由于这个应用程序将在企业中使用,我收到一个请求,IT部门可以提交一个外部的XML文件,我完全控制在应用程序外部目录中,其中包含用户在应用程序本身中可以设置的所有选项。如果存在该文件,则需要在SharedPreferences中实现这些选项。我已经从外部的XML文件中实现了所有的设置,除了视频目录。我想用户可以在XML中提供常规路径,比如<setting key="video_folder">/sdcard/Movies</setting>,然后我在应用程序中解析它,从路径中获取treeUri,并将其保存在SharedPreferences中以备将来使用。是否有任何想法,是否可行,或者是否应该采取其他方法?

我尝试了以下方法:

public static Uri[] getSafUris(Context context, File file) {

    Uri[] uri = new Uri[2];
    String scheme = "content";
    String authority = "com.android.externalstorage.documents";

    // 将文件路径的每个元素分隔开
    // 文件格式:"/storage/XXXX-XXXX/sub-folder1/sub-folder2..../filename"
    // (XXXX-XXXX是外部可移动的编号)
    String[] ele = file.getPath().split(File.separator);
    //  ele[0] = 未使用 (空)
    //  ele[1] = 未使用 (存储名称)
    //  ele[2] = 存储编号
    //  ele[3 到 (n-1)] = 文件夹
    //  ele[n] = 文件名

    // 使用SAF格式构建文件夹字符串
    StringBuilder folders = new StringBuilder();
    if (ele.length > 4) {
        folders.append(ele[3]);
        for (int i = 4; i < ele.length - 1; ++i) folders.append("%2F").append(ele[i]);
    }

    String common = ele[2] + "%3A" + folders.toString();

    // 构建TREE Uri
    Uri.Builder builder = new Uri.Builder();
    builder.scheme(scheme);
    builder.authority(authority);
    builder.encodedPath("/tree/" + common);
    uri[0] = builder.build();

    // 构建DOCUMENT Uri
    builder = new Uri.Builder();
    builder.scheme(scheme);
    builder.authority(authority);
    if (ele.length > 4) common = common + "%2F";
    builder.encodedPath("/document/" + common + file.getName());
    uri[1] = builder.build();

    return uri;
}

但是这给了我以下错误:

Permission Denial: reading com.android.externalstorage.ExternalStorageProvider uri content://com.android.externalstorage.documents/tree/Movies%3A/document/Movies%3A/children from pid=28318, uid=10157 requires that you obtain access using ACTION_OPEN_DOCUMENT or related APIs
英文:

In my application i have a regular Settings, where user can choose a video directory on his android device, and videos found in that directory will play at some point in the application. Now, when user himself is doing that via Preferences, i am opening ACTION_OPEN_DOCUMENT_TREE, and Uri returned is treeUri, that i am later using in my Video Activity with DocumentsContract.buildChildDocumentsUriUsingTree. This part is completely fine, it's working and all is OK.

However, since this application is going to be used in enterprises, i have a request, that IT department can submit an external xml file that i am completely controlling in application external directory, with all options that you as a user can set in the application itself, and if that file exists, those options need to be implemented in SharedPreferences. I got all settings to be implemented from that external xml file, apart that video directory. I was thinking that user can give regular path in the xml, like &lt;setting key=&quot;video_folder&quot;&gt;/sdcard/Movies&lt;/setting&gt;, and then i parse that in the application, get treeUri from path, and save it in SharedPreferences for later use. Any ideas if this is doable, or this should have some other approach?
I've tried this method below:

public static Uri[] getSafUris (Context context, File file) {
Uri[] uri = new Uri[2];
String scheme = &quot;content&quot;;
String authority = &quot;com.android.externalstorage.documents&quot;;
// Separate each element of the File path
// File format: &quot;/storage/XXXX-XXXX/sub-folder1/sub-folder2..../filename&quot;
// (XXXX-XXXX is external removable number
String[] ele = file.getPath().split(File.separator);
//  ele[0] = not used (empty)
//  ele[1] = not used (storage name)
//  ele[2] = storage number
//  ele[3 to (n-1)] = folders
//  ele[n] = file name
// Construct folders strings using SAF format
StringBuilder folders = new StringBuilder();
if (ele.length &gt; 4) {
folders.append(ele[3]);
for (int i = 4; i &lt; ele.length - 1; ++i) folders.append(&quot;%2F&quot;).append(ele[i]);
}
String common = ele[2] + &quot;%3A&quot; + folders.toString();
// Construct TREE Uri
Uri.Builder builder = new Uri.Builder();
builder.scheme(scheme);
builder.authority(authority);
builder.encodedPath(&quot;/tree/&quot; + common);
uri[0] = builder.build();
// Construct DOCUMENT Uri
builder = new Uri.Builder();
builder.scheme(scheme);
builder.authority(authority);
if (ele.length &gt; 4) common = common + &quot;%2F&quot;;
builder.encodedPath(&quot;/document/&quot; + common + file.getName());
uri[1] = builder.build();
return uri;
}

but that gives me:

Permission Denial: reading com.android.externalstorage.ExternalStorageProvider uri content://com.android.externalstorage.documents/tree/Movies%3A/document/Movies%3A/children from pid=28318, uid=10157 requires that you obtain access using ACTION_OPEN_DOCUMENT or related APIs

答案1

得分: 1

我不得不完全重新排列播放视频的逻辑,以从常规的 file:// URI 读取视频,以绕过 SAF。简而言之,我的问题是,如果您没有从 ACTION_OPEN_DOCUMENT、ACTION_OPEN_DOCUMENT_TREE 和类似的 API 中获取树状 URI,是否有任何可能的方式可以获取此类树状 URI 的权限。据我所知,这是不可能的(甚至不是通过任何形式的运行时权限呈现给用户)。如果还有其他人认为存在这样的可能性,请告知我。

英文:

I had to completely rearrange logic for playing videos, to read them from regular file:// uri's, in order to bypass SAF. In short, my question was, if you don't obtain tree URI from ACTION_OPEN_DOCUMENT, ACTION_OPEN_DOCUMENT_TREE, and similar API's, is there any way possible, to obtain a permission for such tree URI. As far as i could tell, that is not possible (not even with any kind of runtime permission presented to the user). If anyone else believes that there is such a possibility, please, let me know.

huangapple
  • 本文由 发表于 2020年9月10日 18:38:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/63827910.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定