问题标签 [scoped-storage]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
2 回答
1144 浏览

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

背景

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

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

问题

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

其中之一称为Scoped Storage,它在访问设备拥有的所有文件时会破坏存储权限。它允许您处理媒体文件,或使用非常受限的存储访问框架 ( SAF ),它不允许应用程序使用 File API 和文件路径访问和使用文件。

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

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

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

我试过的

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

  1. 使用存储权限确实没有让我读取任何不是媒体文件的文件(我想查找 APK 文件)。就好像文件不存在一样。

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

  3. 我试图对文件建立一个符号链接(链接在这里),然后从符号链接中读取。它没有帮助。

  4. 对于解析APK文件的情况,我尝试寻找替代解决方案。我找到了 2 个使用 File 类(此处此处)处理 APK 的 github 存储库,以及一个使用 InputStream 代替(此处)的存储库。遗憾的是,使用 InputStream 的那个非常旧,缺少各种功能(例如获取应用程序的名称和图标)并且不会很快更新。此外,拥有一个库需要维护以跟上未来的 Android 版本,否则将来可能会出现问题,甚至崩溃。

问题

  1. 一般来说,有没有办法在使用 SAF 时仍然使用 File API?我不是在谈论根解决方案或只是将文件复制到其他地方。我说的是更可靠的解决方案。

  2. 对于APK解析的情况,有没有办法解决框架只提供文件路径作为参数的问题?也许有任何解决方法或使用 InputStream 的方法?

0 投票
2 回答
5997 浏览

android - 如何在不使用文件或文件路径的情况下获取文件系统(不仅仅是已安装的)中 APK 文件的信息?

背景

我的应用程序(这里)可以在整个文件系统(不仅仅是已安装的应用程序)中搜索 APK 文件,显示每个应用程序的信息,允许删除、共享、安装...

作为 Android Q 范围存储功能的一部分,Google 宣布 SAF(存储访问框架)将取代正常的存储权限。这意味着即使您尝试使用存储权限,它也只会授予对特定类型文件的访问权限,以便使用或完全沙盒化文件和文件路径(写在这里)。

这意味着很多框架将需要依赖 SAF 而不是 File 和 file-path。

问题

其中之一是packageManager.getPackageArchiveInfo,它给定一个文件路径,返回 PackageInfo,我可以得到各种信息:

  1. 名称(在当前配置上),又名“标签”,使用packageInfo.applicationInfo.loadLabel(packageManager). 这基于设备的当前配置(区域设置等...)
  2. 包名,使用packageInfo.packageName
  3. 版本代码,使用packageInfo.versionCodeor packageInfo.longVersionCode
  4. 版本号,使用packageInfo.versionName
  5. 应用程序图标,使用各种方式,基于当前配置(密度等...):

一个。BitmapFactory.decodeResource(packageManager.getResourcesForApplication(applicationInfo),packageInfo.applicationInfo.icon, bitmapOptions)

湾。如果安装,AppCompatResources.getDrawable(createPackageContext(packageInfo.packageName, 0), packageInfo.applicationInfo.icon )

C。ResourcesCompat.getDrawable(packageManager.getResourcesForApplication(applicationInfo), packageInfo.applicationInfo.icon, null)

它返回给你的还有很多,还有很多是可选的,但我认为这些是关于 APK 文件的基本细节。

我希望谷歌会为此提供一个很好的替代方案(在此处此处请求),因为目前我找不到任何好的解决方案。

我试过的

使用从 SAF 获得的 Uri 并从中获得 InputStream 非常容易:

但是现在你被卡住了,因为我见过的所有框架都需要一个文件或文件路径。

我尝试使用 Android 框架找到任何替代方案,但我找不到任何替代方案。不仅如此,我发现的所有图书馆也不提供这样的东西。

编辑:发现我看过的库之一(在这里)-有点可以选择仅使用流来解析 APK 文件(包括其资源),但是:

  1. 原始代码使用文件路径(类为ApkFile),比使用 Android 框架正常解析要多出约 10 倍。原因可能是它解析了所有可能的或接近它的东西。另一种ByteArrayApkFile解析方式(class is )是使用包含整个 APK 内容的字节数组。如果您只需要其中的一小部分,则阅读整个文件非常浪费。另外,这种方式可能会占用大量内存,而且正如我测试过的,它确实可以达到 OOM,因为我必须将整个 APK 内容放入一个字节数组中。

  2. 我发现它有时无法解析框架可以解析的 APK 文件(此处)。也许它很快就会被修复。

  3. 我试图只提取 APK 文件的基本解析,它确实有效,但在速度方面甚至更糟(这里)。从其中一个类(称为AbstractApkFile)中获取代码。所以从文件中,我得到了不应该占用太多内存的清单文件,我使用库单独解析它。这里:

    /li>

所以,就目前而言,这不是一个好的解决方案,因为它很慢,而且因为获取应用程序名称和图标需要我提供整个 APK 数据,这可能导致 OOM。那是除非也许有办法优化库的代码......

