You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android 10+使用ExifInterface读取存储图片GPS经纬度失败问题

问题分析与解决方案

核心问题

当选择content://com.android.externalstorage.documents/类型的存储目录图片时,直接通过openInputStream()拿到的是媒体库提供的剥离GPS元数据的文件副本(Android 10+ Scoped Storage机制默认行为),导致无法读取GPS经纬度,其他EXIF数据不受影响。


具体修复步骤

1. 强制请求原始文件URI

API 29(Android 10)及以上,必须调用MediaStore.setRequireOriginal(uri)获取包含完整EXIF的原始文件,需处理不支持该方法的异常场景:

Uri selecteduri = data.getData();

// 关键:请求原始文件URI(仅API 29+生效)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
    try {
        selecteduri = MediaStore.setRequireOriginal(selecteduri);
    } catch (UnsupportedOperationException e) {
        // 处理第三方文件管理器返回的不兼容URI
        e.printStackTrace();
    }
}

2. 修复权限申请逻辑

ACCESS_MEDIA_LOCATION是API 29新增权限,需单独做版本判断,且需批量申请所有必要权限:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    List<String> permissionsToRequest = new ArrayList<>();
    // 申请READ_EXTERNAL_STORAGE
    if (checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
        permissionsToRequest.add(Manifest.permission.READ_EXTERNAL_STORAGE);
    }
    // API 29+ 申请ACCESS_MEDIA_LOCATION
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && 
        checkSelfPermission(Manifest.permission.ACCESS_MEDIA_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        permissionsToRequest.add(Manifest.permission.ACCESS_MEDIA_LOCATION);
    }

    if (!permissionsToRequest.isEmpty()) {
        // 批量申请权限
        registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), result -> {
            boolean allGranted = true;
            for (Boolean granted : result.values()) {
                if (!granted) {
                    allGranted = false;
                    break;
                }
            }
            if (allGranted) {
                openImagePicker();
            }
        }).launch(permissionsToRequest.toArray(new String[0]));
    } else {
        openImagePicker();
    }
}

3. 优化图片选择Intent

使用ACTION_OPEN_DOCUMENT替代ACTION_GET_CONTENT,更符合Scoped Storage设计,同时精简权限标记:

public void openImagePicker() {
    Intent photoPickerIntent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
    photoPickerIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION |
            Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
    photoPickerIntent.setType("image/*");
    photoPickerIntent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
    someActivityResultLauncher.launch(Intent.createChooser(photoPickerIntent, "选择图片"));
}

4. 修复流资源泄漏问题

将InputStream关闭逻辑放入finally块,避免异常时资源无法释放:

InputStream stream = null;
try {
    stream = getContentResolver().openInputStream(selecteduri);
    if (stream != null) {
        ExifInterface exifInterface = new ExifInterface(stream);
        float[] output = new float[2];
        boolean hasGps = exifInterface.getLatLong(output);
        if (hasGps) {
            System.out.println("Lat: " + output[0]);
            System.out.println("Long: " + output[1]);
        } else {
            System.out.println("无GPS数据");
        }
    }
} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if (stream != null) {
        try {
            stream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

关键注意事项

  • 禁止使用URI转文件路径的方法,Scoped Storage下该方式已被废弃且可能失效。
  • ACCESS_MEDIA_LOCATION是Android 10+读取GPS元数据的必要条件,必须与READ_EXTERNAL_STORAGE同时申请。

内容的提问来源于stack exchange,提问作者Uvin Abeysinghe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 10:20:34