teslamotors / react-native-camera-kit

A high performance, easy to use, rock solid camera library for React Native apps.
MIT License
2.49k stars 590 forks source link

[Android] App crash after capture #678

Open VincentSastra opened 2 weeks ago

VincentSastra commented 2 weeks ago

Versions OS: Android 13 React: 18.3.1 React Native: 0.76.1 react-native-camera-kit: 14.0.0

Describe the bug App crash after capture, Logcat mentions two main errors getOrCreateModule(): Unable to create module "UIManager" (legacy: false, turbo: true) and then java.lang.NullPointerException: null cannot be cast to non-null type com.rncamerakit.CKCamera at com.rncamerakit.RNCameraKitModule.capture$lambda$0(RNCameraKitModule.kt:70) on line val view = uiManager?.resolveView(viewTag) as CKCamera

I believe the main issue is that the UIManager is not created

To Reproduce

const CameraComponent = ({ setImageData, onClose }) => {
  const cameraRef = useRef(null);

  const handleOnPress = async () => {
    if (cameraRef.current !== null) {
      const image = await cameraRef.current.capture();

      setImageData({
        name: image.name,
        type: "image/jpg",
        uri: image.uri,
      });

      onClose();
    }
  };

  return (
    <>
      <Camera style={{ aspectRatio: 3 / 4, width: "100%" }} ref={cameraRef} />
      <Icon
        onPress={() => onClose()}
        name="arrow-back"
        color={"white"}
        size={80}
      />
      <Icon onPress={handleOnPress} name="circle" color={"white"} size={80} />
      <Icon name="arrow-back" color={"black"} size={80} />
    </>
  );
};

Logcat Crash message

Screenshot 2024-11-06 at 2 44 12 PM

Null pointer at source code

Screenshot 2024-11-06 at 2 44 34 PM
cmkf01 commented 2 weeks ago

I'm seeing this same error:

java.lang.NullPointerException: null cannot be cast to non-null type com.rncamerakit.CKCamera
at com.rncamerakit.RNCameraKitModule.capture$lambda$0(RNCameraKitModule.kt:70)

since upgrading to react-native@0.76

ditiem commented 2 weeks ago

If this is a clue, it happens when I upgraded to the latest react native version which uses the "new architecture". Maybe this has something to do with it:

https://github.com/reactwg/react-native-new-architecture/discussions/201

ditiem commented 2 weeks ago

I can confirm that this code works with the new architecture (current react-native version is 0.76.1), BUT I was not able to make it switch between old and new architecture:

import com.facebook.react.uimanager.UIManagerHelper
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import com.facebook.react.BuildConfig

// (...)

    @ReactMethod
    fun capture(options: ReadableMap, viewTag: Int, promise: Promise) {
        // if (ReactFeatureFlags.useTurboModules) {
        // if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
            captureUsingNewArchitecture(options, viewTag, promise)
        // } else {
        //    captureUsingOldArchitecture(options, viewTag, promise)
        // }
     }

    private fun captureUsingNewArchitecture(options: ReadableMap, viewTag: Int, promise: Promise) {
        GlobalScope.launch(Dispatchers.Main) {
            try {
              val uiManager = UIManagerHelper.getUIManager(reactContext, viewTag)
              val view = uiManager?.resolveView(viewTag) as? CKCamera

              if (view != null) {
                  view.capture(options.toHashMap(), promise)
              } else {
                  promise.reject("VIEW_NOT_FOUND", "Could not find CKCamera view with tag $viewTag")
              }
            } catch (e: Exception) {
                promise.reject("CAPTURE_FAILED", e.message, e)
            }
        }
    }

    private fun captureUsingOldArchitecture(options: ReadableMap, viewTag: Int, promise: Promise) {
        val uiManager = reactContext.getNativeModule(UIManagerModule::class.java)
        reactContext.runOnUiQueueThread {
            val view = uiManager?.resolveView(viewTag) as? CKCamera
            if (view != null) {
                view.capture(options.toHashMap(), promise)
            } else {
                promise.reject("VIEW_NOT_FOUND", "Could not find CKCamera view with tag $viewTag")
            }
        }
    }
cmkf01 commented 1 week ago

672 fixed this issue for me.