This is the first time I'm trying the bridging of react-native and a native iOS app.
In my react-native iOS project, I've created a swift file (that created a bridging header) and in that swift file I've created a sample method to test first:
import Foundation
@objc(MyModule)
class MyModule: NSObject {
@objc
func testFunctionWithPromiseResolve(frame: Frame,
resolver resolve: @escaping RCTPromiseResolveBlock,
rejecter reject: @escaping RCTPromiseRejectBlock) {
var resp = [String:Any]() //Init Dictionary
resp.updateValue(frame, forKey: "frame");
resolve(resp);
}
@objc
static func requiresMainQueueSetup() -> Bool {
return true
}
}
In the bridging header file I have imports only:
#import "React/RCTBridgeModule.h"
#import <VisionCamera/FrameProcessorPlugin.h>. //from react-native-vision-camera
#import <VisionCamera/Frame.h> //from react-native-vision-camera
Then I created an objective-c file named MyModule.m
and in it, I've added:
#import <Foundation/Foundation.h>
#import "React/RCTBridgeModule.h"
@interface
RCT_EXTERN_MODULE(MyModule, NSObject);
RCT_EXTERN_METHOD(testFunctionWithPromiseResolve:
(Frame *)frame
resolver:(RCTPromiseResolveBlock *)resolve
rejecter:(RCTPromiseRejectBlock *)reject);
@end
Then in react-native, I have a Home.js
where I'm going to access this method.
import React from 'react';
import { Text, StyleSheet, ScrollView, NativeModules } from 'react-native';
import { Camera, useCameraDevices, useFrameProcessor } from 'react-native-vision-camera';
import 'react-native-reanimated'
function Home(props) {
const devices = useCameraDevices();
const device = devices.back;
const { MyModule } = NativeModules;
const frameProcessor = useFrameProcessor((frame) => {
'worklet';
let res = MyModule.testFunctionWithPromiseResolve(frame);
console.log(res);
// .then((res) => {
// console.log(res);
// }).catch((e) => {
// console.log(e);
// })
})
//... My other code is just UI-related in which I'm calling the frameProcessor in <Camera... using its prop frameProcessor={frameProcessor} as per react-native-vision-camera documentation.
As per my understanding, we handle a Promise with then
and catch
as I assume this is what we'll be getting from RCTPromiseResolveBlock
but that was not working so I just simply tried console.log(res);
and it prints undefined
.
The error I'm getting is:
Tried to synchronously call function {promiseMethodWrapper} from a different thread.
Possible solutions are:
a) If you want to synchronously execute this method, mark it as a Worklet
b) If you want to execute this method on the JS thread, wrap it using runOnJS
reanimated::REAIOSErrorHandler::raiseSpec()
REAIOSErrorHandler.mm:18
reanimated::ErrorHandler::raise()::'lambda'()::operator()()
decltype(static_cast<reanimated::ErrorHandler::raise()::'lambda'()&>(fp)()) std::__1::__invoke<reanimated::ErrorHandler::raise()::'lambda'()&>(reanimated::ErrorHandler::raise()::'lambda'()&)
void std::__1::__invoke_void_return_wrapper<void, true>::__call<reanimated::ErrorHandler::raise()::'lambda'()&>(reanimated::ErrorHandler::raise()::'lambda'()&)
std::__1::__function::__alloc_func<reanimated::ErrorHandler::raise()::'lambda'(), std::__1::allocator<reanimated::ErrorHandler::raise()::'lambda'()>, void ()>::operator()()
std::__1::__function::__func<reanimated::ErrorHandler::raise()::'lambda'(), std::__1::allocator<reanimated::ErrorHandler::raise()::'lambda'()>, void ()>::operator()()
std::__1::__function::__value_func<void ()>::operator()() const
std::__1::function<void ()>::operator()() const
invocation function for block in vision::VisionCameraScheduler::scheduleOnUI(std::__1::function<void ()>)
F14F0161-E0DE-3D9C-851E-AD12F95A3073
F14F0161-E0DE-3D9C-851E-AD12F95A3073
F14F0161-E0DE-3D9C-851E-AD12F95A3073
F14F0161-E0DE-3D9C-851E-AD12F95A3073
F14F0161-E0DE-3D9C-851E-AD12F95A3073
_pthread_wqthread
start_wqthread
I've worklet
defined in the useFrameProcessor
.
UPDATE:
I've updated the obj-c
method to:
@objc(testFunctionWithPromiseResolve:resolver:rejecter:)
func testFunctionWithPromiseResolve(_ frame: Frame,
resolver resolve: @escaping RCTPromiseResolveBlock,
rejecter reject: @escaping RCTPromiseRejectBlock) {...
and the in JS I did:
let module = NativeModules.MyModule;
const frameProcessor = useFrameProcessor((frame) => {
'worklet';
//let module = NativeModules.MyModule; //didnt work either
console.log(module.testFunctionWithPromiseResolve(frame));
})
But I get the same error: