1、权限:
bash
<!-- Android 13(API 33)及以上,允许应用读取存储在外部存储上的图片文件。替代了:READ_EXTERNAL_STORAGE(在 Android 13 被细化成 READ_MEDIA_IMAGES、READ_MEDIA_VIDEO、READ_MEDIA_AUDIO 等) -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<!-- Android 12及以下 允许应用读取外部存储器(SD卡或主存储空间)中的所有文件(不区分图片、音频、视频等) -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- 允许应用读取媒体文件(如图片、视频)中嵌入的位置信息(GPS坐标),这部分信息通常存在于 EXIF 元数据中。 -->
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
2、动态申请权限:
kotlin
private val REQUEST_CODE_MEDIA = 1001
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
requestMediaPermissions(this, REQUEST_CODE_MEDIA)
}
fun requestMediaPermissions(activity: Activity, requestCode: Int) {
val permissions = mutableListOf<String>()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
// Android 13+
permissions.add(android.Manifest.permission.READ_MEDIA_IMAGES)
} else {
// Android 12 及以下
permissions.add(android.Manifest.permission.READ_EXTERNAL_STORAGE)
}
// Android 10+ 支持读取媒体位置信息
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
permissions.add(android.Manifest.permission.ACCESS_MEDIA_LOCATION)
}
ActivityCompat.requestPermissions(activity, permissions.toTypedArray(), requestCode)
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == REQUEST_CODE_MEDIA) {
if (grantResults.all { it == PackageManager.PERMISSION_GRANTED }) {
Log.d("Permission", "所有权限已授予")
// 可以开始读取图片及其位置信息
} else {
Log.e("Permission", "部分权限被拒绝,功能可能受限")
}
}
}
3、获取图片信息(路径和经纬度)代码实现:
kotlin
import android.content.ContentUris
import android.content.Context
import androidx.exifinterface.media.ExifInterface
import android.net.Uri
import android.provider.MediaStore
import android.util.Log
import com.next.homestorage.entity.ImageInfo
/**
* 获取系统图片信息列表
*/
fun getSystemImageInfos(context: Context): List<ImageInfo> {
val imageList = mutableListOf<ImageInfo>()
val projection = arrayOf(
MediaStore.Images.Media._ID, //系统为每一张图片生成的唯一 ID
MediaStore.Images.Media.DATA, //图片在设备本地文件系统中的实际路径
MediaStore.Images.Media.DISPLAY_NAME //图片的文件显示名称(不包括路径)
)
val uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
val sortOrder = "${MediaStore.Images.Media.DATE_ADDED} DESC"
context.contentResolver.query(uri, projection, null, null, sortOrder)?.use { cursor ->
val columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)
val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID)
while (cursor.moveToNext()) {
val id = cursor.getLong(idColumn)
val contentUri = ContentUris.withAppendedId(uri, id)
val (lat, lon) = readImageLocation(context, contentUri)
val path = cursor.getString(columnIndex)
val imageInfo = ImageInfo( path, lat, lon)
imageList.add(imageInfo)
Log.d("MediaFile", "path=$path")
Log.d("MediaFile", "uri=$contentUri")
Log.d("MediaFile", "uriPath=${contentUri.path}")
}
}
return imageList
}
/**
* 获取图片经纬度
*/
private fun readImageLocation(context: Context, uri: Uri): Pair<Float, Float> {
var latitude = 0f
var longitude = 0f
try {
context.contentResolver.openInputStream(uri)?.use { input ->
val exif = ExifInterface(input)
val latLong = FloatArray(2)
exif.latLong?.let {
latitude = it[0].toFloat()
longitude = it[1].toFloat()
Log.d("MediaFile", "EXIF Lat: ${latLong[0]}, Lon: ${latLong[1]}")
}
}
} catch (e: Exception) {
Log.e("MediaFile", "Error reading EXIF for $uri", e)
}
return latitude to longitude
}
data class ImageInfo(
val path: String,
val latitude: Float,
val longitude: Float
)
注:代码已在Android 12上测试通过