Android 11中通过Intent.ACTION_VIEW无法在其他应用打开图片
问题排查与修复
核心错误原因
你通过MediaStore将图片写入了系统媒体库,但后续打开图片时,错误地使用了context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)下的空文件构建Uri——这个文件从未被写入图片数据,导致其他应用无法找到媒体文件。
修正后的代码实现
直接使用MediaStore插入后返回的uri构建打开意图即可,无需额外创建File和FileProvider Uri:
private fun savePhotoToExternalStorage(displayName: String, bmp: Bitmap, mimeType: String): Boolean { LogUtil.d(TAG, "savePhotoToExternalStorage: ") val imageCollection = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY) } else { MediaStore.Images.Media.EXTERNAL_CONTENT_URI } val contentValues = ContentValues().apply { put(MediaStore.Images.Media.DISPLAY_NAME, displayName) put(MediaStore.Images.Media.MIME_TYPE, mimeType) put(MediaStore.Images.Media.WIDTH, bmp.width) put(MediaStore.Images.Media.HEIGHT, bmp.height) } return try { context.contentResolver.insert(imageCollection, contentValues)?.also { mediaUri -> context.contentResolver.openOutputStream(mediaUri).use { outputStream -> if (!bmp.compress( // 根据mimeType匹配压缩格式,避免格式不兼容 if (mimeType == "image/png") Bitmap.CompressFormat.PNG else Bitmap.CompressFormat.JPEG, 95, outputStream ) ) { LogUtil.e(TAG, "savePhotoToExternalStorage: 图片压缩失败") } // 直接使用MediaStore返回的uri构建打开意图 val intent = Intent(Intent.ACTION_VIEW).apply { setDataAndType(mediaUri, mimeType) addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) // 低版本系统需手动授予权限 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { val resolvedActivities = context.packageManager.queryIntentActivities(this, PackageManager.MATCH_DEFAULT_ONLY) resolvedActivities.forEach { ri -> context.grantUriPermission( ri.activityInfo.packageName, mediaUri, Intent.FLAG_GRANT_READ_URI_PERMISSION ) } } } try { context.startActivity(Intent.createChooser(intent, "打开方式").addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)) } catch (e: ActivityNotFoundException) { e.printStackTrace() Log.e(TAG, "savePhotoToExternalStorage: 未找到支持打开该图片的应用") } } } true } catch (e: IOException) { Log.e(TAG, "savePhotoToExternalStorage: ${e.message} ") e.printStackTrace() false } catch (e: Exception) { Log.e(TAG, "savePhotoToExternalStorage: ${e.message}", ) e.printStackTrace() false } }
额外优化点
- 压缩格式匹配MIME类型:根据传入的
mimeType选择对应压缩格式,避免JPEG压缩PNG导致的格式错误。 - 移除冗余代码:删除未使用的
File创建和FileProvider Uri构建逻辑,减少无效操作。 - 权限处理简化:Android 10及以上版本,
MediaStore插入的媒体Uri无需额外授权,低版本按需批量授予权限即可。
原方案无效的原因
你创建的File指向应用私有外部存储目录,但从未将图片数据写入该文件——图片实际被写入MediaStore管理的公共媒体库路径,两个路径完全不同,导致FileProvider返回的Uri指向空文件,触发"Media not found"错误。
内容的提问来源于stack exchange,提问作者Ved
相关产品推荐
相关产品推荐