问题

  1. 如何从 APK 文件的 InputStream 中获取 APK 信息(至少是我在列表中提到的内容)?

  2. 如果在正常框架上没有替代方案,我在哪里可以找到这样的东西可以允许它?是否有任何流行的库为 Android 提供它?

注意:当然我可以将 InputStream 复制到一个文件中然后使用它,但这非常低效,因为我必须为找到的每个文件都这样做,而且这样做会浪费空间和时间,因为文件已经存在.


编辑:在找到解决方法(heregetPackageArchiveInfo )以通过(on )获取有关 APK 的非常基本信息后"/proc/self/fd/" + fileDescriptor.fd,我仍然找不到任何方法来获取app-labelapp-icon。请,如果有人知道如何单独使用 SAW(没有存储权限),请告诉我。

我已经为此设置了新的赏金,希望有人也能找到一些解决方法。


由于我发现了一个新发现,我提出了新的赏金:一个名为“ Solid Explorer ”的应用程序以 API 29 为目标,但使用 SAF 它仍然可以显示 APK 信息,包括应用程序名称和图标。

即使在最初针对 API 29 时,它也没有显示任何有关 APK 文件的信息,包括图标和应用程序名称。

尝试了一个名为“插件检测器”的应用程序,我找不到该应用程序用于此目的的任何特殊库,这意味着可以使用普通框架来完成它,而无需非常特殊的技巧。

编辑:关于“Solid Explorer”,似乎他们只使用“requestLegacyExternalStorage”的特殊标志,所以他们不单独使用 SAF,而是使用普通框架。

所以,如果有人知道如何单独使用 SAF 获取应用程序名称和应用程序图标(并且可以在工作示例中显示它),请告诉我。


编辑:似乎APK-parser 库可以很好地获取应用程序名称和图标,但对于图标它有一些问题:

  1. 限定词有点错误,你需要找到最适合你的情况。
  2. 对于自适应图标,它可以获得 PNG而不是 VectorDrawable。
  3. 对于 VectorDrawable,它只获取byte-array。不知道如何将其转换为真正的 VectorDrawable。
0 投票
2 回答
1337 浏览

android - FFmpeg:无法在 Android Q 上使用文件描述符进行搜索

鉴于公共文件路径在具有范围存储的 Android Q 中通常不可用,我试图弄清楚如何使我的 FFmpeg 音频解码器与文件描述符一起工作,而不会将文件复制到我的应用程序的私有目录中。

我们可以使用Android Q 隐私更改中描述的方法轻松获取文件描述符,并且可以使用管道协议打开文件描述符,如将本机 fd int 从可打开的 URI 传递给 FFMPEG 中所述。但是,av_seek_frame使用 的持续时间成员无法搜索结果,并且持续时间也不可用AVFormatContext

有没有办法使用 FFmpeg 查找文件描述符并检索持续时间?

0 投票
5 回答
27187 浏览

android - Android Q (10) 请求访问所有存储的权限。范围存储

在 Android 10 中,需要访问存储的应用程序需要请求访问具体路径的权限。但是文件资源管理器等应用程序可以请求访问根存储的权限,并获得对所有存储的读/写权限。这就是我想要做的。

根据Android,我们必须ACTION_OPEN_DOCUMENT_TREE为此使用。我遇到的问题是一切似乎都是正确的,但没有授予应用程序权限。

在这里,用户可以看到 Android 文件树,并在选择主存储的情况下,单击以授予权限。“它将允许 - 应用程序名称 - 完全访问当前存储在此位置下的所有文件,以及存储在此处的任何未来内容”-> 允许

然后:

日志:

takePersistableUriPermission: content://com.android.externalstorage.documents/tree/primary%3A

然后该应用程序仍然没有访问root的权限。

打开失败:EACCES(权限被拒绝)

我当然有:

由用户授予。

0 投票
2 回答
960 浏览

android - Android 10 MediaStore update image RecoverableSecurityException

I'm in the process of updating an Android app to scoped storage and the problem I'm facing now is that on my app users can select a set of images to be processed automatically (and they can choose to overwrite the original image).

The problem is, when I'm trying to overwrite the original image from its Uri, Android throws a RecoverableSecurityException, which displays a dialog to the user asking consent to modify that photo.

What I want to know is if it's possible to instead show a permission dialog but for the whole set of, for example, 10 images at once, instead of having to show a dialog for each one.

I tried using the applyBatch method of ContentResolver (the code below simulates the issue), but the consent dialog only shows for the first updated image.

Any ideas on this? Thank you.

0 投票
2 回答
2172 浏览

android - 如何解决 Android 10 的存储问题

由于Android在文件访问方面不同主要版本之间非常不一致,我感到有些失落。我尝试尽可能简单地描述问题:

My Company 使用商业原生 DRM 来保护我们提供的其他原生库。我们有一个 Licensing App,它调用了一些 Voodoo,最终得到了 /sdcard/companyname/LicenseContainer/ 中的 Licensing 文件。其他受保护的应用程序在本机代码中查看此目录,检查用户是否拥有有效的许可证。

