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
,例如:
<paths>
<external-path name="images" path="Pictures/" /><!-- prior to SDK-29, use public external storage -->
<external-files-path name="externalImages" path="Pictures/" />
<files-path name="internalImages" path="internalImages/"/>
<cache-path name="cache" path="/" />
</paths>
这些在正确配置后现在运行良好,但是实现了“保存到图库”功能,例如:通知其他应用程序新图像不再适用于运行 Android-10 的设备
// use FileProvider to make this new photo publicly accessible
val shareableUri = FileProvider.getUriForFile(context, FILE_PROVIDER_AUTHORITY, newImage)
context.sendBroadcast(
Intent(ACTION_MEDIA_SCANNER_SCAN_FILE).apply { data = uris.externalUri }
)
这种方法应该有效,但不管原始图像保存在哪里(私有应用程序目录、缓存目录、外部私有)
MediaScannerConnection.scanFile(context, arrayOf(newImage.absolutePath), arrayOf("image/jpeg")) { path: String, uri: Uri? ->
if (uri == null) {
throw IllegalStateException("media scan failed...")
} else {
// successful
}
}
Android 的 SDK-29 中是否有新的限制需要更改 MediaScanning,特别是与扫描(可能)私有图像文件的方式有关?我注意到MediaScanner
方法大多期望String
路径而不是 URI,所以这让我认为新的限制不适用于它,因为它是一个系统组件。
解决方案
默认情况下,面向 Android 10(API 级别 29)及更高版本的应用会获得对外部存储设备或范围存储的范围访问权限。
因此您需要使其与 scopedStorage 兼容,但您可以使用 Google Android 开发人员指南中提到的这种临时方法。
在您的应用与范围存储完全兼容之前,您可以根据应用的目标 SDK 级别或 requestLegacyExternalStorage 清单属性暂时选择退出:
<manifest ... >
<!-- This attribute is "false" by default on apps targeting
Android 10 or higher. -->
<application android:requestLegacyExternalStorage="true" ... >
...
</application>
</manifest>
访问此链接了解更多信息: https ://developer.android.com/training/data-storage/files/external-scoped
推荐阅读
- sublimetext3 - Sublime Text 3 - 一劳永逸地修复标签
- javascript - svg路径上的jQuery鼠标悬停事件
- angular - 使用 openFromComponent 从 matSnackBar 获取数据
- python - 类型错误:不支持 divmod() 的操作数类型:“NoneType”和“Int”
- java - 在 grails 中生成与原始域类具有相同字段的新域类
- castle-dynamicproxy - 静态方法可以用 Castle DynamicProxy 拦截吗?
- java - 使用 Android Studio 3.0.1 为 QR 码扫描仪添加保存选项
- android - 如何在 Firebase 中对节点的子值实施唯一约束?
- ibm-cloud - 如果 Watson 可以根据国名返回国家代码?
- python - python,django,solr,haystack:编辑 solr_build_schema BaseCommand.add_argument() 时 django 模板上下文错误