如何使用Android 5.0(Lollipop)新推出的SD卡访问API?

2023-11-29

背景

On 安卓4.4(KitKat),Google 对 SD 卡的访问进行了相当严格的限制。

从 Android Lollipop (5.0) 开始,开发人员可以使用新的 API,要求用户确认允许访问特定文件夹,如此 Google 网上论坛帖子 .

问题

该帖子引导您访问两个网站:

  • https://android.googlesource.com/platform/development/+/android-5.0.0_r2/samples/Vault/src/com/example/android/vault/VaultProvider.java#258

这看起来像一个内部示例(可能稍后会在 API 演示中显示),但很难理解发生了什么。

  • http://developer.android.com/reference/android/support/v4/provider/DocumentFile.html

这是新 API 的官方文档,但它没有提供有关如何使用它的足够详细信息。

它告诉你的是:

如果您确实需要完全访问整个文档子树, 首先启动 ACTION_OPEN_DOCUMENT_TREE 让用户选择一个 目录。然后将生成的 getData() 传递给 fromTreeUri(Context, Uri)开始使用用户选择的树。

当您浏览 DocumentFile 实例树时,您始终可以使用 getUri() 获取代表底层文档的 Uri 该对象,与 openInputStream(Uri) 等一起使用。

要简化运行 KITKAT 或更早版本的设备上的代码,您可以 使用 fromFile(File) 来模拟 DocumentsProvider 的行为。

问题

我对新 API 有几个问题:

  1. 你如何真正使用它?
  2. 根据该帖子,操作系统会记住该应用程序已获得访问文件/文件夹的权限。如何检查是否可以访问文件/文件夹?是否有一个函数可以返回我可以访问的文件/文件夹列表?
  3. Kitkat 上如何处理这个问题?它是支持库的一部分吗?
  4. 操作系统上是否有一个设置屏幕显示哪些应用程序可以访问哪些文件/文件夹?
  5. 如果在同一设备上为多个用户安装一个应用程序,会发生什么情况?
  6. 还有关于这个新 API 的其他文档/教程吗?
  7. 权限可以撤销吗?如果是这样,是否有发送到应用程序的意图?
  8. 是否会在选定的文件夹上递归地请求权限?
  9. 使用该权限是否还可以让用户有机会根据用户的选择进行多项选择?或者应用程序是否需要专门告诉意图允许哪些文件/文件夹?
  10. 有没有办法在模拟器上尝试新的 API?我的意思是,它有 SD 卡分区,但它作为主要外部存储,因此已经授予了对其的所有访问权限(使用简单的权限)。
  11. 当用户更换 SD 卡时会发生什么情况?

很多好问题,让我们深入探讨。:)

你如何使用它?

以下是与 KitKat 中的存储访问框架交互的精彩教程:

https://developer.android.com/guide/topics/providers/document-provider.html#client

与 Lollipop 中的新 API 交互非常相似。要提示用户选择目录树,您可以启动如下意图:

    Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
    startActivityForResult(intent, 42);

然后在 onActivityResult() 中,您可以将用户选择的 Uri 传递给新的 DocumentFile 帮助器类。这是一个简单的示例,列出了所选目录中的文件,然后创建一个新文件:

public void onActivityResult(int requestCode, int resultCode, Intent resultData) {
    if (resultCode == RESULT_OK) {
        Uri treeUri = resultData.getData();
        DocumentFile pickedDir = DocumentFile.fromTreeUri(this, treeUri);

        // List all existing files inside picked directory
        for (DocumentFile file : pickedDir.listFiles()) {
            Log.d(TAG, "Found file " + file.getName() + " with size " + file.length());
        }

        // Create a new file and write into it
        DocumentFile newFile = pickedDir.createFile("text/plain", "My Novel");
        OutputStream out = getContentResolver().openOutputStream(newFile.getUri());
        out.write("A long time ago...".getBytes());
        out.close();
    }
}

返回的 Uri 为DocumentFile.getUri()足够灵活,可以与不同平台的 API 一起使用。例如,您可以使用以下方式共享它Intent.setData() with Intent.FLAG_GRANT_READ_URI_PERMISSION.

如果你想从本机代码访问该 Uri,你可以调用ContentResolver.openFileDescriptor()然后使用ParcelFileDescriptor.getFd() or detachFd()获取传统 POSIX 文件描述符整数。

如何检查是否可以访问文件/文件夹?

