expo: [expo-image-picker] [android only] EXIF/lat-lng data not being pulled

Summary

Seems like when we want to get LAT+LNG information from a photo taken with Android (since API leven 29, Android 10), using expo-image-picker, it doesn’t work anymore (not even adding ACCESS_MEDIA_LOCATION in the permissions).

You can get more information about this bug in:

I would say the most important information is here: https://github.com/expo/expo/pull/16541#issuecomment-1060959583, in the first point.

the current way of requesting location from EXIF tags in expo-image-picker (see ExifDataHandler class in ImagePickerUtils.kt and exifTags in ImagePickerConstants.kt) doesn’t work any longer. Reading the location is now more complex, you can see the putAssetInfo() in AssetUtils.kt in expo-media-library for the working implementation.

So… In some way, we have to move the complex-logic from expo-media-library (I guess) to expo-image-picker, in order to be able to get the exif data.

We also have another workaround, but currently it’s not doable because of a lack of an id in expo-media-picker. Check the full description I left in this comment: https://github.com/expo/expo/issues/16548#issuecomment-1116808876 To sum up the comment: expo-media-picker doesn’t provide us the exif/lat-lng data, but we could get it using MediaLibrary.getAssetInfoAsync. The problem is that MediaLibrary.getAssetInfoAsync is asking for an assetId, and ImagePicker.launchImageLibraryAsync is not retrieving any kind of assetId.

As a temporal workaround, seems like I will have to migrate the whole “upload file” flow from expo-image-picker to expo-media-library. Right?

Managed or bare workflow? If you have ios/ or android/ directories in your project, the answer is bare!

managed

What platform(s) does this occur on?

Android

SDK Version (managed workflow only)

44 (and probably 45. will test it soon)

Environment

  expo-env-info 1.0.3 environment info:
    System:
      OS: macOS 11.6.1
      Shell: 5.8 - /bin/zsh
    Binaries:
      Node: 14.18.2 - ~/.nvm/versions/node/v14.18.2/bin/node
      Yarn: 1.22.18 - ~/.yarn/bin/yarn
      npm: 8.3.2 - ~/.nvm/versions/node/v14.18.2/bin/npm
      Watchman: 4.9.0 - /usr/local/bin/watchman
    SDKs:
      iOS SDK:
        Platforms: iOS 14.5, DriverKit 20.4, macOS 11.3, tvOS 14.5, watchOS 7.4
      Android SDK:
        API Levels: 27, 31
        Build Tools: 23.0.1, 23.0.3, 25.0.3, 26.0.1, 27.0.3, 28.0.3, 29.0.2
        System Images: android-31 | Google Play Intel x86 Atom_64
    IDEs:
      Android Studio: 2021.1 AI-211.7628.21.2111.8309675
      Xcode: 12.5.1/12E507 - /usr/bin/xcodebuild
    npmPackages:
      expo: ^44.0.0 => 44.0.6
      react: 17.0.1 => 17.0.1
      react-native: 0.64.3 => 0.64.3
    npmGlobalPackages:
      eas-cli: 0.52.0
      expo-cli: 5.4.3
    Expo Workflow: managed

Reproducible demo

https://snack.expo.dev/@brodanoel/no-exif

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Comments: 32 (26 by maintainers)

Most upvoted comments

Get out of here

I’m also experiencing the same issue for SDK 50. I cannot get lat/long info with launchImageLibraryAsync. Also as mentioned, there is no asset ID (using Recent and Albums) that I can use for MediaLibrary. Any updates regarding the issue?

Here more details:

const options = {
  mediaTypes: ImagePicker.MediaTypeOptions.Images,
  allowsEditing: false,
  exif: true,
};

ImagePicker.launchImageLibraryAsync(options).then(async response => {
  const { assetId, uri, exif = {} } = response;

  let gpsData = {
    lat: null,
    lng: null,
  };

  // If I have the GPS data in the main `exif`, use it.
  let hasGPS = !!exif.GPSLatitude;

  if (hasGPS) {
    gpsData.lat = exif.GPSLatitude;
    gpsData.lng = exif.GPSLongitude;
  }

  let assetData = {};

  if (assetId) {
    // I get the `assetData` even if we already got the GPS. Just to hydrate the photo with more info
    assetData = await MediaLibrary.getAssetInfoAsync(assetId);

    // But... If we don't have the GPS data in the main EXIF, let's try to find it here.
    if (!hasGPS) {
      // GPS data may be present in: `assetData.location`
      if (assetData.location && assetData.location.latitude) {
        gpsData.lat = assetData.location.latitude;
        gpsData.lng = assetData.location.longitude;
        hasGPS = true;
      } else if (
        assetData.exif &&
        assetData.exif['{GPS}'] &&
        assetData.exif['{GPS}'].Latitude
      ) {
        // GPS data may be present in this new crazy non-standard format: `assetData.exif['{GPS}'].Latitude`
        const gps = assetData.exif['{GPS}'];

        gpsData.lat = gps.Latitude;
        gpsData.lng = gps.Longitude;
        hasGPS = true;
      } else if (assetData.exif && assetData.exif.GPSLatitude) {
        // GPS data may be present in `assetData.exif.GPSLatitude`
        gpsData.lat = assetData.exif.GPSLatitude;
        gpsData.lng = assetData.exif.GPSLongitude;
        hasGPS = true;
      }
    }
  }

  actions.userPhotos.save({
    uri,
    lat: gpsData.lat,
    lng: gpsData.lng,
    exif: {
      ...exif,
      assetData,
    },
  })
}

If you check this ^^^, in the backend I will always save the exif data with the original/main exif, and then, inside exif.assetData I will save all the info that I get from await MediaLibrary.getAssetInfoAsync(assetId);.

With this user I mentioned, exif.assetData is ALWAYS {}, which means that while using Samsung Gallery App I actually COULD NOT get the AssetId… But now, at least Samsung Gallery App is providing the GPS data in the main exif (the user was clearly always using the File System).

So… Kind of crazy… We’ll have to add a new 4th option like “Samsung Gallery App”, where Asset ID is also non-pressent.