Android 13+应用图片分享权限错误及合规实现方案咨询
Android 13+ 分享Drawable图片的正确实现方案
问题背景
完全不了解应用间内容分享机制,应用内需分享的图片初始存储在drawable目录。当前实现是将图片写入外部文件,通过FileProvider分享,但持续遭遇权限错误:
java.io.FileNotFoundException: /storage/emulated/0/Documents/image.png: open failed: EACCES (Permission denied)
或
java.io.FileNotFoundException: /storage/emulated/0/image.png: open failed: EPERM (Operation not permitted)
Android 13+中申请读写外部存储权限已无效,申请MANAGE_EXTERNAL_STORAGE权限则可能导致应用无法上架Google Play,需明确正确实现方式。
当前实现代码:
val varName = "p_$muhImage" val resourceId: Int =context.getResources().getIdentifier(varName, "drawable", context.packageName) val bitmap =BitmapFactory.decodeResource(context.resources, resourceId) val path= Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS).toString() + "/image.png" try { FileOutputStream(path).use { out -> bitmap.compress( Bitmap.CompressFormat.PNG, 100, out ) } } catch (e: IOException) { e.printStackTrace() } val shareIntent = Intent(Intent.ACTION_SEND) shareIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK) shareIntent.type = "image/*" val imageUri = FileProvider.getUriForFile( context, context.getPackageName() + ".fileprovider", File(path) ) shareIntent.putExtra(Intent.EXTRA_STREAM, imageUri) shareIntent.putExtra(Intent.EXTRA_TITLE, "share") shareIntent.putExtra(Intent.EXTRA_TEXT, "share") val chooserIntent = Intent.createChooser(shareIntent, "share") chooserIntent.putExtra(Intent.EXTRA_TITLE, "share") chooserIntent.putExtra(Intent.EXTRA_TEXT, "share") chooserIntent.putExtra(Intent.EXTRA_CONTENT_QUERY, "image/*") context.startActivity( Intent.createChooser( shareIntent, "share too" ) ); File(path).deleteOnExit();
Manifest权限配置:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Manifest中Provider配置:
<provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/provider"/> </provider>
Provider XML配置:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path name="external_files" path="."/> </paths>
正确实现方案
核心逻辑
避开外部公共目录的权限限制,改用应用私有缓存目录存储待分享图片,配合FileProvider完成跨应用授权分享,全程无需任何外部存储权限。
步骤1:修改FileProvider路径配置
更新res/xml/provider.xml,指向应用私有缓存目录:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 配置为应用私有缓存目录 --> <cache-path name="cache_files" path="."/> </paths>
步骤2:重构分享代码
将图片写入应用私有缓存目录,无需权限即可读写:
val varName = "p_$muhImage" val resourceId: Int = context.resources.getIdentifier(varName, "drawable", context.packageName) val bitmap = BitmapFactory.decodeResource(context.resources, resourceId) // 改用应用私有缓存目录,无需权限 val cacheDir = context.cacheDir val shareFile = File(cacheDir, "share_image.png") try { FileOutputStream(shareFile).use { out -> bitmap.compress(Bitmap.CompressFormat.PNG, 100, out) } } catch (e: IOException) { e.printStackTrace() return // 处理写入失败场景 } val shareIntent = Intent(Intent.ACTION_SEND) // 必须添加该Flag,授予接收方临时读取权限 shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) shareIntent.type = "image/*" val imageUri = FileProvider.getUriForFile( context, "${context.packageName}.fileprovider", shareFile ) shareIntent.putExtra(Intent.EXTRA_STREAM, imageUri) shareIntent.putExtra(Intent.EXTRA_TITLE, "分享图片") shareIntent.putExtra(Intent.EXTRA_TEXT, "这是我分享的图片") // 启动分享选择器 context.startActivity(Intent.createChooser(shareIntent, "选择分享方式")) // 延迟删除文件,避免分享时文件被提前清理 shareFile.deleteOnExit()
步骤3:清理无用权限
删除Manifest中无需再使用的外部存储权限:
<!-- 移除以下权限 --> <!-- <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> --> <!-- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> -->
关键原理说明
- 应用私有目录:
context.cacheDir是应用专属的私有缓存目录,仅当前应用可读写,Android全版本无权限限制。 - FileProvider:将私有文件路径转换为Content Uri,通过临时授权机制让目标应用安全访问文件,避免直接暴露文件路径的安全风险。
- FLAG_GRANT_READ_URI_PERMISSION:必须添加该Flag,否则接收方应用无法读取Uri指向的文件,会触发权限错误。
内容的提问来源于stack exchange,提问作者M.KH
相关产品推荐
相关产品推荐

