首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >尝试从不同线程同步调用函数{promiseMethodWrapper}

尝试从不同线程同步调用函数{promiseMethodWrapper}
EN

Stack Overflow用户
提问于 2022-04-29 16:05:34
回答 1查看 686关注 0票数 5

这是我第一次尝试连接react本机和本地iOS应用程序。

在我的react本机iOS项目中,我创建了一个快速文件(它创建了一个桥接头),在这个快速文件中,我创建了一个示例方法来首先进行测试:

代码语言:javascript
复制
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
  }

}

在桥接头文件中,只有导入:

代码语言:javascript
复制
#import "React/RCTBridgeModule.h"
#import <VisionCamera/FrameProcessorPlugin.h>. //from react-native-vision-camera
#import <VisionCamera/Frame.h> //from react-native-vision-camera

然后我创建了一个名为MyModule.m的objective文件,并在其中添加了:

代码语言:javascript
复制
#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

然后,在react本机中,我有一个Home.js,在这里我将访问这个方法。

代码语言:javascript
复制
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.

根据我的理解,我们使用thencatch来处理一个承诺,因为我认为这就是我们从RCTPromiseResolveBlock得到的东西,但这不起作用,所以我只是尝试了console.log(res);,然后它打印了undefined

我得到的错误是:

代码语言:javascript
复制
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

我已经在worklet中定义了useFrameProcessor

更新:

我更新了obj-c方法如下:

代码语言:javascript
复制
@objc(testFunctionWithPromiseResolve:resolver:rejecter:)
  func testFunctionWithPromiseResolve(_ frame: Frame,
                                 resolver resolve: @escaping RCTPromiseResolveBlock,
                                 rejecter reject: @escaping RCTPromiseRejectBlock) {...

在JS中我做到了:

代码语言:javascript
复制
let module = NativeModules.MyModule;

const frameProcessor = useFrameProcessor((frame) => {

        'worklet';
        //let module = NativeModules.MyModule; //didnt work either
        console.log(module.testFunctionWithPromiseResolve(frame));

    })

但我也有同样的错误:

EN

回答 1

Stack Overflow用户

发布于 2022-05-22 08:56:44

幸运的是我发现了这个问题。

  1. 自定义Frame Processor Plugins需要根据文档完成,文档地址是创建帧处理器插件,您需要使用VISION_EXPORT_FRAME_PROCESSOR导出定义插件的本地自定义代码,而使用RCT_EXTERN_MODULERCT_EXTERN_METHOD将失败。
  2. 您需要在js端导出自定义插件方法,文档地址是向JS公开您的帧处理器插件,如下所示:
代码语言:javascript
复制
import type { Frame } from 'react-native-vision-camera'

/**
 * Scans QR codes.
 */
export function scanQRCodes(frame: Frame): string[] {
  'worklet'
  return __scanQRCodes(frame)
}

但现在,这将是__scanQRCodes

代码语言:javascript
复制
module.exports = {
  plugins: [
    [
      'react-native-reanimated/plugin',
      {
        globals: ['__scanQRCodes'],
      },
    ],

要使babel.config.js文件生效,您必须重新启动metro-bundler。

他说:你必须重新开始项目才能生效。

我的代码如下:

我定制了一个名为MyModuleFrameProcessPlugin.m的Ojective-C MyModuleFrameProcessPlugin.m,代码实现如下:

代码语言:javascript
复制
#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

创建一个名为ExamplePlugin.ts的新js插件,代码如下:

代码语言:javascript
复制
/* 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]);
}

babel.config.js文件如下:

代码语言:javascript
复制
module.exports = {
  presets: ['module:metro-react-native-babel-preset'],
  plugins: [
    [
      'react-native-reanimated/plugin',
      {
        globals: ['__myCustomPlugin']
      }
    ]
  ],
};

插件导入代码如下:

代码语言:javascript
复制
import {cusPlugin} from './ExamplePlugin';

调用代码如下:

代码语言:javascript
复制
  const frameProcessor = useFrameProcessor((frame) => {
    'worklet';
    const value = cusPlugin(frame);
    console.log(`Return Values: ${JSON.stringify(value)}`);
  }, []);
  //Use in Camera is  frameProcessor={frameProcessor}

我测试了我的代码,它是好的,我希望它能帮助你。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72060767

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档