2

I am attempted to create a React-native 'Native Module' (BankedSdk) in a project developed on an M1 Macbook. - However any attempt to initialise the module returns an empty object.

This is the example (2020) repo that works on my intel machine ✅: https://github.com/banked/banked-react-native-sdk-example

On my larger (M1 based) project i have integrated it like this:

Within my iOS folder I have three new files:

BankedSdk.h:

#import <Foundation/Foundation.h>
#import "React/RCTBridge.h"

NS_ASSUME_NONNULL_BEGIN

@interface BankedSdk : NSObject <RCTBridgeModule>

@end

NS_ASSUME_NONNULL_END

BankedSdk.m:

#import "BankedSdk.h"
#import "React/RCTLog.h"
#import "BankedReactNativeExample-Swift.h"

@implementation BankedSdk

RCT_EXPORT_MODULE();

RCT_EXPORT_METHOD(initialise:(NSString *)apiKey)
{
  [[BankedCheckoutWrapper shared] setUpWithApiKey: apiKey];
}

RCT_EXPORT_METHOD(openBankedSdk:(NSString *)paymentId and:(NSString *)continueUrl)
{
  dispatch_async(dispatch_get_main_queue(), ^{
    UIViewController *presentedViewController = RCTPresentedViewController();
    
    [[BankedCheckoutWrapper shared] presentCheckoutWithViewController: presentedViewController  paymentId: paymentId continueURL: continueUrl];
  });
}

RCT_EXPORT_METHOD(handlePaymentForURL:(NSURL *)url)
{
  [[BankedCheckoutWrapper shared] handlePaymentWithUrl: url];
}

@end

BankedWrapper.swift:

import Foundation
import UIKit
import Banked

@objc class BankedCheckoutWrapper: NSObject {
     
  @objc static let shared: BankedCheckoutWrapper = BankedCheckoutWrapper()
  
  @objc func setUp(apiKey: String) {
    BankedCheckout.shared.setUp(apiKey)
  }
  
  @objc func presentCheckout(viewController: UIViewController ,paymentId: String, continueURL: String) {
    BankedCheckout.shared.presentCheckout(viewController , paymentId: paymentId, action: .pay, continueURL: continueURL) { response in
      switch response {
      case .success:
        print("success")
      case .failure(let error):
        print("error \(error)")
      }
    }
  }
  
  @objc func handlePayment(url: URL) {
    
    BankedCheckout.shared.handlePaymentWithURL(url, action: .pay) { response in
      switch response {
      case .success:
        print("success")
      case .failure(let error):
        print("error \(error)")
      }
    }
  }
}

Then I have a component called Banked Sdk which reads as follows:

import { NativeModules } from 'react-native'

const { BankedSdk } = NativeModules

export default BankedSdk

Which is called as follows:

import React, { useState, useEffect } from 'react'
[import a bunch of other stuff]
import BankedSdk from '@components/BankedSdk'


//Main file stuff
 
// -> TEST NATIVE MODULES BUTTON

  function checkNativeModules() {
    const apiKey = "xxxxxxxxxxxxxxxx"
    BankedSdk.initialise(apiKey)
    BankedSdk.openBankedSdk("xxxxxxxxxxxxxxxx", "urlHere")
   console.log("Banked Sdk in Test Button: ", BankedSdk)
  }




  return (
    <>
     // Other UI stuff
      <Button
       title="Initiate Native Mod"
       color="primary"
       onPress={checkNativeModules}
       />
    </>
  )
}

export default Button

However - My NativeModules are logging out as an empty object:

Native Modules: {}

with the error:

ERROR TypeError: null is not an object (evaluating '_BankedSdk.default.initialise')

(see images)

enter image description here enter image description here

***** UPDATE in response to @user3193920 *****

This was eventually fixed with the following:

in Podfile:

# ENABLES BANKED (DYMANIC FRAMEWORK)
  pod 'Banked', '0.0.25', :build_type => :dynamic_framework 

BankedSdk.h:

#import <Foundation/Foundation.h>
#import "React/RCTBridge.h"

NS_ASSUME_NONNULL_BEGIN

@interface BankedSdk : NSObject <RCTBridgeModule>

@end


NS_ASSUME_NONNULL_END

BankedSdk.m:

#import "BankedSdk.h"
#import "React/RCTLog.h"
#import "systemSpendAppReactNativeOnM1-Swift.h"

@implementation BankedSdk

RCT_EXPORT_MODULE();

RCT_EXPORT_METHOD(initialise:(NSString *)apiKey)
{
  dispatch_async(dispatch_get_main_queue(), ^{
    [[BankedCheckoutWrapper shared] setUpWithApiKey: apiKey];
  });
}

RCT_EXPORT_METHOD(openBankedSdk:(NSString *)paymentId and:(NSString *)continueUrl and:(RCTPromiseResolveBlock)resolve and:(RCTPromiseRejectBlock)reject)
{
  dispatch_async(dispatch_get_main_queue(), ^{
    UIViewController *presentedViewController = RCTPresentedViewController();

    [[BankedCheckoutWrapper shared] presentCheckoutWithViewController: presentedViewController  paymentId: paymentId continueURL: continueUrl resolve: resolve rejecter: reject];
  });
}

RCT_EXPORT_METHOD(handlePaymentForURL:(NSURL *)url)
{
  dispatch_async(dispatch_get_main_queue(), ^{
    [[BankedCheckoutWrapper shared] handlePaymentWithUrl: url];
  });
}

@end

And BankedWrapper.swift:

import Foundation
import UIKit
import Banked

@objc class BankedCheckoutWrapper: NSObject {

  private var presentingCheckout = false {
    didSet {
      print("+++ presentingCheckout \(presentingCheckout.description)")
    }
  }
  @objc static let shared: BankedCheckoutWrapper = BankedCheckoutWrapper()
  
  @objc func setUp(apiKey: String) {
    BankedCheckout.shared.setUp(apiKey)
  }
  
  @objc func presentCheckout(viewController: UIViewController ,paymentId: String, continueURL: String,  resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
    presentingCheckout = true
    return BankedCheckout.shared.presentCheckout(viewController , paymentId: paymentId, action: .pay, continueURL: continueURL) { [weak self] response in
      guard let self = self else { return }
      if self.presentingCheckout {
        switch response {
        case .success:
          print("+++ success presentCheckout")
          resolve("success")
        case .failure(let error):
          print("+++ error presentCheckout \(error)")
          let errorNew = NSError(domain: "", code: 200, userInfo: nil)
          reject("Caught error", "error", errorNew)
        }
      }
      self.presentingCheckout = false
    }
  }
  
  @objc func handlePayment(url: URL) {
    BankedCheckout.shared.handlePaymentWithURL(url, action: .pay) { response in
      switch response {
      case .success:
        print("+++ success handlePayment")
      case .failure(let error):
        print("+++ error handlePayment \(error)")
      }
    }
  }
}
David Pears
  • 435
  • 2
  • 6
  • 17
  • I have the same issue. Did you find any workaround ? – user3193920 Feb 12 '23 at 22:43
  • I dug through some old code to find the fix we did (see above, under the '***** UPDATE **** line) , because i remember we lost DAYS on this going back and forth. I don't know if this will help in your situation - but i hope it will steer you in the right direction! D – David Pears Feb 15 '23 at 15:00
  • I don't understand what the fix is, was it adding "Banked" to the podfile and where did you pull the version number 0.0.25 from? Where in the podfile did you place this line of code? – afterburn Jul 24 '23 at 20:19

0 Answers0