因非核心功能申请全文件权限,App遭Google Play拒审求助
解决方案:用内部存储+FileProvider实现合规的拍照上传
核心思路
完全放弃外部存储权限(包括MANAGE_EXTERNAL_STORAGE),仅使用应用内部存储保存图片,配合FileProvider给相机授权访问,既满足拍照上传需求,又符合Google Play的权限审核规则。
步骤1:精简权限清单
修改AndroidManifest.xml,只保留必要权限,移除所有外部存储相关权限:
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.INTERNET" /> <!-- 相机硬件特性,autofocus非必须则设为非强制 --> <uses-feature android:name="android.hardware.camera" android:required="true" /> <uses-feature android:name="android.hardware.camera.autofocus" android:required="false" /> <!-- 保留FileProvider配置 --> <provider android:name="androidx.core.content.FileProvider" android:authorities="com.test.fileupload.provider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider>
file_paths.xml只需配置内部存储路径,示例:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <files-path name="my_images" path="my_images/" /> </paths>
步骤2:拍照保存到内部存储的正确实现
生成内部存储的图片文件,通过FileProvider给相机授权,避免权限崩溃:
private const val REQUEST_CODE_TAKE_PHOTO = 100 fun takePhoto(context: Context) { // 创建内部存储的图片目录 val storageDir = File(context.filesDir, "my_images") if (!storageDir.exists()) { storageDir.mkdirs() } // 生成唯一命名的图片文件 val photoFile = File(storageDir, "${System.currentTimeMillis()}.jpg") // 通过FileProvider生成可共享的Uri val photoUri = FileProvider.getUriForFile( context, "com.test.fileupload.provider", // 与Manifest中authorities一致 photoFile ) // 启动相机Intent val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE) takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri) // 授予相机临时写入权限 takePictureIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION) // 适配Android 10+的权限授予方式 context.packageManager.queryIntentActivities(takePictureIntent, 0).forEach { context.grantUriPermission( it.activityInfo.packageName, photoUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION ) } // 启动相机(Activity中用startActivityForResult,Fragment用registerForActivityResult) (context as Activity).startActivityForResult(takePictureIntent, REQUEST_CODE_TAKE_PHOTO) }
步骤3:直接用内部存储文件上传服务器
图片保存在内部存储,直接通过File对象读取上传,无需Uri转路径:
fun uploadImage(photoFile: File) { // 以OkHttp为例构建上传请求 val requestBody = MultipartBody.Builder() .setType(MultipartBody.FORM) .addFormDataPart( "image", photoFile.name, RequestBody.create(MediaType.parse("image/jpeg"), photoFile) ) .build() val request = Request.Builder() .url("你的服务器上传接口") .post(requestBody) .build() // 执行上传请求(建议在子线程或协程中执行) OkHttpClient().newCall(request).enqueue(object : Callback { override fun onFailure(call: Call, e: IOException) { // 处理上传失败 } override fun onResponse(call: Call, response: Response) { // 处理上传成功 } }) }
关键说明
- 之前用内部存储崩溃的原因:没有通过FileProvider给相机授权,导致相机无法写入你的App私有内部存储,添加
FLAG_GRANT_WRITE_URI_PERMISSION和批量授权后即可解决。 - 此方案完全符合Google Play的权限最小化要求,不需要任何外部存储权限,审核不会被拒。
内容的提问来源于stack exchange,提问作者meazuri
相关产品推荐
相关产品推荐

