Cha*_*lha 5 objective-c ios swift react-native rctbridge
这是我第一次尝试连接 React-native 和原生 iOS 应用程序。
在我的react-native iOS 项目中,我创建了一个 swift 文件(创建了桥接标头),并在该 swift 文件中创建了一个示例方法来首先测试:
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
}
}
Run Code Online (Sandbox Code Playgroud)
在桥接头文件中,我仅导入:
#import "React/RCTBridgeModule.h"
#import <VisionCamera/FrameProcessorPlugin.h>. //from react-native-vision-camera
#import <VisionCamera/Frame.h> //from react-native-vision-camera
Run Code Online (Sandbox Code Playgroud)
然后我创建了一个名为的 Objective-C 文件MyModule.m,并在其中添加了:
#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
Run Code Online (Sandbox Code Playgroud)
然后在react-native中,我有一个Home.js可以访问这个方法的地方。
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.
Run Code Online (Sandbox Code Playgroud)
根据我的理解,我们处理一个 Promise then,catch因为我认为这就是我们将从中得到的RCTPromiseResolveBlock,但那不起作用,所以我只是简单地尝试了一下console.log(res);,它打印了undefined。
我收到的错误是:
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
Run Code Online (Sandbox Code Playgroud)
我已经worklet在useFrameProcessor.
更新:
我已将obj-c方法更新为:
@objc(testFunctionWithPromiseResolve:resolver:rejecter:)
func testFunctionWithPromiseResolve(_ frame: Frame,
resolver resolve: @escaping RCTPromiseResolveBlock,
rejecter reject: @escaping RCTPromiseRejectBlock) {...
Run Code Online (Sandbox Code Playgroud)
和我在 JS 中所做的:
let module = NativeModules.MyModule;
const frameProcessor = useFrameProcessor((frame) => {
'worklet';
//let module = NativeModules.MyModule; //didnt work either
console.log(module.testFunctionWithPromiseResolve(frame));
})
Run Code Online (Sandbox Code Playgroud)
但我得到同样的错误:
小智 2
幸运的是我发现了问题。
Frame Processor Plugins需要按照文档完成,文档地址为Creating Frame Processor Plugins,原生端自定义代码需要使用VISION_EXPORT_FRAME_PROCESSOR导出定义插件,使用RCT_EXTERN_MODULE和RCT_EXTERN_METHOD会失败。import type { Frame } from 'react-native-vision-camera'
/**
* Scans QR codes.
*/
export function scanQRCodes(frame: Frame): string[] {
'worklet'
return __scanQRCodes(frame)
}
Run Code Online (Sandbox Code Playgroud)
但现在,这将是__scanQRCodes:
module.exports = {
plugins: [
[
'react-native-reanimated/plugin',
{
globals: ['__scanQRCodes'],
},
],
Run Code Online (Sandbox Code Playgroud)
您必须重新启动 Metro-bundler 才能使babel.config.js文件中的更改生效。
3:必须重新启动项目才能生效。
我的代码如下:
我自定义了一个Ojective-C ,frame Processor Plugins名为MyModuleFrameProcessPlugin.m,代码实现如下:
#import <VisionCamera/FrameProcessorPlugin.h>
#import <VisionCamera/Frame.h>
@interface MyModuleFrameProcessPlugin : NSObject
@end
@implementation MyModuleFrameProcessPlugin
static inline id myCustomPlugin(Frame* frame, NSArray* arguments) {
CVPixelBufferRef imageBuffer = CMSampleBufferGetImageBuffer(frame.buffer);
NSLog(@"myCustomPlugin: %zu x %zu Image. Logging %lu parameters:", CVPixelBufferGetWidth(imageBuffer), CVPixelBufferGetHeight(imageBuffer), (unsigned long)arguments.count);
for (id param in arguments) {
NSLog(@"myCustomPlugin: -> %@ (%@)", param == nil ? @"(nil)" : [param description], NSStringFromClass([param classForCoder]));
}
return @{
@"myCustomPlugin_str": @"Test",
@"myCustomPlugin_bool": @true,
@"myCustomPlugin_double": @5.3,
@"myCustomPlugin_array": @[
@"Hello",
@true,
@17.38
]
};
}
VISION_EXPORT_FRAME_PROCESSOR(myCustomPlugin)
@end
Run Code Online (Sandbox Code Playgroud)
新建一个js插件,命名为ExamplePlugin.ts,代码如下:
/* global __myCustomPlugin */
import type { Frame } from 'react-native-vision-camera';
declare let _WORKLET: true | undefined;
export function cusPlugin(frame: Frame): string[] {
'worklet';
if (!_WORKLET) throw new Error('my_custom_plugin must be called from a frame processor!');
// @ts-expect-error because this function is dynamically injected by VisionCamera
return __myCustomPlugin(frame, 'hello my_custom_plugin!', 'parameter2', true, 42, { test: 0, second: 'test' }, ['another test', 500]);
}
Run Code Online (Sandbox Code Playgroud)
文件babel.config.js内容如下:
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
plugins: [
[
'react-native-reanimated/plugin',
{
globals: ['__myCustomPlugin']
}
]
],
};
Run Code Online (Sandbox Code Playgroud)
插件导入代码如下:
import {cusPlugin} from './ExamplePlugin';
Run Code Online (Sandbox Code Playgroud)
调用代码如下:
const frameProcessor = useFrameProcessor((frame) => {
'worklet';
const value = cusPlugin(frame);
console.log(`Return Values: ${JSON.stringify(value)}`);
}, []);
//Use in Camera is frameProcessor={frameProcessor}
Run Code Online (Sandbox Code Playgroud)
我测试了我的代码,没问题,希望对你有帮助。
| 归档时间: |
|
| 查看次数: |
1706 次 |
| 最近记录: |