然而,Android 10 更新完全使此工作流程无效,因为它仅提供scoped storage access. 我们可以使用Storage Manager授予访问权限来解决问题,不幸的是,现在也已弃用。

所以我现在的问题是:一个应用程序如何将文件保存到 /sdcard/FOLDER 上的某个位置

  1. 删除应用时未删除
  2. 其他应用程序可以在本机代码中访问

我对所有可能的解决方案(SAF、FileProvider 等)有点不知所措,它们经常调用一个应用程序向另一个应用程序授予权限。但是这些文件应该可以在没有安装的第一个应用程序的情况下访问。

我知道必须有一个解决方案,因为最近的 FileManagers(即Files by Google)可以访问整个/sdcard/目录。

什么是最简单,面向未来的路线,无需调用“黑客”之类的android:requestLegacyExternalStorage="true"

0 投票
1 回答
1006 浏览

mediastore - SDK-29 上的 MediaScanner 和 ScopedStorage

我正在开发的应用程序使用 aFile作为照片捕获的目标。这是由用户使用选择相机应用程序在外部执行的Intent(ACTION_IMAGE_CAPTURE)。自从将 build 和 target-sdk 升级到 29 后,出现了一系列问题,首先是限制自由访问外部存储上的文件。第一个更改是使用应用程序的私有缓存目录之一,例如:

File.createTempFile("tempImage", ".jpg", context.cacheDir)

或应用程序私有外部存储目录:

File.createTempFile("tempImage", ".jpg", context.getExternalFilesDir(Environment.DIRECTORY_PICTURES))

结合 FileProvider 访问file_paths.xml,例如:

这些在正确配置后现在运行良好,但是实现了“保存到图库”功能,例如:通知其他应用程序新图像不再适用于运行 Android-10 的设备

这种方法应该有效,但不管原始图像保存在哪里(私有应用程序目录、缓存目录、外部私有)

Android 的 SDK-29 中是否有新的限制需要更改 MediaScanning,特别是与扫描(可能)私有图像文件的方式有关?我注意到MediaScanner方法大多期望String路径而不是 URI,所以这让我认为新的限制不适用于它,因为它是一个系统组件。

0 投票
1 回答
3002 浏览

android - Scoped Storage - 下载文件夹访问

我的目标是 android 10,我不使用android:requestLegacyExternalStorage. 我使用通过以下DownloadManager方式下载到下载文件夹:request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName). 我收听下载完成广播,提取 uri ( file:///storage/emulated/0/Download/<name>.pdf) 并通过 .pdf 在 pdf 阅读器中打开它FileProvider。它有效......为什么?自android 10和范围存储以来,它不应该不起作用吗?为什么允许我访问下载文件夹中的文件?

编辑:Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).listFiles()列出所有文件,尽管文档说:

为了提高用户隐私,不推荐直接访问共享/外部存储设备。当应用程序以 Q 为目标时,从此方法返回的路径不再可供应用程序直接访问

0 投票
0 回答
1186 浏览

android - Android10中如何使用MediaStore和范围存储来存储文件

在 Android 10 使用其范围存储锁定所有内容后,我正在尝试开发一个 android-lib 以将文件存储在 /sdcard/{Environment.DIRECTORY_*} 中。

我试过context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)哪个给我/sdcard/Android/data/my.company.namespace/files/Pictures。我假设我可以使用 MediaStore 来扫描这个文件夹,画廊应用程序会从那里显示图片。不幸的是,它不...

我正在阅读文档数小时,但找不到有关如何执行此操作的全面指南。

例如:

MediaStore.Images.Media.insertImage(ContentResolver, Bitmap, String, String)弃用并链接到MediaStore.MediaColumns.IS_PENDING,它没有说明如何使用它。如果我查看代码内部,它使用了很多不存在的类,例如,PendingParams或者PendingSession即使我复制它们,它们仍然使用不推荐使用的方法。

是否有综合指南,如何使用 MediaStore 将文件保存在各自的位置?

假设我想将自定义图像格式 (image/wsq) 存储在/sdcard/Pictures. 或/sdcard/Documents. 其他应用程序是否可以访问它并不重要。

我该怎么做MediaStore

0 投票
1 回答
19632 浏览

android - 如果在 Android 10+ 中禁用旧版外部存储访问,则以编程方式测试

是否有一个简单的 API 调用可以告诉我在 Android 10 或更高版本上运行的应用程序是否必须使用 Scoped Storage 访问权限,也就是说,是否禁用了正常的文件访问权限,即“旧版外部存储”?请注意,即使应用程序在 AndroidManifest.xml 部分声明:

由于未来谷歌政策的变化,文件访问仍然可能被拒绝,所以测试这个值是没有用的。我发现的唯一方法是测试外部存储根目录是否可读,但为此,应用程序必须首先请求存储权限,如果禁用旧版存储,这对其他任何事情都无用。

我想我曾经看过一个新的 API 来检测这一点,但再也找不到那篇文章了……