Android低版本(SDK_INT<Q)使用ACTION_SEND分享时图片不显示问题
Android低版本(SDK < Q)分享图片不显示问题修复
问题现象
使用ACTION_SEND Intent实现图片分享时,Android 10及以上版本(SDK_INT≥Q)的分享对话框可正常显示图片,但Android 9及以下版本(SDK_INT<Q)中图片无法显示。已配置FileProvider并实现Bitmap转PNG生成URI的逻辑,但低版本仍未达到预期效果。
问题原因分析
- 变量名不匹配:Intent调用代码中传入
EXTRA_STREAM的变量是未定义的bmpUri,而非生成的uri,导致低版本无法获取正确的图片URI。 - 异步扫描延迟:低版本中调用
MediaScannerConnection.scanFile是异步操作,可能在分享启动时图片尚未完成媒体库索引,导致接收应用无法读取。 - 权限覆盖不全:部分低版本系统中,
createChooser不会自动将URI读取权限传递给所有候选分享应用,导致部分应用无法访问图片。
修复方案
1. 修正Intent变量名错误
将Intent中putExtra(Intent.EXTRA_STREAM, bmpUri)改为putExtra(Intent.EXTRA_STREAM, uri),确保传入正确的图片URI。
2. 移除不必要的媒体扫描(低版本)
使用FileProvider分享应用私有目录的图片时,无需将图片加入媒体库,异步扫描反而可能导致分享时机过早。移除低版本代码中的MediaScannerConnection.scanFile调用。
3. 手动授予所有候选应用权限
针对低版本系统,手动遍历所有支持分享的应用,为每个应用授予URI读取权限,确保所有候选应用都能访问图片。
修正后的完整代码
Manifest配置(保持不变)
<provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.provider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/provider_paths" /> </provider>
Provider路径配置(保持不变)
<paths> <external-files-path name="external_files" path="Pictures" /> </paths>
Bitmap转URI函数(修正后)
import android.content.Context import android.graphics.Bitmap import android.os.Build import android.os.Environment import android.provider.MediaStore import androidx.core.content.FileProvider import java.io.File import java.io.FileOutputStream fun Bitmap.saveAsPng(context: Context, filename: String): Uri? = "$filename.png".let { name -> if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { @Suppress("DEPRECATION") val file = File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), name) FileOutputStream(file).use { compress(Bitmap.CompressFormat.PNG, 100, it) } // 移除媒体扫描,分享无需媒体库索引 FileProvider.getUriForFile( context, "${context.packageName}.provider", file ) } else { val values = ContentValues().apply { put(MediaStore.Images.Media.DISPLAY_NAME, name) put(MediaStore.Images.Media.MIME_TYPE, "image/png") put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_DCIM) put(MediaStore.Images.Media.IS_PENDING, 1) } val resolver = context.contentResolver val uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values) uri?.let { resolver.openOutputStream(it) } ?.use { compress(Bitmap.CompressFormat.PNG, 100, it) } values.clear() values.put(MediaStore.Images.Media.IS_PENDING, 0) uri?.also { resolver.update(it, values, null, null) } uri } }
Intent分享代码(修正后)
import android.content.Intent import android.content.pm.PackageManager import android.graphics.Bitmap import android.net.Uri import android.widget.Toast // 调用分享逻辑 fun shareBitmap(context: Context, bitmap: Bitmap) { bitmap.saveAsPng(context, "qrcodeImg")?.let { uri -> val shareIntent = Intent(Intent.ACTION_SEND).apply { type = "image/*" putExtra(Intent.EXTRA_STREAM, uri) // 修正变量名 addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) } // 适配低版本:给所有候选应用授予URI读取权限 val resInfoList = context.packageManager.queryIntentActivities(shareIntent, PackageManager.MATCH_DEFAULT_ONLY) for (resolveInfo in resInfoList) { val packageName = resolveInfo.activityInfo.packageName context.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION) } context.startActivity(Intent.createChooser(shareIntent, "Share via...")) } ?: run { Toast.makeText(context, "图片保存失败,无法分享", Toast.LENGTH_SHORT).show() } }
内容的提问来源于stack exchange,提问作者Hamdah_Tr
相关产品推荐
相关产品推荐

