Android 13中ExifInterface.getLatLong()始终返回false的解决咨询
Android 13下ExifInterface无法读取照片经纬度的解决方案
问题根源分析
- 权限校验升级:Android 13(API 33)新增
ACCESS_MEDIA_LOCATION权限,即使拥有READ_MEDIA_IMAGES,也必须单独申请该权限才能读取EXIF中的定位信息。 - 分区存储限制:手动拼接
file://Uri的方式,在Android 10+的分区存储机制下,无法获取完整的文件访问权限,导致ExifInterface无法读取定位元数据。 - 原生方法兼容性:系统原生
ExifInterface的getLatLong()方法在Android 13上存在兼容性问题,部分场景下无法正确解析GPS标签。
解决方案
1. 完善权限配置
在AndroidManifest.xml中添加对应权限声明:
<!-- Android 13+ 媒体位置权限 --> <uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" /> <!-- Android 13+ 图片读取权限 --> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <!-- Android 10-12 存储读取权限 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
2. 适配分区存储的Uri获取方式
避免手动拼接file:// Uri,改用MediaStore查询文件对应的内容Uri:
private fun getContentUriFromPath(context: Context, filePath: String): Uri? { val projection = arrayOf(MediaStore.Images.Media._ID) val selection = "${MediaStore.Images.Media.DATA} = ?" val selectionArgs = arrayOf(filePath) context.contentResolver.query( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, selection, selectionArgs, null )?.use { cursor -> if (cursor.moveToFirst()) { val id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID)) return ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id) } } return null }
3. 使用AndroidX ExifInterface库(跨版本兼容)
引入AndroidX的ExifInterface库修复原生类的兼容性问题,在Module级build.gradle添加依赖:
implementation "androidx.exifinterface:exifinterface:1.3.6"
修改核心逻辑,手动解析GPS标签替代getLatLong()方法:
private fun getLocationAndMoveOn() { if (hasMediaLocationPermission(requireContext())) { val pickedPhotoData = libraryViewModel.viewState.pickedPhoto.value?.DATA ?: return val uri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { getContentUriFromPath(requireContext(), pickedPhotoData) ?: return } else { Uri.fromFile(File(pickedPhotoData)) } requireContext().contentResolver.openInputStream(uri)?.use { stream -> androidx.exifinterface.media.ExifInterface(stream).run { // 读取EXIF中的GPS标签 val latitude = getAttribute(ExifInterface.TAG_GPS_LATITUDE) val latitudeRef = getAttribute(ExifInterface.TAG_GPS_LATITUDE_REF) val longitude = getAttribute(ExifInterface.TAG_GPS_LONGITUDE) val longitudeRef = getAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF) if (!latitude.isNullOrEmpty() && !latitudeRef.isNullOrEmpty() && !longitude.isNullOrEmpty() && !longitudeRef.isNullOrEmpty()) { // 转换为十进制经纬度 val lat = convertExifToDegree(latitude) * if (latitudeRef == "N") 1 else -1 val lon = convertExifToDegree(longitude) * if (longitudeRef == "E") 1 else -1 val location = Location("").apply { latitude = lat longitude = lon } navigateToLocation(location) } else { showPhotoLocationDataDialog() } } } } else { requestMediaLocationPermission(requireActivity(), REQUEST_PERMISSION_MEDIA_ACCESS) } } // 将EXIF格式的经纬度转换为十进制度数 private fun convertExifToDegree(exifValue: String): Double { val parts = exifValue.split(",").map { it.split("/") } val degrees = parts[0][0].toDouble() / parts[0][1].toDouble() val minutes = parts[1][0].toDouble() / parts[1][1].toDouble() val seconds = parts[2][0].toDouble() / parts[2][1].toDouble() return degrees + (minutes / 60) + (seconds / 3600) }
4. 优化权限检查逻辑
确保hasMediaLocationPermission()适配全版本:
private fun hasMediaLocationPermission(context: Context): Boolean { return when { Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> { ContextCompat.checkSelfPermission(context, Manifest.permission.READ_MEDIA_IMAGES) == PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_MEDIA_LOCATION) == PackageManager.PERMISSION_GRANTED } Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q -> { ContextCompat.checkSelfPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_MEDIA_LOCATION) == PackageManager.PERMISSION_GRANTED } else -> { ContextCompat.checkSelfPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED } } }
内容的提问来源于stack exchange,提问作者Helios
相关产品推荐
相关产品推荐

