标签: storage-access-framework

Android存储访问框架 - 启动自定义文件类型的选择器

我试图在我的应用程序中使用SAF选择器来查找我的自定义文件类型.当文件具有mime类型时,通过调用setType("text/plain")或类似方法,这样做很容易.

如果我想查找所有带有'.blah'扩展名的文件,那么这个电话会是什么样的?

编辑:更多信息:文件类型实际上是具有更改的扩展名的纯文本文件.在文件中,存在一些文本,我解析它从中创建一些数据结构.但是,当用户查找特定扩展名的文件时,我希望他们只查看我的自定义文件,而不是所有文本文件.

android storage-access-framework

5
推荐指数
1
解决办法
502
查看次数

使用存储访问框架创建多个文档

我正在使用类型意图ACTION_CREATE_DOCUMENT将文件从我的应用程序保存到设备上。有没有一种方法可以同时创建多个文档来实现此目的?我正在考虑使用EXTRA_ALLOW_MULTIPLE,但我不知道如何提供我想要创建的文档数量。

感谢您的帮助。

android storage-access-framework

5
推荐指数
0
解决办法
200
查看次数

Android:<provider>里面"不允许使用元素intent-filter"?

http://developer.android.com/guide/topics/providers/document-provider.html#manifest上显示了如何在清单中注册自定义文档提供程序:

<manifest... >
    ...
    <uses-sdk
        android:minSdkVersion="19"
        android:targetSdkVersion="19" />
        ....
        <provider
            android:name="com.example.android.storageprovider.MyCloudProvider"
            android:authorities="com.example.android.storageprovider.documents"
            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>
    </application>

</manifest>
Run Code Online (Sandbox Code Playgroud)

此处需要此<intent-filter>元素,但Android Studio会抱怨:

此处不允许元素intent-filter

并且提供者元素的文档似乎也表明了这一点:

CAN CONTAIN:
<meta-data> 
<grant-uri-permission> 
<path-permission>
Run Code Online (Sandbox Code Playgroud)

这是Android Studio和文档错误还是我错过了什么?

android android-manifest android-xml android-studio storage-access-framework

5
推荐指数
1
解决办法
1532
查看次数

使用SAF访问Google云端硬盘时如何刷新内容

我正在尝试使用以下代码从我的应用程序中的Google驱动器访问PDF文件:

Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("application/pdf");
startActivityForResult(intent, MY_ACTION_OPEN_DOCUMENT);
Run Code Online (Sandbox Code Playgroud)

这是直接从谷歌的文档中获取的.我能够让文件选择器出现.但是有两个问题:

  1. 无法刷新文件选择器的内容.
  2. 在我转到实际的Google云端硬盘应用并在那里执行刷新之前,新添加到Google云端硬盘帐户的文件不会显示.

我想知道我的实现中是否缺少某些内容.我试图搜索网络,并惊奇地发现没有任何相关性.更令人惊讶的是,我遇到了与gmail应用程序相同的问题.

提前致谢.

android storage-access-framework

5
推荐指数
1
解决办法
1096
查看次数

从android中的存储访问框架中选择多个图像后如何保留图像的顺序?

我正在使用 Android 存储访问框架来上传图像选择器。这是我的代码

    Intent.createChooser(new 
    Intent(Intent.ACTION_GET_CONTENT).setType("image/*"), "Choose an image");
    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);

    if (multiple) {
        intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
        intent.putExtra(Intent.EXTRA_INDEX, 0);
    }
Run Code Online (Sandbox Code Playgroud)

当 onActivityResult 被调用时,像下面这样解析它。

final ClipData clipData = data.getClipData();
    int takeFlags = data.getFlags();
    takeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    for(int i = 0; i < clipData.getItemCount(); i++) {
            ClipData.Item item = clipData.getItemAt(i);
            Uri dataUri = item.getUri();
            ....
    }
Run Code Online (Sandbox Code Playgroud)

