I know this question has been asked many times but all the questions refers to integrating a third party dependency in react-native
app but in my case it is because of my own native code and I am having issues on how to fix it. I am using react-native
0.69
Here is snippet of my code
CealScanQrView.ktclass CealScanQrView(context: Context): FrameLayout(context) {...//Contains all the logic of integrating camerax, check below code repo to see the full source code ...}CealScanQrFragment.ktclass CealScanQrFragment: Fragment() { private lateinit var cealScanQrView: CealScanQrView override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { super.onCreateView(inflater, container, savedInstanceState) cealScanQrView = CealScanQrView(requireNotNull(context)) return cealScanQrView // this CustomView could be any view that you want to render } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // do any logic that should happen in an `onCreate` method, e.g: cealScanQrView.setUpCamera(requireActivity()) } override fun onDestroy() { super.onDestroy() cealScanQrView.destroyCamera() }}CealScanQrViewManager.ktclass CealScanQrViewManager( private val reactContext: ReactApplicationContext) : ViewGroupManager<FrameLayout>() { private val cealScanQrView = "CealScanQrView" private val topChange = "topChange" private val phasedRegistrationNames = "phasedRegistrationNames" private val bubbled = "bubbled" private val onChange = "onChange" private val create = "create" companion object { private const val COMMAND_CREATE = 1 } private var propWidth: Int? = null private var propHeight: Int? = null override fun getName() = cealScanQrView override fun createViewInstance(reactContext: ThemedReactContext) = FrameLayout(reactContext) override fun getCommandsMap() = mapOf("create" to COMMAND_CREATE) override fun receiveCommand(root: FrameLayout, commandId: String?, args: ReadableArray?) { super.receiveCommand(root, commandId, args) val reactNativeViewId = requireNotNull(args).getInt(0) when (commandId?.toInt()) { COMMAND_CREATE -> createFragment(root, reactNativeViewId) } } private fun createFragment(root: FrameLayout, reactNativeViewId: Int) { val parentView = root.findViewById<ViewGroup>(reactNativeViewId) setupLayout(parentView) val myFragment = CealScanQrFragment() val activity = reactContext.currentActivity as FragmentActivity activity.supportFragmentManager .beginTransaction() .replace(reactNativeViewId, myFragment, reactNativeViewId.toString()) .commit() } private fun setupLayout(view: View) { Choreographer.getInstance().postFrameCallback(object: Choreographer.FrameCallback { override fun doFrame(frameTimeNanos: Long) { manuallyLayoutChildren(view) view.viewTreeObserver.dispatchOnGlobalLayout() Choreographer.getInstance().postFrameCallback(this) } }) } @ReactPropGroup(names = ["width", "height"], customType = "Style") fun setStyle(view: FrameLayout, index: Int, value: Int) { if (index == 0) propWidth = value if (index == 1) propHeight = value } private fun manuallyLayoutChildren(view: View) { // propWidth and propHeight coming from react-native props val width = requireNotNull(propWidth) val height = requireNotNull(propHeight) view.measure( View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY)) view.layout(0, 0, width, height) } override fun getExportedCustomBubblingEventTypeConstants(): Map<String, Any> { return mapOf( topChange to mapOf( phasedRegistrationNames to mapOf( bubbled to onChange ) ) ) }}
On the JS
side
I created a CealScanQrViewManager.tsx
file
import {requireNativeComponent} from 'react-native';export const CealScanQrViewManager = requireNativeComponent('CealScanQrViewManager',);
In App.tsx
const createFragment = (viewId: number | null) => UIManager.dispatchViewManagerCommand( viewId, // we are calling the 'create' command UIManager.CealScanQrViewManager.Commands.create.toString(), [viewId], );const App = () => { const isDarkMode = useColorScheme() === 'dark'; const [isCameraPermissionGranted, setIsCameraPermissionGranted] = useState(false); const backgroundStyle = { backgroundColor: isDarkMode ? Colors.darker : Colors.lighter, }; const ref = useRef(null); useEffect(() => { requestCameraPermission(); }, []); useEffect(() => { if (isCameraPermissionGranted) { const viewId = findNodeHandle(ref.current); createFragment(viewId); } }, [isCameraPermissionGranted]); const requestCameraPermission = async () => { try { const granted = await PermissionsAndroid.request( PermissionsAndroid.PERMISSIONS.CAMERA, { title: 'Cool Photo App Camera Permission', message:'Cool Photo App needs access to your camera '+'so you can take awesome pictures.', buttonNeutral: 'Ask Me Later', buttonNegative: 'Cancel', buttonPositive: 'OK', }, ); if (granted === PermissionsAndroid.RESULTS.GRANTED) { setIsCameraPermissionGranted(true); } else { console.log('Camera permission denied'); } } catch (err) { console.warn(err); } }; const readQr = async (data: any) => { console.log(data.nativeEvent.qrCode); }; return (<SafeAreaView style={backgroundStyle}><StatusBar barStyle={isDarkMode ? 'light-content' : 'dark-content'} /> {isCameraPermissionGranted ? (<CealScanQrViewManager style={{ // converts dpi to px, provide desired height height: PixelRatio.getPixelSizeForLayoutSize(200), // converts dpi to px, provide desired width width: PixelRatio.getPixelSizeForLayoutSize(200), }} ref={ref} onChange={readQr} /> ) : (<View style={{flex: 1, backgroundColor: 'red'}} /> )}</SafeAreaView> );};
As soon as I grant the camera permission I get error saying
requireNativeComponent CealScanQrViewManager was not found in UIManager
Full source code here