我正在使用此处指定的新Kitkat存储访问框架(SAF):https: //developer.android.com/guide/topics/providers/document-provider.html
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("image/*");
startActivityForResult(intent, 0);
这与示例代码相同,但图像过滤器不起作用.S5或Note3上没有显示任何内容.视频(视频/*)也是如此.我也尝试了不同的模式,如/无效.
这看起来像是一个应该由他们解决的三星问题,我只是想知道是否有人知道解决方法.
android android-4.4-kitkat samsung-touchwiz storage-access-framework
当用户点击谷歌硬盘中的"发送文件"按钮并选择我的应用程序.我想获取该文件的文件路径,然后允许用户将其上传到其他位置.
我为kitkat手机检查了这些类似的SO帖子:从URI,Android KitKat新的存储访问框架获取真实路径
然而,解决方案似乎不再适用于Lollipop设备.
问题似乎是MediaStore.MediaColumns.DATA在ContentResolver上运行查询时返回null.
https://code.google.com/p/android/issues/detail?id=63651
您应该使用ContentResolver.openFileDescriptor()而不是尝试获取原始文件系统路径."_data"列不是CATEGORY_OPENABLE合同的一部分,因此不需要Drive返回它.
我已经阅读了CommonsWare的这篇博文,其中建议我"尝试直接使用Uri直接使用ContentResolver",这是我不明白的.如何直接在ContentResolvers中使用URI?
但是,我仍然不清楚如何最好地处理这些类型的URI.
我能找到的最佳解决方案是调用openFileDescriptor,然后将文件流复制到一个新文件中,然后将该新文件路径传递给我的上传活动.
 private static String getDriveFileAbsolutePath(Activity context, Uri uri) {
    if (uri == null) return null;
    ContentResolver resolver = context.getContentResolver();
    FileInputStream input = null;
    FileOutputStream output = null;
    String outputFilePath = new File(context.getCacheDir(), fileName).getAbsolutePath();
    try {
        ParcelFileDescriptor pfd = resolver.openFileDescriptor(uri, "r");
        FileDescriptor fd = pfd.getFileDescriptor();
        input = new FileInputStream(fd);
        output = new FileOutputStream(outputFilePath);
        int read = 0;
        byte[] bytes = new byte[4096];
        while ((read …android android-intent google-drive-api storage-access-framework
我正在尝试编写一个自定义规则DocumentsProvider,以允许其他应用程序对其提供的Uris拥有持久权限
我有一个DocumentsProvider我声明AndroidManufest.xml如下
<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权限设置
<uses-permission android:name="android.permission.MANAGE_DOCUMENTS" />
(显然,这不是必需的,但是添加/删除它也没有关系)。然后,当我打开ACTION_OPEN_DOCUMENT选择器用户界面时,可以看到我的提供者
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()我的App 的方法中,我可以通过我DocumentsProvider从Uri那里获取,成功打开我提供的文件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
如果我从Google驱动器中选取文件,或者在选择器UI中选择下载提供程序,则以这种方式获得许可就可以了。所以我认为问题出在我的提供者中。
尽管我进行了指定,为什么没有创建许可授予android:grantUriPermissions="true"?
如何说服Android为我创建这样的权限授予?
毕竟我不认为自己可以做,因为我不知道UID打开选择器UI的过程,或者至少我不知道该怎么做。
permissions android android-contentprovider storage-access-framework
我正在使用android的存储访问框架(SAF)与文档进行交互。我已经能够找到/读取/写入文档,没有任何麻烦,但是当我尝试对Google Drive文档使用DocumentsContract#renameDocument()重命名时遇到了问题。我发布的代码与内部存储中的文件配合正常。
为了使事情变得容易,我制作了一个示例应用程序并将其推送到github。您可以在以下位置找到该代码:https : //github.com/scottTomaszewski/SafExample,我与文档本身的交互都在此类https://github.com/scottTomaszewski/SafExample/blob/master/app/src/main中/java/com/example/safexample/SafDocument.java
重命名通过Google Drive的SAF界面获取的Uri时出现的错误是这样的(更易于阅读的版本:https : //github.com/scottTomaszewski/SafExample/blob/master/README.md)
03-03 14:10:41.529 29069-29069/com.example.safexample W/grok: java.io.FileNotFoundException
        at android.database.DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(DatabaseUtils.java:144)
        at android.content.ContentProviderProxy.openTypedAssetFile(ContentProviderNative.java:692)
        at android.content.ContentResolver.openTypedAssetFileDescriptor(ContentResolver.java:1103)
        at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:942)
        at android.content.ContentResolver.openInputStream(ContentResolver.java:662)
        at com.example.safexample.SafDocument$2.openStream(SafDocument.java:66)
        at com.google.common.io.ByteSource$AsCharSource.openStream(ByteSource.java:420)
        at com.google.common.io.CharSource.read(CharSource.java:147)
        at com.example.safexample.SafDocument.read(SafDocument.java:73)
        at com.example.safexample.MainActivity.onOptionsItemSelected(MainActivity.java:61)
        at android.app.Activity.onMenuItemSelected(Activity.java:2912)
        at android.support.v4.app.FragmentActivity.onMenuItemSelected(FragmentActivity.java:404)
        at android.support.v7.app.AppCompatActivity.onMenuItemSelected(AppCompatActivity.java:167)
        at android.support.v7.view.WindowCallbackWrapper.onMenuItemSelected(WindowCallbackWrapper.java:100)
        at android.support.v7.view.WindowCallbackWrapper.onMenuItemSelected(WindowCallbackWrapper.java:100)
        at android.support.v7.app.ToolbarActionBar$2.onMenuItemClick(ToolbarActionBar.java:69)
        at android.support.v7.widget.Toolbar$1.onMenuItemClick(Toolbar.java:169)
        at android.support.v7.widget.ActionMenuView$MenuBuilderCallback.onMenuItemSelected(ActionMenuView.java:760)
        at android.support.v7.view.menu.MenuBuilder.dispatchMenuItemSelected(MenuBuilder.java:811)
        at android.support.v7.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:152)
        at android.support.v7.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:958)
        at android.support.v7.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:948)
        at android.support.v7.widget.ActionMenuView.invokeItem(ActionMenuView.java:618)
        at android.support.v7.view.menu.ActionMenuItemView.onClick(ActionMenuItemView.java:139)
        at android.view.View.performClick(View.java:5201)
        at android.view.View$PerformClick.run(View.java:21163)
        at android.os.Handler.handleCallback(Handler.java:746)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:148)
        at android.app.ActivityThread.main(ActivityThread.java:5443)
        at …假设一个 Uri 可以是以下之一:
在这两种情况下,它都指目录下的文件。
有没有一种直接的方法来获取其父目录的 Uri 而不尝试两者中的每一个来查看哪个有效?
[编辑]:以下是 SAF 的示例:
乌里:
content://com.android.externalstorage.documents/tree/0000-0000%3Atest/document/0000-0000%3Atest%2Ffoo%2FMovies%2FRR%20parking%20lot%20a%202018_02_22_075101.mp4
获取路径():
/tree/0000-0000:test/document/0000-0000:test/foo/Movies/RR 停车场 a 2018_02_22_075101.mp4
getPathSegments():
0 = "tree"
1 = "0000-0000:test" 
2 = "document"
3 = "0000-0000:test/foo/Movies/RR parking lot a 2018_02_22_075101.mp4"
父文件夹应该是 test/foo/Movies。
以下是常规文件的示例:
乌里:
file:///storage/emulated/0/foo/Movies/RR%20parking%20lot%20a%202018_02_22_081351.mp4
获取路径():
/storage/emulated/0/foo/Movies/RR 停车场 a 2018_02_22_081351.mp4
getPathSegments():
0 = "storage"
1 = "emulated"
2 = "0"
3 = "foo"
4 = "Movies"
5 = "RR parking lot a 2018_02_22_081351.mp4"
android.os.FileObserver需要一个java.io.File功能。但是在 Android 10 中,谷歌限制了对著名的“存储访问框架”的访问,但您的应用程序私有目录除外。由于通过java.io.File中断和渲染访问任何内容FileObserver useless unless you intend to use it in your apps private directory. However I want to get noticed when something is changed in a certain directory on external storage. I would also like to avoid periodically checking for changes.
我尝试使用ContentResolver.registerContentObserver(uri,notifyForDescendants,observer)该方法并遇到了一些问题:
Uri到目前为止我插入的每一个都被接受了Uri不工作Uri真正有效我所做的唯一工作是以下方法:
// works, but returns all changes to the external storage
contentResolver.registerContentObserver(MediaStore.Files.getContentUri("external"), true, contentObserver)
不幸的是,这包括所有外部存储,并且仅Uri在发生更改时返回 Media 。content://media/external/file/67226 …
我正在尝试创建许多文件,作为用户的一项功能。例如,我可能会编写一个应用程序,为他们过去几周听过的每首歌曲创建一个文件(例如,带有歌词的文本文件)。我不能让用户为我生成的每个文件选择目录和文件名,这需要他们几个小时。用户应该可以从其他应用程序访问这些文档。
在 Android 11 中,存储访问框架似乎没有用处。我注意到最初有两个有趣的选项:
WRITE_EXTERNAL_STORAGE. 不幸的是,此权限在 Android 11 上被拒绝。因此,我无法使用此处发布的解决方案。ACTION_OPEN_DOCUMENT_TREE)访问目录以访问目录,但我无法将文件写入此目录。(我明白了FileNotFoundException,因为这不是普通路径,而是树路径。)我想在我的情况下,我需要沿着“管理存储设备上的所有文件”的路线走下去,如此处所述,这涉及使用ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION. 我宁愿不请求读取整个驱动器的权限,也不想让用户进入设置应用程序以授予权限。写入文件不应该需要任何权限...
您将如何为用户保存许多(非媒体)文件?
我将创建一个用于从 Internet 访问文件的应用程序。我不想实现 UI,而是让它们从其他文件管理器中可见。因此,我选择实现一个文档提供程序。我做到了。在接下来的图片中,您可以看到我打开“文件”应用程序,找到“我的文档提供程序”并可以访问其文件。
然而,它是一个模拟器。当我尝试在物理设备上使用该应用程序时,我发现我无法查看文档提供者。我使用小米红米 Note 5 Pro(android 9.0),没有“文件”应用程序。我测试了 Google Play 中排名前 20 的文件管理器,甚至 MIUI 内置的文件资源管理器,但它们都不能向我显示我的“我的文档提供程序”。
仅当尝试从 Gmail 应用程序附加文档时,我才设法看到我的文档提供程序。但这不是我需要的。
问题:
最后我找到了解决方案。据我了解,标准应用程序“文件”内置于任何设备中。然而,制造商可能“隐藏”这个应用程序并提供一些模拟。MIUI 上有一个“文件管理器”。在许多三星设备以及 Pixel 2 XL 上,它是“Google 文件”应用程序。他们都没有看到文档提供者。只有“文件”应用程序可以。
当您使用 SAF 时,“文件”应用程序仍然可以作为一个选项进行访问(例如使用 ACTION_OPEN_DOCUMENT 启动 Intent)。但您仍然无法独立启动该应用程序。不过,您可以从 Google Play 下载“文件快捷方式”。打开它时,您可以选择一个应将“文件快捷方式”作为快捷方式的应用程序。我选择“文件”应用程序,一切正常(直到我选中“记住我的选择”选项才起作用)。在 Pixel 2 和 Redmi Note 5 上,我都可以看到我的文档提供程序。这是一个好消息,因为我不必浪费时间来创建 UI!
PS 请注意,我上面描述的内容并非来自可靠来源。根据我的观察和理解,我使用了“隐藏应用程序”一词以及在任何设备上预安装“文件”的事实。
PPS 另外,我发现在 Pixel 2 上的“Google 文件”应用程序中还有一种打开“文件”的方法:浏览 -> 其他存储 -> 系统痕迹。由于某种原因,红米 Note 5 上没有“其他存储”按钮。
你好我的伙伴stackoverflows,
我正在编写一个应用程序,我在其中实现了一个处理共享意图的Activity.到目前为止它工作正常但在测试期间我遇到了Quickoffice(Android 4.4,KitKat)的问题,因为它返回一个URI,我无法从中获取文件名.我还尝试与其他应用程序共享,如Dropbox,它在那里工作.
我从Qickoffice应用程序获得的确切URI:
content://com.quickoffice.android.quickcommon.FileContentProvider/5cmeDeeatcdv8IFyu-bEr2w1jSHrvPmCzXGb_VvZulMBErE5Tmfd_5P5kckE68LaEYDVSp3q5r19%0A4sOkpYCEM_VqK6Y%3D%0A
这是我先使用的代码:
public String getRealPathFromURI(Uri contentUri) {
    Cursor cursor = null;
    try {
        String[] proj = {MediaStore.Images.Media.DATA}; // = "_data"
        ContentResolver cr = getContentResolver(); 
        cursor = cr.query(contentUri, proj, null, null, null); // <--EXCEPTION
        int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
        cursor.moveToFirst();
        return cursor.getString(column_index);
    } catch (Exception exception) {
        Log.d("clixend", "Exception: " + exception);
        Toast.makeText(this, "Exception: " + exception, Toast.LENGTH_LONG).show();
    } finally {
        if (cursor != null) {
            cursor.close();
        }
    }
    return null;
}
我收到以下错误的地方:
09-23 16:54:17.664  32331-32341/? E/DatabaseUtils? Writing …如果我调用  DocumentFile.fromTreeUri()主目录并列出其内容,它会DocumentFile按预期返回与目录中包含的文件夹和文件相关的所有对象,但是当我尝试调用DocumentFile.fromTreeUri()其中Uri的文件夹之一时DocumentFile,而不是返回所有DocumentFile相关对象按预期返回到子目录中包含的文件夹和文件,它实际上返回与其根目录上的调用完全相同的内容Uri
例如,我有一个包含 3 个文件的下载文件夹和一个包含 2 个文件的子文件夹,其结构如下
Download
-->file1
-->file2
-->file3
-->Subfolder
----->subfile1
----->subfile2
如果我调用  通过意图回调选择的DocumentFile.fromTreeUri().listFiles()下载文件夹
它会返回我Uricontent://com.android.externalstorage.documents/tree/primary%3ADownload
-->file1
-->file2
-->file3
-->Subfolder
到目前为止一切都很好,现在如果我尝试获取Uri与调用DocumentFile相关的对象,我得到的显然看起来是正确的,但是如果我调用它,当我列出它的内容时我会再次得到Subfoldermysub.getUri()content://com.android.externalstorage.documents/tree/primary%3ADownload/document/primary%3ADownload%2FSubfolderDocumentFile.fromTreeUri().listFiles()
-->file1
-->file2
-->file3
-->Subfolder
与主下载文件夹 Uri 上的调用完全相同。如果我直接打电话,也会发生同样的情况mysub.listFiles()。这看起来是一个完全不合逻辑的设计。
我怎样才能真正从与其父DocumentFile文件夹相关的对象中正确获取与子文件夹相关的对象DocumentFile,以便子文件夹DocumentFile可以列出其内容而不是其父文件夹的内容?
android ×9
android-10.0 ×2
android-11 ×1
android-file ×1
fileobserver ×1
google-docs ×1
java ×1
permissions ×1