问题是,当我选择多个图像时,顺序很奇怪。如果我按顺序选择 A、B、C 和 D,它将按顺序返回 B、C、D、A。我发现这是因为所选项目是按文档 ID 排序的。(例如,如果文档 uri 为 content://com.android.providers.media.documents/document/image%3A10473,则按“3A10473”排序)

存储访问框架总是这样工作的。无论用户按顺序选择什么,它都会返回按文档 ID 排序的项目。在得到结果之前我不知道文档 ID 是什么。

保留所选项目的顺序对我来说非常重要。我怎样才能使这成为可能?

谢谢。

android storage-access-framework

5
推荐指数
1
解决办法
1103
查看次数

有没有办法选择使用存储访问框架打开 zip 文件?

我有一个应用程序,允许用户通过 CSV 或包含多个文件的压缩包导出和/或导入批量数据。

目前它使用第三方库(ar.com.daidalos.afiledialog),但我正在尝试迁移到用户更可能熟悉的存储访问框架(并且看起来也更“android-y”) )。当前的库无法使用云端硬盘,这是我想添加的额外功能。

我已经让它工作了,以便导出到两种格式都可以工作。我可以选择一个 CSV 文件来读取:

Intent intent = new Intent();
intent.setAction(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("text/*");
startActivityForResult(intent,4);
Run Code Online (Sandbox Code Playgroud)

但是,当我将类型更改为“application/zip”(或任何更宽松的内容)以使 zip 可选择时,文件选择器会将 zipfile 视为另一个目录并显示其内容而不是选择它。看起来它正在响应 .zip 扩展名,因为当我从文件中删除它时,它会使其变得可选择(如果我无法正确解决此问题,这可能会给我一个解决方法)。

所以问题是,我如何告诉选择器选择zip文件而不是深入其中?我必须使用 zip 文件,因为现有用户已经以他们可能需要读取的格式导出了数据。

android storage-access-framework

5
推荐指数
1
解决办法
1337
查看次数

为 ACTION_OPEN_DOCUMENT 提供默认路径

在我的应用程序中,我想为用户提供一种从 app\xe2\x80\x99s 数据目录中选择文件的方法。这是我的代码:

\n\n
// use ACTION_OPEN_DOCUMENT because ACTION_GET_CONTENT will give us\n// gallery and other stuff we don\xe2\x80\x99t need\nIntent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);\nintent.addCategory(Intent.CATEGORY_OPENABLE);\nUri uri = Uri.parse(getExternalFilesDir(null).getAbsolutePath());\nLog.d(TAG, "Browsing " + uri.toString());\nintent.setDataAndType(uri, "*/*");\n// show the entire internal storage tree\nintent.putExtra("android.content.extra.SHOW_ADVANCED", true);\nstartActivityForResult(intent, 42);\n
Run Code Online (Sandbox Code Playgroud)\n\n

logcat 显示我设置的 URI 是file:///sdcard/Android/data/my.app/files,但文件选择器 UI 默认为共享存储根 ( /sdcard)。

\n\n

以下代码有效(根据文档需要 API 26+,意图可从 API 中获取DocumentsContract.EXTRA_INITIAL_URI):

\n\n
// works only with this intent, at the expense of gallery etc. appearing\nIntent intent = new Intent(Intent.ACTION_GET_CONTENT);\nintent.addCategory(Intent.CATEGORY_OPENABLE);\n\n// apparently we need …
Run Code Online (Sandbox Code Playgroud)

android storage-access-framework

5
推荐指数
1
解决办法
4053
查看次数

当我只能处理文件或文件路径时如何处理 SAF?

背景

在 Android Q 之前,如果我们想要获取有关 APK 文件的信息,我们可以使用WRITE_EXTERNAL_STORAGEREAD_EXTERNAL_STORAGE来访问存储,然后在文件路径上使用PackageManager.getPackageArchiveInfo函数。

类似的情况也存在,例如在压缩文件上使用ZipFile 类,可能还有无数的框架 API 和第三方库。

问题

谷歌最近宣布了对 Android Q 的大量限制。

其中之一称为“范围存储”,当访问设备拥有的所有文件时,它会破坏存储权限。它可以让您处理媒体文件,或者使用非常受限的存储访问框架 ( SAF ),该框架不允许应用程序使用文件 API 和文件路径访问和使用文件。

当Android Q Beta 2发布时,它破坏了很多应用程序,包括谷歌的应用程序。原因是它默认打开,影响所有应用程序,无论它们是否针对 Android Q。

原因是许多应用程序、SDK 和 Android 框架本身 - 都经常使用文件 API。在许多情况下,它们也不支持 InputStream 或 SAF 相关的解决方案。一个例子就是我写的 APK 解析示例 (PackageManager.getPackageArchiveInfo)。

然而,在 Q beta 3 上,情况发生了一些变化,因此目标 Q 的应用程序将具有范围存储,并且有一个标志可以禁用它,但仍然像往常一样使用正常的存储权限和文件 API。遗憾的是,该标志只是暂时的(请阅读此处),因此它推迟了不可避免的事情。

我尝试过的

我已经尝试并发现了接下来的事情:

  1. 使用存储权限确实不允许我读取任何非媒体文件的文件(我想找到 APK 文件)。就好像这些文件不存在一样。

  2. 使用 SAF,我可以找到 APK 文件,并通过一些解决方法来找到其真实路径(链接此处),我注意到文件 API 可以告诉我该文件确实存在,但无法获取其大小,并且框架无法使用其路径getPackageArchiveInfo在这里写过这个

  3. 我尝试创建到该文件的符号链接(链接此处 …

android file storage-access-framework android-10.0 scoped-storage

5
推荐指数
1
解决办法
1705
查看次数

Storage Access Framework的“音频”选项卡“媒体为只读”

尝试获取一个uri通过Storage Access Framework编辑音频文件时,如果用户从“音频”选项卡中进行选择,则显示java.lang.IllegalArgumentException: Media is read-only

SAF非常适合将uri移至sdcard根目录,以及从存储卷本身中选择文件。但是,从SAF Picker的“音频”选项卡中进行选择会返回一个只读uri。当前,我有一条消息告诉用户只能从卷本身中进行选择,但是我的报告显示他们仍然相当频繁地使用它。

这是我当前调用SAF选择器的方式:

Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("audio/mpeg");
startActivityForResult(intent, REQUEST_CODE_SAF_READ_FILE);
Run Code Online (Sandbox Code Playgroud)

根据Android文档,在使用时Intent.CATEGORY_OPENABLE

所有选定的文档将通过持久的读写权限授予返回到调用应用程序。

-这就是为什么出现只读错误是如此令人惊讶的原因。

有什么办法让我获得适当的可写uri?我知道某些提供程序可以是只读的,但是由于该提供程序由文件支持,有没有办法我可以查询只读uri指向的媒体文件的存储量?

我可以从SAF公开的只读uri中获取显示名称和文件大小,但是根据文档

...称为“显示名称”。这是特定于提供程序的,不一定是文件名。

任何建议表示赞赏。

android android-sdcard storage-access-framework

5
推荐指数
0
解决办法
182
查看次数

如何使用存储访问框架android将文件保存到下载文件夹?

我正在从服务器下载文件,并保存到android中的下载文件夹,通过以下方式保存访问文件路径

 Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
Run Code Online (Sandbox Code Playgroud)

在Android Q中已被弃用,所以我必须使用存储访问框架。

 fun downloadFile(url: String, originalFileName: String) {
    mDownloadDisposable.add(
            mRCloudRepository.downloadFile(url)
                    .flatMap(object : Function1<Response<ResponseBody>, Flowable<File>> {
                        override fun invoke(p1: Response<ResponseBody>): Flowable<File> {
                            return Flowable.create({
                                try {
                                    val file = File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).absoluteFile, originalFileName)
                                    val sink = file.sink().buffer() 
                                    sink.writeAll(p1.body()!!.source())
                                    sink.close()
                                    it.onNext(file)
                                    it.onComplete()
                                } catch (e: IOException) {
                                    e.printStackTrace()
                                    it.onError(e)
                                }
                            }, BackpressureStrategy.BUFFER)
                        }

                    })
                    .subscribeOn(mIoScheduler)
                    .observeOn(mUiScheduler)
                    .subscribe(
                            {
                                cancelNotification()
                                val contentIntent: PendingIntent = PendingIntent.getActivity(mContext, NotificationBuilder.NOTIFICATION_DOWNLOAD_ID, getOpenFileIntent(it), PendingIntent.FLAG_CANCEL_CURRENT)
                                NotificationBuilder.showDownloadedNotification(mContext!!, 2, "Downloaded $originalFileName ", "", contentIntent)
                            }, {
                        cancelNotification()
                        it.printStackTrace()
                    }
                    )
    )
}
Run Code Online (Sandbox Code Playgroud)

android kotlin storage-access-framework android-10.0

5
推荐指数
1
解决办法
2131
查看次数