У меня есть приложение React Native, которое отлично работает, и мне нужно интегрировать SDK для iOS в Objective-C.Я создал мост, и он работает, поскольку я могу вызывать собственные методы iOS из React Native и получать ответы через эмиттер обратно в мое приложение React Native.
Проблема заключается в том, что один из вызовов метода SDKпросит передать контроллер представления, так как SDK, похоже, имеет предварительно скомпилированную раскадровку, которую он хочет отображать.Однако я не смог определить, какой контроллер представления передать. Я предполагаю, что раскадровка SDK будет отображаться поверх этого контроллера до тех пор, пока он не будет отклонен.
Может кто-нибудь подсказать мне из кода ниже, что мне не хватает?Поскольку я не очень хорошо знаком с Objective-C, возможно, мне не хватает чего-то фундаментального.
Мой файл моста выглядит так:
#import "AuthorizeNet.h"
// import RCTBridge
#if __has_include(<React/RCTBridge.h>)
#import <React/RCTBridge.h>
#elif __has_include(“RCTBridge.h”)
#import “RCTBridge.h”
#else
#import “React/RCTBridge.h”
#endif
// import RCTEventDispatcher
#if __has_include(<React/RCTEventDispatcher.h>)
#import <React/RCTEventDispatcher.h>
#elif __has_include(“RCTEventDispatcher.h”)
#import “RCTEventDispatcher.h”
#else
#import “React/RCTEventDispatcher.h”
#endif
#import <AuthNet.h>
#import <MobileDeviceLoginRequest.h>
#import <React/RCTLog.h>
#import <AnetEMVManager.h>
#import <AnetBTObject.h>
@implementation AuthorizeNet
@synthesize bridge = _bridge;
// Export a native module
RCT_EXPORT_MODULE();
// Export constants
- (NSDictionary *)constantsToExport
{
return @{
@"EXAMPLE": @"example"
};
}
- (NSArray<NSString *> *)supportedEvents
{
return @[
@"SCAN_DEVICES",
@"DEVICE_CONNECTION",
];
}
// Return the native view that represents your React component
- (UIView *)view
{
return [[UIView alloc] init];
}
// Export methods to a native module
RCT_EXPORT_METHOD(login)
{
RCTLogInfo(@"Trying to login to gateway");
[self loginToGateway];
}
RCT_EXPORT_METHOD(scanDevices)
{
dispatch_async(dispatch_get_main_queue(), ^{
RCTLogInfo(@"Trying to scan devices");
[self scanBTDevices];
});
}
RCT_EXPORT_METHOD(connectToDevice:(NSInteger *)index)
{
dispatch_async(dispatch_get_main_queue(), ^{
RCTLogInfo(@"Trying to connect to device");
[self connectToBTDevice:index];
});
}
RCT_EXPORT_METHOD(disconnectDevice)
{
dispatch_async(dispatch_get_main_queue(), ^{
RCTLogInfo(@"Disconnecting device");
[self disconnectBTDevice];
});
}
RCT_EXPORT_METHOD(swipeAndSend:(NSString *)amount :(NSString *)paymentId)
{
dispatch_async(dispatch_get_main_queue(), ^{
RCTLogInfo(@"Swipe and send transaction");
[self swipeAndSendTransaction:amount :paymentId];
});
}
#pragma mark - Private methods
NSString* sessionToken;
AnetEMVManager *AnetMan;
// Implement methods that you want to export to the native module
- (void) emitDeviceListToRN: (NSString *)eventName :(NSArray *)foundDevices {
[self sendEventWithName: eventName body: foundDevices];
}
- (void) emitDeviceConnectionToRN: (NSString *)eventName :(NSNumber *)connected {
[self sendEventWithName: eventName body: connected];
}
// API methods
- (void) loginToGateway {
RCTLogInfo(@"login to gateway called");
[AnetMan setLoggingEnabled:TRUE];
MobileDeviceLoginRequest *mobileDeviceLoginRequest =
[MobileDeviceLoginRequest mobileDeviceLoginRequest];
mobileDeviceLoginRequest.anetApiRequest.merchantAuthentication.name = @"xxxxx";
mobileDeviceLoginRequest.anetApiRequest.merchantAuthentication.password = @"xxxxx";
mobileDeviceLoginRequest.anetApiRequest.merchantAuthentication.mobileDeviceId = @"xxxxx";
AuthNet *an = [AuthNet getInstance];
[an setDelegate:self];
[an setLoggingEnabled:true];
[an mobileDeviceLoginRequest: mobileDeviceLoginRequest];
}
- (void) scanBTDevices {
RCTLogInfo(@"Scan devices called");
AnetEMVTerminalMode iTerminalMode = AnetEMVModeInsertOrSwipe;
AnetEMVConnectionMode iConnectionMode = AnetEMVConnectionModeBluetooth;
AnetMan = [AnetEMVManager initWithCurrecyCode:@"USD" terminalID:@"xxxxx" skipSignature:TRUE showReceipt: FALSE];
[AnetMan setLoggingEnabled:TRUE];
RCTLogInfo(([AnetMan loggingEnabled]) ? @"True" : @"False" );
[AnetMan setTerminalMode:iTerminalMode];
[AnetMan setConnectionMode:iConnectionMode];
BTScanDeviceListBlock deviceListBlock = ^void(NSArray * _Nullable iBTDeviceList, AnetBTDeviceStatusCode status) {
RCTLogInfo(@"Scanned devices");
NSMutableArray *foundDevices = [NSMutableArray array];
for (AnetBTObject *object in iBTDeviceList) {
RCTLogInfo(object.name);
[foundDevices addObject:object.name];
}
[self emitDeviceListToRN:@"SCAN_DEVICES" :foundDevices];
};
[AnetMan setDeviceListBlock:deviceListBlock];
[AnetMan scanBTDevicesList];
}
- (void) connectToBTDevice:(NSInteger)index {
BTDeviceConnected deviceConnectedBlock = ^void(BOOL isConnectionSuccessful, NSString * _Nullable iDeviceName, AnetBTDeviceStatusCode status) {
RCTLogInfo(@"Device connected block called");
if (status == AnetBTDeviceConnected) {
RCTLogInfo(@"Device connected");
} else if (status == AnetBTDeviceDisconnected) {
RCTLogInfo(@"Device disconnected");
} else if (status == AnetBTDeviceConnectionTimeout) {
RCTLogInfo(@"Device timeout");
} else if (status == AnetBTDeviceAlreadyConnectedError) {
RCTLogInfo(@"Device already connected");
} else if (status == AnetBTDeviceFailToStart) {
RCTLogInfo(@"Device fail to start");
} else if (status == AnetBTDeviceIllegalStateException) {
RCTLogInfo(@"Device illegal state exception");
} else if (status == AnetBTDeviceGenericError) {
RCTLogInfo(@"Device generic error");
} else {
RCTLogInfo(@"Different error");
}
[self emitDeviceConnectionToRN:@"DEVICE_CONNECTION" :@(isConnectionSuccessful)];
};
[AnetMan setDeviceConnectedBlock:deviceConnectedBlock];
[AnetMan connectBTDeviceAtIndex:index];
[self loginToGateway];
}
- (void) disconnectBTDevice {
[AnetMan disconnectBTDevices];
[self emitDeviceConnectionToRN:@"DEVICE_CONNECTION" :0];
}
- (void) swipeAndSendTransaction:(NSString *)amount :(NSString *)paymentId {
RCTLogInfo(@"Swipe and send starting");
AnetEMVTransactionRequest *request = [AnetManShared transactionRequest];
request.emvTransactionType = EMVTransactionType_Payment;
request.amount = amount;
request.anetApiRequest.merchantAuthentication.sessionToken = sessionToken;
request.anetApiRequest.merchantAuthentication.mobileDeviceId = @"xxxxx";
request.order.invoiceNumber = paymentId;
request.order.orderDescription = @"xxxxx";
request.retail.marketType = @"2";
request.retail.deviceType = @"7";
RequestCompletionBlock completionBlock = ^void(AnetEMVTransactionResponse * _Nullable response, AnetEMVError *_Nullable error) {
if (error) {
RCTLogInfo(@"Error!");
}
RCTLogInfo(response.responseCode);
};
CancelActionBlock andCancelActionBlock = ^void {
RCTLogInfo(@"Cancelled");
};
[AnetMan startQuickChipWithTransactionRequest:request forPaperReceiptCase:FALSE presentingViewController:###WHAT SHOULD I PASS IN HERE?### completionBlock:completionBlock andCancelActionBlock:andCancelActionBlock];
}
- (void) mobileDeviceLoginSucceeded:(MobileDeviceLoginResponse *)response {
RCTLogInfo(@"Login succeeded");
sessionToken = response.sessionToken;
};
@end
Методы "scanBTDevices", "connectToBTDevice",«disconnectBTDevice» и «loginToGateway» работают как положено, а метод swipeAndSendTransaction - нет.После выхода «Консоль и отправка запуска» на консоль, больше ничего не происходит.Он не запускает блок завершения, он не запускает блок отмены и не выдает ошибку.Я могу только предположить, что это потому, что контроллеры представления, которые я пытался передать, неверны и не могут отображать раскадровку, которую он хочет.
Документация SDK очень плохая, и это все, что она говорит оэтот метод:
/**
* Start a Quick Chip transaction with EMV request, presenting view controller and completion block.
* @param iTransactionRequest A request object of AnetEMVTransactionRequest
* @param iPaperReceiptCase if this is true then the Merchant needs to get the paper receipt signed by the customer and settle the transaction later on.
AnetEMVManager will leave the trasaction in Auth_Only state.
* @param iPresentingController A presenting controller object. EMV controller will be presented on top of it
* @param iRequestCompletionBlock A completion block. Block will be executed on success or failure of EMV transaction
* @param iCancelActionBlock A Cancel block. Block will be executed when cancel action is taken
*/
- (void)startQuickChipWithTransactionRequest:(AnetEMVTransactionRequest * _Nonnull)iTransactionRequest
forPaperReceiptCase:(BOOL)iPaperReceiptCase
presentingViewController:(UIViewController * _Nonnull)iPresentingController
completionBlock:(RequestCompletionBlock _Nonnull)iRequestCompletionBlock
andCancelActionBlock:(CancelActionBlock _Nonnull)iCancelActionBlock;
SDK, который я пытаюсь реализовать, можно найти здесь: https://github.com/AuthorizeNet/inperson-sdk-ios
Есть пример приложения (которое работает), но оно написано на Swift, поэтому яне в состоянии точно понять, что он делает, к тому же ему не нужно общаться с React Native, поэтому у него нет дополнительных сложностей.
Если кому-то нужна дополнительная информация, чтобы помочь, тогда, пожалуйста, дайте мне знать,Спасибо за чтение!