Search code examples
swiftobjective-creact-nativereact-native-modules

RN module in Swift can not get param


I am implementing my own module and I have a problem with passing params into function in swift. That function should return Promise. And it always crashes with this error

Exception 'getPassesOf: is not a recognized Objective-C method.' was thrown while invoking getPassesOf on target RNAppleWallet with params ( DDDDtest, 5026, 5027 )

my O-C bridge:

#import "React/RCTBridgeModule.h"

@interface RCT_EXTERN_MODULE(RNAppleWallet, NSObject)

RCT_EXTERN_METHOD(openWallet:(NSDictionary*)config callback:(RCTResponseSenderBlock))

...

RCT_EXTERN_METHOD(getPasses: (RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)

RCT_EXTERN_METHOD(getPassesOf: (NSString *)test (RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)

//RCT_EXTERN_METHOD(getPassesOf:(NSString*)passType (RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
//RCT_EXTERN_METHOD(getPassesOf:(NSString *)passType resolve:(RCTPromiseResolveBlock *)resolve reject:(RCTPromiseRejectBlock *)reject)


...


@end

important Functions getRemoteSecureElementPasses, getRemotePaymentPasses and getPasses works fine. But they don't have extra parameter and function getPassesOf with pramateter test crash

RCT_EXTERN_METHOD(getPassesOf: (NSString *)test (RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)

This is an implementation in swift function getPsses works fine but getPassesOf have a problem with that param

...
  @objc
  func getPasses(_ resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
    let passes =  passLib.passes();
    let passesArray = convertPassesToJsonString(passes:passes)
    resolve(passesArray)
  }

  
 @objc
  func getPassesOf(_ test: String, resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) -> Void{
    print("===================================================")
    print(test)

    resolve("cus")
  }
...

interesting is when I remove param test all works fine ... but I need it

and this is how I call it in RN getPasses works fine getPassesOf doest work:

...
  public async getPasses(): Promise<PassType[]> {
    const passData = await this.walletModule.getPasses();

    return passData.map(pass => JSON.parse(pass));
  }

  public async getPassesOf(passType: string): Promise<PassType[]> {
    // const passesOf = await this.walletModule.getPassesOf();
    const passesOf = await this.walletModule.getPassesOf('DDDDtest');

    return passesOf.map(pass => JSON.parse(pass));
  }
...

UPDATE:

I remove return type -> Void bud nothing change still doesn't work

before:

@objc func getPassesOf(_ test: String, resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) -> Void{

after:

@objc func getPassesOf(_ test: String, resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {


Solution

  • The problem in your code with definition of your getPassesOf function in Objective-C (missing resolve:) and the bridge can't find your method:

    // Your
    RCT_EXTERN_METHOD(getPassesOf:(NSString *)test (RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject);
    
    // Correct
    RCT_EXTERN_METHOD(getPassesOf:(NSString *)test resolve:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject);
    

    Many parameters

    The common rule for RCT_EXPORT_METHOD or RCT_EXTERN_METHOD with many parameters:

    Objective-C:

    RCT_EXTERN_METHOD(methodName:(Type1*)param1 param2:(Type2*)param2 ... 
     paramN:(TypeN*)paramN);
    

    Swift:

    @objc
    func methodName(_ param1: Type1, param2: Type2, ..., paramN: TypeN) {
        ...
    }
    

    Where types should be NSString*, NSNumber*, BOOL etc. in ObjC and String, Int, Bool etc. in Swift (https://reactnative.dev/docs/native-modules-ios#argument-types)

    For promises you should append resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject in ObjC and resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock in Swift to the end of the parameters list accordingly.