默认情况下,通过存储访问框架意图返回的 Uris 是not重新启动后仍然存在。平台“提供”了持久化权限的能力,但如果你想要的话,你仍然需要“获取”权限。在上面的示例中,您可以调用:

    getContentResolver().takePersistableUriPermission(treeUri,
            Intent.FLAG_GRANT_READ_URI_PERMISSION |
            Intent.FLAG_GRANT_WRITE_URI_PERMISSION);

您始终可以通过以下方式找出您的应用程序可以访问的持久授权:ContentResolver.getPersistedUriPermissions()API。如果您不再需要访问持久化的 Uri,可以使用以下命令释放它:ContentResolver.releasePersistableUriPermission().

KitKat 上有这个吗?

不可以,我们无法向旧版本的平台追溯添加新功能。

我可以查看哪些应用程序可以访问文件/文件夹吗?

目前没有 UI 显示这一点,但您可以在“授予的 Uri 权限”部分找到详细信息adb shell dumpsys activity providers output.

如果在同一设备上为多个用户安装一个应用程序,会发生什么情况?

就像所有其他多用户平台功能一样,Uri 权限授予是按每个用户隔离的。也就是说,在两个不同用户下运行的同一应用程序没有重叠或共享的 Uri 权限授予。

权限可以撤销吗?

支持的 DocumentProvider 可以随时撤销权限,例如删除基于云的文档时。发现这些被撤销的权限的最常见方法是当它们从ContentResolver.getPersistedUriPermissions()上文提到的。

每当清除参与授予的任一应用程序的应用程序数据时,权限也会被撤销。

是否会在选定的文件夹上递归地请求权限?

是的,ACTION_OPEN_DOCUMENT_TREE意图使您可以递归访问现有的和新创建的文件和目录。

这是否允许多项选择?

是的,从 KitKat 开始就支持多重选择,你可以通过设置来允许它EXTRA_ALLOW_MULTIPLE当开始你的ACTION_OPEN_DOCUMENT意图。您可以使用Intent.setType() or EXTRA_MIME_TYPES缩小可以选择的文件类型:

http://developer.android.com/reference/android/content/Intent.html#ACTION_OPEN_DOCUMENT

有没有办法在模拟器上尝试新的 API?

是的,主共享存储设备应该出现在选择器中,甚至出现在模拟器上。如果您的应用程序仅使用存储访问框架来访问共享存储,则您不再需要READ/WRITE_EXTERNAL_STORAGE权限at all并可以删除它们或使用android:maxSdkVersion功能仅在较旧的平台版本上请求它们。

当用户更换 SD 卡时会发生什么情况?

当涉及物理介质时,底层介质的UUID(例如FAT序列号)总是被烧录到返回的Uri中。系统使用它来将您连接到用户最初选择的媒体,即使用户在多个插槽之间交换媒体也是如此。

如果用户换入第二张卡,您需要提示才能访问新卡。由于系统会记住每个 UUID 的授权,因此如果用户稍后重新插入原始卡,您将继续拥有先前授予的对原始卡的访问权限。

