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)
***** 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)")
}
}
}
}