expo: Expo ImagePicker fails to launch. Call to function 'ExponentImagePicker.launchCameraAsync' has been rejected.

Summary

My users on Android arrive at a point where they can no longer launch the camera. User has given camera and media library permissions. User was able to open camera. User is no longer able to open Camera or Media Library.

It seems to be related to the expo task manager too.

** I’ve found that the issue appears when: **

  • Given you are tracking location via a task in the task manager
  • When you close the app
  • When you reopen the app
  • When you try to pick an image
  • Then the image picker will not open

I’ve found that the issue does not appear when location tracking is not active when the app was last closed.

Check the linked repo with reproducible example.

result = await ImagePicker.launchCameraAsync({
        base64: true,
        allowsEditing: true,
        mediaTypes: ImagePicker.MediaTypeOptions.Images,
        quality: 0.2
      });

// or

result = await ImagePicker.launchImageLibraryAsync({...})

Resulting error logs (source Sentry):

Error: Error: Call to function 'ExponentImagePicker.launchCameraAsync' has been rejected.
→ Caused by: java.lang.IllegalStateException: Attempting to launch an unregistered ActivityResultLauncher with contract expo.modules.imagepicker.contracts.CameraContra...
  at ? (app:///index.android.bundle:3411:1320)
  at generatorResume([native code])
  at n(app:///index.android.bundle:269:69)
  at p(app:///index.android.bundle:269:316)
  at u(app:///index.android.bundle:2634:157)
  at ? (app:///index.android.bundle:2634:884)
  at ? (app:///index.android.bundle:76:1692)
  at p(app:///index.android.bundle:76:528)
  at N(app:///index.android.bundle:76:918)
  at callReactNativeMicrotasks(app:///index.android.bundle:76:3079)
  at value(app:///index.android.bundle:56:2935)
  at ? (app:///index.android.bundle:56:1045)
  at value(app:///index.android.bundle:56:2583)
  at value(app:///index.android.bundle:56:1004)
  at value([native code])
  at value([native code])

Closing and reopening the app does not resolve the issue. Once a user has met this error, only reinstalling the app works.

What platform(s) does this occur on?

Android

Environment

expo-env-info 1.0.5 environment info: System: OS: macOS 12.0.1 Shell: 3.2.57 - /bin/bash Binaries: Node: 16.12.0 - ~/.nvm/versions/node/v16.12.0/bin/node Yarn: 1.22.17 - /usr/local/bin/yarn npm: 8.1.0 - ~/.nvm/versions/node/v16.12.0/bin/npm Watchman: 2021.06.07.00 - /usr/local/bin/watchman Managers: CocoaPods: 1.10.1 - /usr/local/bin/pod SDKs: iOS SDK: Platforms: DriverKit 21.4, iOS 15.5, macOS 12.3, tvOS 15.4, watchOS 8.5 IDEs: Android Studio: 4.1 AI-201.8743.12.41.7199119 Xcode: 13.4.1/13F100 - /usr/bin/xcodebuild npmPackages: expo: ^46.0.0 => 46.0.9 react: 18.0.0 => 18.0.0 react-dom: 18.0.0 => 18.0.0 react-native: 0.69.6 => 0.69.6 react-native-web: ~0.18.7 => 0.18.8 react-navigation: ^4.4.4 => 4.4.4 npmGlobalPackages: eas-cli: 0.53.1 expo-cli: 6.0.6 Expo Workflow: managed

Minimal reproducible example

The error appears only for production builds and dev builds using a dev-client.
I’ve been able to reproduce it via the example demo app in this github repository: https://github.com/Nxtra/expo-image-picker-issue-reproduce

The steps to reproduce the exact issue are in the repo, also here:

  • run npx expo start
  • open via dev client
  • Press “pick an image”
  • You will be able to pick an image
  • Select start tracking
  • After a few sec an icon will appear in you top notification bar indicating that you are being tracked
  • Close the app (really close it by swiping it out of your open apps menu)
  • Open app
  • Press “pick an image”
  • The camera picker won’t open!

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 18
  • Comments: 98 (8 by maintainers)

Commits related to this issue

Most upvoted comments

Some news?

I have the same problem and the same steps to replicate it.

@Nxtra @bradjones1 @rgonzalez-clicoh @russnes @stharvey I was able to temporarily fix this in my app until the expo team can provide a permanent solution. I had to patch expo-image-picker using https://github.com/ds300/patch-package This is the patchfile for the version in the reproduction repo: expo-image-picker+13.3.1.patch

diff --git a/node_modules/expo-image-picker/android/src/main/java/expo/modules/imagepicker/ImagePickerModule.kt b/node_modules/expo-image-picker/android/src/main/java/expo/modules/imagepicker/ImagePickerModule.kt
index 7a28702..b6b7bf4 100644
--- a/node_modules/expo-image-picker/android/src/main/java/expo/modules/imagepicker/ImagePickerModule.kt
+++ b/node_modules/expo-image-picker/android/src/main/java/expo/modules/imagepicker/ImagePickerModule.kt
@@ -26,6 +26,7 @@ import kotlinx.coroutines.suspendCancellableCoroutine
 import kotlinx.coroutines.withContext
 import kotlin.coroutines.resume
 import kotlin.coroutines.resumeWithException
+import java.lang.IllegalStateException
 
 // TODO(@bbarthec): rename to ExpoImagePicker
 private const val moduleName = "ExponentImagePicker"
@@ -62,12 +63,29 @@ class ImagePickerModule : Module() {
       val uri = mediaFile.toContentUri(context)
       val contractOptions = options.toCameraContractOptions(uri)
 
-      launchContract({ cameraLauncher.launch(contractOptions) }, options)
+      try {
+        launchContract({ cameraLauncher.launch(contractOptions) }, options)
+      } catch (e: IllegalStateException) {
+        cameraLauncher = appContext.registerForActivityResult(
+          CameraContract(this@ImagePickerModule),
+        ) { input, result -> handleResultUponActivityDestruction(result, input.options) }
+
+        launchContract({ cameraLauncher.launch(contractOptions) }, options)
+      }
     }
 
     AsyncFunction("launchImageLibraryAsync") Coroutine { options: ImagePickerOptions ->
       val contractOptions = options.toImageLibraryContractOptions()
-      launchContract({ imageLibraryLauncher.launch(contractOptions) }, options)
+
+      try {
+        launchContract({ imageLibraryLauncher.launch(contractOptions) }, options)
+      } catch (e: IllegalStateException) {
+        imageLibraryLauncher = appContext.registerForActivityResult(
+          ImageLibraryContract(this@ImagePickerModule),
+        ) { input, result -> handleResultUponActivityDestruction(result, input.options) }
+
+        launchContract({ imageLibraryLauncher.launch(contractOptions) }, options)
+      }
     }
 
     AsyncFunction("getPendingResultAsync") Coroutine { ->
@@ -133,8 +151,18 @@ class ImagePickerModule : Module() {
         result.data.size == 1 &&
         result.data[0].first == MediaType.IMAGE
       ) {
-        result = launchPicker {
-          cropImageLauncher.launch(CropImageContractOptions(result.data[0].second, options))
+        try {
+          result = launchPicker {
+            cropImageLauncher.launch(CropImageContractOptions(result.data[0].second, options))
+          }
+        } catch (e: IllegalStateException) {
+          cropImageLauncher = appContext.registerForActivityResult(
+            CropImageContract(this@ImagePickerModule),
+          ) { input, result -> handleResultUponActivityDestruction(result, input.options) }
+  
+          result = launchPicker {
+            cropImageLauncher.launch(CropImageContractOptions(result.data[0].second, options))
+          }
         }
       }
       mediaHandler.readExtras(result.data, options)

This is the patchfile I for the most recent expo-image-picker version: expo-image-picker+14.0.2.patch

diff --git a/node_modules/expo-image-picker/android/src/main/java/expo/modules/imagepicker/ImagePickerModule.kt b/node_modules/expo-image-picker/android/src/main/java/expo/modules/imagepicker/ImagePickerModule.kt
index eb83273..f81f45b 100644
--- a/node_modules/expo-image-picker/android/src/main/java/expo/modules/imagepicker/ImagePickerModule.kt
+++ b/node_modules/expo-image-picker/android/src/main/java/expo/modules/imagepicker/ImagePickerModule.kt
@@ -26,6 +26,7 @@ import kotlinx.coroutines.withContext
 import java.io.File
 import kotlin.coroutines.resume
 import kotlin.coroutines.resumeWithException
+import java.lang.IllegalStateException
 
 // TODO(@bbarthec): rename to ExpoImagePicker
 private const val moduleName = "ExponentImagePicker"
@@ -62,12 +63,29 @@ class ImagePickerModule : Module() {
       val uri = mediaFile.toContentUri(context)
       val contractOptions = options.toCameraContractOptions(uri)
 
-      launchContract({ cameraLauncher.launch(contractOptions) }, options)
+      try {
+        launchContract({ cameraLauncher.launch(contractOptions) }, options)
+      } catch (e: IllegalStateException) {
+        cameraLauncher = appContext.registerForActivityResult(
+          CameraContract(this@ImagePickerModule),
+        ) { input, result -> handleResultUponActivityDestruction(result, input.options) }
+
+        launchContract({ cameraLauncher.launch(contractOptions) }, options)
+      }
     }
 
     AsyncFunction("launchImageLibraryAsync") Coroutine { options: ImagePickerOptions ->
       val contractOptions = options.toImageLibraryContractOptions()
-      launchContract({ imageLibraryLauncher.launch(contractOptions) }, options)
+
+      try {
+        launchContract({ imageLibraryLauncher.launch(contractOptions) }, options)
+      } catch (e: IllegalStateException) {
+        imageLibraryLauncher = appContext.registerForActivityResult(
+          ImageLibraryContract(this@ImagePickerModule),
+        ) { input, result -> handleResultUponActivityDestruction(result, input.options) }
+  
+        launchContract({ imageLibraryLauncher.launch(contractOptions) }, options)
+      }
     }
 
     AsyncFunction("getPendingResultAsync") Coroutine { ->
@@ -134,8 +152,18 @@ class ImagePickerModule : Module() {
         result.data.size == 1 &&
         result.data[0].first == MediaType.IMAGE
       ) {
-        result = launchPicker {
-          cropImageLauncher.launch(CropImageContractOptions(result.data[0].second, options))
+        try {
+          result = launchPicker {
+           cropImageLauncher.launch(CropImageContractOptions(result.data[0].second, options))
+          }
+        } catch (e: IllegalStateException) {
+          cropImageLauncher = appContext.registerForActivityResult(
+            CropImageContract(this@ImagePickerModule),
+          ) { input, result -> handleResultUponActivityDestruction(result, input.options) }
+
+          result = launchPicker {
+            cropImageLauncher.launch(CropImageContractOptions(result.data[0].second, options))
+          }
         }
       }
       mediaHandler.readExtras(result.data, options)

The general idea is to repeat the registering and restart launching the picker in case it fails due to the here mentioned error.

I am not an android expert and only briefly tested it. So test it properly for yourself before using it.

I am running into this as well, however the error is on the image picker, not the camera:

Call to function 'ExponentImagePicker.launchImageLibraryAsync' has been rejected. → Caused by: java.lang.IllegalStateException: Attempting to launch an unregistered ActivityResultLauncher with contract expo.modules.imagepicker.contracts.ImageLibraryContract@7b3ffcc and input ImageLibraryContractOptions(options=expo.modules.imagepicker.ImagePickerOptions@fbf9cf1). You must ensure the ActivityResultLauncher is registered before calling launch()

Unlike the OP, I do not engage in background location tracking. I do make calls to fetch location and they might be underway while the user is attempting to pick a photo. Perhaps that’s enough to trigger this?

I updated my patches for expo sdk 49. I did not have the time to completely test everything yet. So check yourself if it is working before using them.

For expo sdk 49 you need to apply 2 patch files. One is equal to the patch file from above. And the other one is reenabling an old api that was removed, even though the new one apparently does not work reliably as this issue seems to show.

@lukmccall You seem to have removed the public facing old api registerForActivityResult in this pr while lots have people here in this thread experience issues with the image picker module not working with the new implementation. Would be nice if you guys could have a look at this issue.

expo-image-picker+14.3.0.patch

diff --git a/node_modules/expo-image-picker/android/src/main/java/expo/modules/imagepicker/ImagePickerModule.kt b/node_modules/expo-image-picker/android/src/main/java/expo/modules/imagepicker/ImagePickerModule.kt
index eb83273..f81f45b 100644
--- a/node_modules/expo-image-picker/android/src/main/java/expo/modules/imagepicker/ImagePickerModule.kt
+++ b/node_modules/expo-image-picker/android/src/main/java/expo/modules/imagepicker/ImagePickerModule.kt
@@ -26,6 +26,7 @@ import kotlinx.coroutines.withContext
 import java.io.File
 import kotlin.coroutines.resume
 import kotlin.coroutines.resumeWithException
+import java.lang.IllegalStateException
 
 // TODO(@bbarthec): rename to ExpoImagePicker
 private const val moduleName = "ExponentImagePicker"
@@ -62,12 +63,29 @@ class ImagePickerModule : Module() {
       val uri = mediaFile.toContentUri(context)
       val contractOptions = options.toCameraContractOptions(uri)
 
-      launchContract({ cameraLauncher.launch(contractOptions) }, options)
+      try {
+        launchContract({ cameraLauncher.launch(contractOptions) }, options)
+      } catch (e: IllegalStateException) {
+        cameraLauncher = appContext.registerForActivityResult(
+          CameraContract(this@ImagePickerModule),
+        ) { input, result -> handleResultUponActivityDestruction(result, input.options) }
+
+        launchContract({ cameraLauncher.launch(contractOptions) }, options)
+      }
     }
 
     AsyncFunction("launchImageLibraryAsync") Coroutine { options: ImagePickerOptions ->
       val contractOptions = options.toImageLibraryContractOptions()
-      launchContract({ imageLibraryLauncher.launch(contractOptions) }, options)
+
+      try {
+        launchContract({ imageLibraryLauncher.launch(contractOptions) }, options)
+      } catch (e: IllegalStateException) {
+        imageLibraryLauncher = appContext.registerForActivityResult(
+          ImageLibraryContract(this@ImagePickerModule),
+        ) { input, result -> handleResultUponActivityDestruction(result, input.options) }
+  
+        launchContract({ imageLibraryLauncher.launch(contractOptions) }, options)
+      }
     }
 
     AsyncFunction("getPendingResultAsync") Coroutine { ->
@@ -134,8 +152,18 @@ class ImagePickerModule : Module() {
         result.data.size == 1 &&
         result.data[0].first == MediaType.IMAGE
       ) {
-        result = launchPicker {
-          cropImageLauncher.launch(CropImageContractOptions(result.data[0].second, options))
+        try {
+          result = launchPicker {
+           cropImageLauncher.launch(CropImageContractOptions(result.data[0].second, options))
+          }
+        } catch (e: IllegalStateException) {
+          cropImageLauncher = appContext.registerForActivityResult(
+            CropImageContract(this@ImagePickerModule),
+          ) { input, result -> handleResultUponActivityDestruction(result, input.options) }
+
+          result = launchPicker {
+            cropImageLauncher.launch(CropImageContractOptions(result.data[0].second, options))
+          }
         }
       }
       mediaHandler.readExtras(result.data, options)

expo-modules-core+1.5.3.patch

# generated by patch-package 6.4.10
#
# command:
#   npx patch-package expo-modules-core
#
# declared package:
#   expo-modules-core: https://registry.yarnpkg.com/expo-modules-core/-/expo-modules-core-1.5.3.tgz#ad09f2e8f47b18cb1fd7c885fa3c65c190a5c879
#
diff --git a/node_modules/expo-modules-core/android/src/main/java/expo/modules/kotlin/AppContext.kt b/node_modules/expo-modules-core/android/src/main/java/expo/modules/kotlin/AppContext.kt
index 8041bfe..7a4fdee 100644
--- a/node_modules/expo-modules-core/android/src/main/java/expo/modules/kotlin/AppContext.kt
+++ b/node_modules/expo-modules-core/android/src/main/java/expo/modules/kotlin/AppContext.kt
@@ -6,6 +6,7 @@ import android.content.Intent
 import android.os.Handler
 import android.os.HandlerThread
 import android.view.View
+import androidx.annotation.MainThread
 import androidx.annotation.UiThread
 import androidx.appcompat.app.AppCompatActivity
 import com.facebook.react.bridge.ReactApplicationContext
@@ -28,6 +29,9 @@ import expo.modules.interfaces.sensors.SensorServiceInterface
 import expo.modules.interfaces.taskManager.TaskManagerInterface
 import expo.modules.kotlin.activityresult.ActivityResultsManager
 import expo.modules.kotlin.activityresult.DefaultAppContextActivityResultCaller
+import expo.modules.kotlin.activityresult.AppContextActivityResultContract
+import expo.modules.kotlin.activityresult.AppContextActivityResultFallbackCallback
+import expo.modules.kotlin.activityresult.AppContextActivityResultLauncher
 import expo.modules.kotlin.defaultmodules.ErrorManagerModule
 import expo.modules.kotlin.defaultmodules.NativeModulesProxyModule
 import expo.modules.kotlin.events.EventEmitter
@@ -47,6 +51,7 @@ import kotlinx.coroutines.SupervisorJob
 import kotlinx.coroutines.android.asCoroutineDispatcher
 import kotlinx.coroutines.cancel
 import java.io.File
+import java.io.Serializable
 import java.lang.ref.WeakReference
 
 class AppContext(
@@ -348,5 +353,23 @@ class AppContext(
       return activityProvider?.currentActivity
     }
 
+// endregion
+
+// region AppContextActivityResultCaller
+
+  /**
+   * For the time being [fallbackCallback] is not working.
+   * There are some problems with saving and restoring the state of [activityResultsManager]
+   * connected with [Activity]'s lifecycle and [AppContext] lifespan. So far, we've failed with identifying
+   * what parts of the application outlives the Activity destruction (especially [AppContext] and other [Bridge]-related parts).
+   */
+  @MainThread
+  @Deprecated(message = "`registerForActivityResult` was deprecated. Please use `RegisterActivityContracts` component instead.")
+  suspend fun <I : Serializable, O> registerForActivityResult(
+    contract: AppContextActivityResultContract<I, O>,
+    fallbackCallback: AppContextActivityResultFallbackCallback<I, O>
+  ): AppContextActivityResultLauncher<I, O> =
+    activityResultsManager.registerForActivityResult(contract, fallbackCallback)
+    
 // endregion
 }

Happened in expo 49 also

I’m also experiencing the same issue, although I haven’t been as thorough in reproducing it in these steps. Now after deleting the app and reinstalling from Google Play, it appears to work. Testing on a galaxy S9, with versions:

"react": "18.0.0",
"expo-image-picker": "13.3.1",
"react-native": "0.69.6",

I found a dirty workaround.

I am wrapping the call to `ImagePicker.launchCameraAsync’ in a try-catch block. If this specific error occurs, “Call to function ‘ExponentImagePicker.launchCameraAsync’ has been rejected”, then I suggest to restart the app in an alert:

        try {
          result = await ImagePicker.launchCameraAsync();
        } catch (e) {
          if (e.message.includes("Call to function 'ExponentImagePicker.launchCameraAsync' has been rejected")) {
            displayCameraActivityFailedAlert();
          } else {
            throw e;
          }
        }
import * as TaskManager from "expo-task-manager";
import * as Updates from "expo-updates";
import i18n from "i18n-js";
import { Alert } from "react-native";

const displayCameraActivityFailedAlert = () => {
  Alert.alert("The app is not able to open your camera.", "Restarting the app can solve this issue. Restart now?", [
    {
      text: "Cancel"
    },
    {
      text: "Ok",
      onPress: async () => {
          await TaskManager.unregisterAllTasksAsync();
          await Updates.reloadAsync();
      }
    }
  ]);
};

export { displayCameraActivityFailedAlert };

Still painfull for the user, but less…

UPDATE: I’ve added a git repo with an example and steps to reproduce.

I encountered this issue for a while and couldn’t resolve it, despite trying all the solutions mentioned above. I even updated Expo from version 48 to 49, but the problem persisted. However, I eventually found a solution. It turns out that you no longer need to request permission. The Expo team has documented this in their official documentation, but I missed it initially. When I removed the code that requests permission before calling launchImageLibraryAsync in my code, the issue was completely resolved. I’m no longer getting any errors from Sentry.

Still facing the error expo - 49.0.16 expo-image-picker - “~14.5.0”

Patches not working. Please help resolve this.

image

I’m getting Call to function 'ExponentImagePicker.launchCameraAsync' has been rejected. when restarting my app and trying to take a picture. It happens on .apk after building with EAS, even though taking pictures after restarting works okay when the app is ran locally with npx expo start.

"expo": "^49.0.10", "expo-image-picker": "^14.5.0"

I’ve got a smilar problem, but i am not using location tracking.

I am using: “expo-image-picker”: “~14.1.1”,

The problem is just opening the camera on android. Media library works fine. On IOS camera and library works fine.

WARN Possible Unhandled Promise Rejection (id: 0): Error: Call to function ‘ExponentImagePicker.launchCameraAsync’ has been rejected. → Caused by: java.lang.NullPointerException: Parameter specified as non-null is null: method host.exp.exponent.experience.d.checkSelfPermission, parameter permission.

Applying the patch for 14.0.2 doesn’t work. The code it 14.1.1 doesn’t seem to be the same.

const openCamera = async (isVideoAllowed: boolean = true) => {
    const { status } = await Camera.requestCameraPermissionsAsync();

    if (status !== "granted") {
      console.log("no camera permission!");
      errorMessage("no camera permission!");
      return;
    }

    // permissions request is necessary for launching the camera library
    const result = await ImagePicker.launchCameraAsync({
      mediaTypes: isVideoAllowed
        ? ImagePicker.MediaTypeOptions.All
        : ImagePicker.MediaTypeOptions.Images,
      allowsEditing: Platform.OS === "android",
      aspect: [3, 4],
      quality: 1,
      base64: true,
    });

    if (!result.canceled) {
      setPreview(result.assets[0].uri);
      await prepareMedia(result.assets[0]);
    }
  };

the status prints: “granted”, it crashes somewhere around using launchCameraAsync

Edit: Even downgrading expo-image-picker to 12.0.1 (the last working version which i know for me) doesn’t work anymore, impossible to open the camera.

@TyAzur I encountered the same issue, but I managed to resolve it. Here are the steps I followed:

  1. I applied two patches: ./patches/expo-image-picker+14.3.2.patch and ./patches/expo-modules-core+1.5.9.patch, while using Expo SDK 49. Here is the code for those files: https://github.com/expo/expo/issues/19512#issuecomment-1697107235

  2. First, run yarn install or npm install to ensure all dependencies are up to date.

  3. Then, execute npx patch-package to apply the patches or add "postinstall": "patch-package", to package.json and make sure you run it.

After completing these steps, I was able to successfully build the project. Hope this helps!

We are also experiencing this problem: expo bare “expo”: “^47.0.0”, “react”: “18.1.0”, “react-native”: “0.70.9”, “expo-image-picker”: “~14.0.2”

Problem is very weird because occurs on client phone but not on mine (exactly same phones, Android versions…). A lot of our clients complains that can’t use camera in our app.

I’m also facing this issue on my app. It works fine on android emulator but I’m receiving the same error message on my own device(Xiaomi 11T Pro).

“expo”: 48.0.9 “react”: “18.2.0”, “react-native”: “0.71.4”,

Hello, I’m also experiencing a similar issue with the Expo Development Client build using EAS Build. I’m encountering the following error:

Execution failed for task ':expo-image-picker:compileDebugKotlin'
A failure occurred while executing org.jetbrains.kotlin.compilerRunner.GradleCompilerRunnerWithWorkers$GradleKotlinCompilerWorkAction

In my case:

  • I’ve updated to Expo SDK 49.
  • Using expo-image-picker version 14.3.2
  • I’ve also applied the expo-image-picker+14.3.2.patch
  • I’m building via EAS Build in the cloud, so I don’t have access to the generated files.

Has anyone found a solution or a workaround for this issue? Any help would be greatly appreciated.

@haciSeydaoglu I see the code sample in their docs for launchImageLibraryAsync:

const pickImage = async () => {
    // No permissions request is necessary for launching the image library
    let result = await ImagePicker.launchImageLibraryAsync({  … });
}

what about ImagePicker.launchCameraAsync({ … }) ? I’ve been running into this error without ever requesting the ImageLibrary perm, but I do call await ImagePicker.requestCameraPermissionsAsync() before trying to launch the camera.

this issue happens when you are trying to enter an activity that runs React Native Application, then leave this page and trigger the Activity.onDestory(), and then try to open another Activity that runs React Native Application again. how did this happen:

  1. when the first React Native Application is created, a class instance of AppContextActivityResultRegistry is created, and its register() method is called, making its requestCodeToKey map set up
  2. when Activity.onDestory() is called, AppContextActivityResultRegistry ‘s unregister() method is called, and requestCodeToKey is cleared
  3. unfortunately, when the next time another Activity that runs React Native Application is created, the register() method is not called, which leaves requestCodeToKey map still empty, and this exception is thrown

you can try to create a new ReactNativeHost object when getReactNativeHost() is called in that case, but is is not recommended

better way to solve : use Intent to choose Image on Android, only use Expo on iOS =)

@chanphiromsok Hi, which part of that stackoverflow helped you? it’s about SDK46 and SDK48. Thanks!

@mcottingham I think the reason is that I’m actually getting another similar error, which I documented in https://github.com/expo/expo/issues/24172.

So, the patch should work for those who have problems with .launchCameraAsync

I can confirm it’s happening on SDK 49

“expo-image-picker”: “~14.3.2”,

Error: Call to function 'ExponentImagePicker.launchImageLibraryAsync' has been rejected.
→ Caused by: java.lang.IllegalArgumentException: Uri lacks 'file' scheme: content://media/picker/0/com.android.providers.media.photopicker/media/1000008735

I’m on SDK 49 and we still see this issue, I’ve seen it happening in both de dev build and the actual prod build (android). Haven’t tested on iOS tho. Is there anyone in the core team aware of this issue? Seems pretty critical as it can happen with both the camera and media picker

@johannessachse thanks, i’ve edited my comment

You need to delete your node modules. Make sure that on reinstall the patch-packages gives a success message. Then you need to recompile your app. Best is to delete the android folder as well to force a fresh build.

@green-munkey @DeltaPy , For you is it also related to having location services on at the same time? Then close the app, reopen and the problem appears.

Or what is the flow when you get this error?

I tried using the patch, but issue exists. Here is my patch file,

diff --git a/node_modules/expo-image-picker/android/src/main/java/expo/modules/imagepicker/ImagePickerModule.kt b/node_modules/expo-image-picker/android/src/main/java/expo/modules/imagepicker/ImagePickerModule.kt
index eb83273..1aec09f 100644
--- a/node_modules/expo-image-picker/android/src/main/java/expo/modules/imagepicker/ImagePickerModule.kt
+++ b/node_modules/expo-image-picker/android/src/main/java/expo/modules/imagepicker/ImagePickerModule.kt
@@ -26,6 +26,7 @@ import kotlinx.coroutines.withContext
 import java.io.File
 import kotlin.coroutines.resume
 import kotlin.coroutines.resumeWithException
+import java.lang.IllegalStateException
 
 // TODO(@bbarthec): rename to ExpoImagePicker
 private const val moduleName = "ExponentImagePicker"
@@ -62,12 +63,28 @@ class ImagePickerModule : Module() {
       val uri = mediaFile.toContentUri(context)
       val contractOptions = options.toCameraContractOptions(uri)
 
-      launchContract({ cameraLauncher.launch(contractOptions) }, options)
+      try {
+        launchContract({ cameraLauncher.launch(contractOptions) }, options)
+      } catch (e: IllegalStateException) {
+        cameraLauncher = appContext.registerForActivityResult(
+          CameraContract(this@ImagePickerModule),
+        ) { input, result -> handleResultUponActivityDestruction(result, input.options) }
+
+        launchContract({ cameraLauncher.launch(contractOptions) }, options)
+      }
     }
 
     AsyncFunction("launchImageLibraryAsync") Coroutine { options: ImagePickerOptions ->
       val contractOptions = options.toImageLibraryContractOptions()
-      launchContract({ imageLibraryLauncher.launch(contractOptions) }, options)
+      try {
+        launchContract({ imageLibraryLauncher.launch(contractOptions) }, options)
+      } catch (e: IllegalStateException) {
+        imageLibraryLauncher = appContext.registerForActivityResult(
+          ImageLibraryContract(this@ImagePickerModule),
+        ) { input, result -> handleResultUponActivityDestruction(result, input.options) }
+  
+        launchContract({ imageLibraryLauncher.launch(contractOptions) }, options)
+      }
     }
 
     AsyncFunction("getPendingResultAsync") Coroutine { ->
@@ -134,8 +151,18 @@ class ImagePickerModule : Module() {
         result.data.size == 1 &&
         result.data[0].first == MediaType.IMAGE
       ) {
-        result = launchPicker {
-          cropImageLauncher.launch(CropImageContractOptions(result.data[0].second, options))
+          try {
+          result = launchPicker {
+           cropImageLauncher.launch(CropImageContractOptions(result.data[0].second, options))
+          }
+        } catch (e: IllegalStateException) {
+          cropImageLauncher = appContext.registerForActivityResult(
+            CropImageContract(this@ImagePickerModule),
+          ) { input, result -> handleResultUponActivityDestruction(result, input.options) }
+
+          result = launchPicker {
+            cropImageLauncher.launch(CropImageContractOptions(result.data[0].second, options))
+          }
         }
       }
       mediaHandler.readExtras(result.data, options)

Can someone help me with a solution?

I’m also facing this issue on my app on android (RedMi note12)

  • “expo”: “~47.0.14”,
  • “expo-image-picker”: “~14.0.2”,
  • “expo-document-picker”: “~11.0.1”,

We recently upgraded to expo 47 in production and this issue started popping up in Sentry. Background geotracking and camera are core features of our application. Did anyone find a workaround without the need to patch packages?

Watching with interest as I have experienced the same issue on a Pixel 4 device. Location Services and ImagePicker are core features of my app so it would be great to see a resolution.

I know I’m adding nothing new here but just wanted to add a message in case it helped to gauge the “breadth of impact”.

Thanks