http://en.wikipedia.org/wiki/Volume_serial_number

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用Android 5.0(Lollipop)新推出的SD卡访问API? 的相关文章

  • 在 Android 上生成 FileDescriptor 而不先打开文件

    在Android中 是否可以直接从字节数组生成FileDescriptor 而不必先打开文件 在 Android 2 2 中 我动态生成 MIDI 文件 然后使用 MediaPlayer 进行播放 我在下面包含了成功执行此操作的 Main
  • 在 Android 模拟器上运行完整的 Android 手机 ROM

    正如标题所说 是否可以在 Android 模拟器中运行完整的 Android 设备 ROM 是的 你可以 但让它 100 工作可能很困难 大多数 ROM 都包含其运行硬件的特定驱动程序 我并不是 100 全力以赴 但可以尝试以下步骤 创建
  • Android Toast 消息不起作用

    我正在通过 Andengine 为 Android 开发游戏 我有 MainActivity 类和 GameScene 类 我在 GameActivity 中使用 Toast 消息 它正在发挥作用 Toast makeText this H
  • 处理 SavedInstances 并恢复活动

    基本上我的应用程序有 2 个活动 说 A 和 B A 启动 B Activity B 播放音乐并且还有通知 情况 1 当视图仍在活动 B 上时 我按主页按钮 然后单击通知 活动 B 将打开 其视图完好无损并播放音乐 因为在清单中我使用 an
  • 如何在 Android 中的 Chrome 或 Firefox 等特定浏览器的 Web 视图中加载应用程序

    我是 Android 新手 我正在做一个应用程序 我需要在平板电脑上的 Web 视图中加载现有的应用程序 在平板电脑中 当我使用 Web 视图加载应用程序时 我的应用程序将加载到默认浏览器中 如何在平板电脑上的 Web 视图中的特定浏览器
  • animation.start() 或animation.startNow() 不会立即开始动画

    我有一个奇怪的问题 有时应该淡出我的控件 ImageButton 的动画不会立即启动 我使用淡出动画来隐藏它 然后在 myListener 的末尾 onAnimationEnd 中 我将新资源作为按钮上的图像 我的应用程序代码中的某处 An
  • 具有自定义厚度的虚线分隔符

    我有一个虚线分隔符
  • 如何使用onDraw(Canvas)获取WebView的位图快照(Android)

    我曾经使用 capturePicture 方法来制作 WebView 的快照 此方法在 API 级别 19 中已弃用 该文档说 使用 onDraw Canvas 获取 WebView 的位图快照 但我真的不知道它是什么意思 你能教我如何解决
  • Android:将图像裁剪为特定尺寸

    我的目的是让用户从图库中选择一张图像 然后进行裁剪活动 但是 我需要将定义裁剪蒙版的矩形锁定到某个尺寸 然后用户只需重新定位它即可显示图像的一部分 关于如何做到这一点有什么想法吗 Thanks T Intent intent new Int
  • Android:将声音保存为铃声/SQLiteConstraintException

    我正在尝试使用 Android 将声音保存为铃声this http www stealthcopter com blog 2010 01 android saving a sound file to sd from resource and
  • 获取Android库中的上下文

    我正在编写一个 Android 应用程序 它的一些功能封装在内部库中 但是 要使此功能发挥作用 库需要一个应用程序上下文的实例 为图书馆提供这种上下文的最佳方式是什么 我看到了一些选择 但没有一个有吸引力 Have my library c
  • Ionic 框架 - Config.xml

    我需要修改 config xml 文件 因此在针对 Android 进行编译时我会获取以下权限
  • 绘制平滑曲线

    我想创建更平滑的曲线 而不仅仅是线角 这是我现在画的图 这是我的代码 case FREEHAND float pts float ptk ptk new float 2 imageMatrix invert inv if mCurrentS
  • 如何告诉 OkHttpClient 忽略缓存并强制从服务器刷新?

    在我的 Android 应用程序中 我将 Retrofit 与 OkHttpClient 结合使用 并启用缓存来访问某些 API 我们的一些 API 有时会返回空数据 我们在应用程序中提供了一个 刷新 按钮 供客户端从特定 API 重新加载
  • 错误膨胀类 android.support.design.widget.NavigationView [启动时崩溃]

    该应用程序应该有一个导航抽屉 可以从左侧拉出并显示各种活动 但是一旦将导航栏添加到 XML Activity homescreen 文档中 应用程序一启动就会崩溃 主屏幕 java package com t99sdevelopment c
  • 如何在 LazyColumn 底部添加空白区域?

    我想添加 LazyColumn 的空白底部 并且我想允许用户调出底部元素 我怎样才能实现这个 Example LazyColumn modifier Modifier fillMaxWidth height 300 dp border 2
  • Recyclerview项目点击涟漪效果[重复]

    这个问题在这里已经有答案了 我正在尝试添加Ripple影响到RecyclerView的项目 我在网上查了一下 但找不到我需要的东西 我努力了android background归因于RecyclerView本身并将其设置为 android
  • 永久删除Android文件

    我发现了一个名为这会从 Android 设备中永久删除文件和文件夹 以便删除的文件无法再恢复 这是我正在谈论的应用程序 但我想知道如何做到这一点 我知道它是用 android studio 制作的 i尝试了常规的删除方式file delet
  • Android ClassNotFoundException:在路径上找不到类

    10 22 15 29 40 897 E AndroidRuntime 2561 FATAL EXCEPTION main 10 22 15 29 40 897 E AndroidRuntime 2561 java lang Runtime
  • 使用部分字符串匹配进行 Firebase 查询[重复]

    这个问题在这里已经有答案了 假设我有一个简单的 firebase 实时数据库结构 其中关键是username其值为userid 现在我想搜索userid by username 如果用户名匹配 这很容易 但如何获得部分匹配的答案 更清楚地说

随机推荐