导语
应用是否曾因请求 或 权限而被 拒绝?随着 权限和隐私政策的不断收紧,除非应用的核心功能是文件管理或相册,否则过度索取存储权限将是应用上架的主要障碍。
本文将深入探讨 的最新要求,并提供一套零权限的解决方案,指导开发者使用 照片选择器 ( ) 和 () 来安全、合规地访问图片、视频和任意文件。
🎯 政策核心变化:应用为什么会被拒?
如果应用在 文件中声明了以下权限,但核心功能并非需要广泛、持续地访问设备上的所有媒体文件(例如,仅用于上传头像),那么应用的更新版本几乎确定会被 拒绝:
READ_MEDIA_IMAGESREAD_MEDIA_VIDEOREAD_EXTERNAL_STORAGE(在 及以上基本被上述权限取代)
的要求是:如果需求是用户选择特定文件进行一次性操作,应用应该使用以下两种基于用户授权的 ,从而完全避免请求存储权限。
一、零权限访问图片和视频:
对于图片和视频选择, 是 ( ) 引入的首选 ,并且通过 库可以向后兼容至 ( )。
1. 添加依赖
需要使用 的 库。
Gradle
dependencies {
implementation("androidx.activity:activity-ktx:1.9.0") // 或更高版本
}
2. 选取单张图片
以下代码展示了如何启动 并处理返回的 ,全程无需权限声明。
Kotlin
import androidx.activity.result.contract.ActivityResultContracts
import android.net.Uri
// 注册 Launcher,用于接收结果
private val pickImage = registerForActivityResult(ActivityResultContracts.PickVisualMedia()) { uri: Uri? ->
if (uri != null) {
// 成功!使用 ContentResolver 处理这个 URI
Log.d("PhotoPicker", "Selected Image URI: $uri")
// 例如:将 URI 加载到 ImageView 或获取 InputStream
contentResolver.openInputStream(uri)?.use { inputStream ->
// 在这里处理图片数据流
}
} else {
Log.d("PhotoPicker", "No image selected")
}
}
// 启动图片选择器的方法
fun launchPhotoPicker() {
pickImage.launch(
PickVisualMediaRequest.Builder()
// 仅允许选择图片
.setMediaType(ActivityResultContracts.PickVisualMedia.ImageOnly)
.build()
)
}
3. 选取多个媒体文件(可选)
如果应用允许用户一次选择多张图片或视频:
Kotlin
// 注册 Launcher,限制最多选择 5 个媒体文件
private val pickMultipleMedia = registerForActivityResult(ActivityResultContracts.PickMultipleVisualMedia(5)) { uris: List<Uri> ->
if (uris.isNotEmpty()) {
Log.d("PhotoPicker", "Number of items selected: ${uris.size}")
// 遍历 uris 列表进行处理
uris.forEach { uri ->
// 处理每个 URI
}
}
}
// 启动多选的方法
fun launchMultiPhotoPicker() {
pickMultipleMedia.launch(
PickVisualMediaRequest.Builder()
// 允许选择图片和视频
.setMediaType(ActivityResultContracts.PickVisualMedia.ImageAndVideo)
.build()
)
}
二、零权限访问任意文件: ()
如果应用需要用户选择 、、文本文档或任何其他非媒体文件,则应使用 。
1. 选取任意单个文件
使用 合约来实现文件的选择。
Kotlin
import androidx.activity.result.contract.ActivityResultContracts
import android.net.Uri
import android.content.Intent
// 注册 Launcher,用于接收文件结果
private val filePickerLauncher = registerForActivityResult(ActivityResultContracts.OpenDocument()) { uri: Uri? ->
if (uri != null) {
Log.d("SAF", "Selected File URI: $uri")
// 关键:获取持久性访问权限(如果需要长期访问此文件)
val flag = Intent.FLAG_GRANT_READ_URI_PERMISSION
contentResolver.takePersistableUriPermission(uri, flag)
// 读取文件内容
contentResolver.openInputStream(uri)?.use { inputStream ->
// 在这里处理文件数据流(例如,读取文本或字节)
}
}
}
// 启动任意文件选择器
fun launchAnyFilePicker() {
// 使用 "*/*" MIME 类型来允许用户选择任意类型的文件
filePickerLauncher.launch("*/*")
}
2. 选取特定类型文件(可选)
如果应用只想让用户选择特定 类型的文件(例如,):
Kotlin
fun launchPdfFilePicker() {
// 启动 PDF 文件选择器
filePickerLauncher.launch("application/pdf")
}
结论
通过从应用的 文件中删除 / 等权限,并用上述 和 机制替换自定义文件选择逻辑,应用不仅能解决 的权限拒绝问题,还能使应用更加安全、更符合现代 的隐私设计原则。
建议开发者立即行动,使用 官方推荐的 更新应用,确保顺利通过审核!