@xbenjii/react-native-braintree-dropin-ui 2.5.0 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +377 -377
- package/RNBraintreeDropIn.podspec +22 -22
- package/android/build.gradle +110 -110
- package/android/gradle/wrapper/gradle-wrapper.properties +8 -8
- package/android/gradle.properties +15 -15
- package/android/gradlew.bat +92 -92
- package/android/src/main/AndroidManifest.xml +4 -4
- package/android/src/main/java/com/xbenjii/RNBraintreeDropIn/RNBraintreeDropInModule.java +366 -366
- package/android/src/main/java/com/xbenjii/RNBraintreeDropIn/RNBraintreeDropInPackage.java +27 -27
- package/index.js +5 -5
- package/index.js.flow +42 -42
- package/ios/RNBraintreeDropIn.h +40 -40
- package/ios/RNBraintreeDropIn.m +352 -352
- package/ios/RNBraintreeDropIn.xcodeproj/project.pbxproj +291 -291
- package/ios/RNBraintreeDropIn.xcworkspace/contents.xcworkspacedata +8 -8
- package/package.json +38 -38
- package/react-native.config.js +13 -13
package/ios/RNBraintreeDropIn.m
CHANGED
@@ -1,352 +1,352 @@
|
|
1
|
-
#import "RNBraintreeDropIn.h"
|
2
|
-
#import <React/RCTUtils.h>
|
3
|
-
#import "BTThreeDSecureRequest.h"
|
4
|
-
#import "BTThreeDSecurePostalAddress.h"
|
5
|
-
#import "BTThreeDSecureAdditionalInformation.h"
|
6
|
-
|
7
|
-
@implementation RNBraintreeDropIn
|
8
|
-
|
9
|
-
- (dispatch_queue_t)methodQueue
|
10
|
-
{
|
11
|
-
return dispatch_get_main_queue();
|
12
|
-
}
|
13
|
-
RCT_EXPORT_MODULE(RNBraintreeDropIn)
|
14
|
-
|
15
|
-
RCT_EXPORT_METHOD(show:(NSDictionary*)options resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
|
16
|
-
{
|
17
|
-
BTDropInColorScheme colorScheme;
|
18
|
-
|
19
|
-
if([options[@"darkTheme"] boolValue]){
|
20
|
-
if (@available(iOS 13.0, *)) {
|
21
|
-
colorScheme = BTDropInColorSchemeDynamic;
|
22
|
-
} else {
|
23
|
-
colorScheme = BTDropInColorSchemeDark;
|
24
|
-
}
|
25
|
-
} else {
|
26
|
-
colorScheme = BTDropInColorSchemeLight;
|
27
|
-
}
|
28
|
-
|
29
|
-
BTDropInUICustomization *uiCustomization = [[BTDropInUICustomization alloc] initWithColorScheme:colorScheme];
|
30
|
-
|
31
|
-
if(options[@"fontFamily"]){
|
32
|
-
uiCustomization.fontFamily = options[@"fontFamily"];
|
33
|
-
}
|
34
|
-
if(options[@"boldFontFamily"]){
|
35
|
-
uiCustomization.boldFontFamily = options[@"boldFontFamily"];
|
36
|
-
}
|
37
|
-
|
38
|
-
self.resolve = resolve;
|
39
|
-
self.reject = reject;
|
40
|
-
self.applePayAuthorized = NO;
|
41
|
-
|
42
|
-
NSString* clientToken = options[@"clientToken"];
|
43
|
-
if (!clientToken) {
|
44
|
-
reject(@"NO_CLIENT_TOKEN", @"You must provide a client token", nil);
|
45
|
-
return;
|
46
|
-
}
|
47
|
-
|
48
|
-
BTDropInRequest *request = [[BTDropInRequest alloc] init];
|
49
|
-
request.uiCustomization = uiCustomization;
|
50
|
-
|
51
|
-
NSDictionary* threeDSecureOptions = options[@"threeDSecure"];
|
52
|
-
if (threeDSecureOptions) {
|
53
|
-
NSNumber* threeDSecureAmount = threeDSecureOptions[@"amount"];
|
54
|
-
if (!threeDSecureAmount) {
|
55
|
-
reject(@"NO_3DS_AMOUNT", @"You must provide an amount for 3D Secure", nil);
|
56
|
-
return;
|
57
|
-
}
|
58
|
-
|
59
|
-
BTThreeDSecureRequest *threeDSecureRequest = [[BTThreeDSecureRequest alloc] init];
|
60
|
-
threeDSecureRequest.amount = [NSDecimalNumber decimalNumberWithString:threeDSecureAmount.stringValue];
|
61
|
-
threeDSecureRequest.versionRequested = BTThreeDSecureVersion2;
|
62
|
-
|
63
|
-
NSString *threeDSecureEmail = threeDSecureOptions[@"email"];
|
64
|
-
if(threeDSecureEmail) {
|
65
|
-
threeDSecureRequest.email = threeDSecureEmail;
|
66
|
-
}
|
67
|
-
|
68
|
-
NSDictionary* threeDSecureBillingAddress = threeDSecureOptions[@"billingAddress"];
|
69
|
-
if(threeDSecureBillingAddress) {
|
70
|
-
BTThreeDSecurePostalAddress *billingAddress = [BTThreeDSecurePostalAddress new];
|
71
|
-
|
72
|
-
if(threeDSecureBillingAddress[@"givenName"]) {
|
73
|
-
billingAddress.givenName = threeDSecureBillingAddress[@"givenName"];
|
74
|
-
}
|
75
|
-
if(threeDSecureBillingAddress[@"surname"]) {
|
76
|
-
billingAddress.surname = threeDSecureBillingAddress[@"surname"];
|
77
|
-
}
|
78
|
-
if(threeDSecureBillingAddress[@"streetAddress"]) {
|
79
|
-
billingAddress.streetAddress = threeDSecureBillingAddress[@"streetAddress"];
|
80
|
-
}
|
81
|
-
if(threeDSecureBillingAddress[@"extendedAddress"]) {
|
82
|
-
billingAddress.extendedAddress = threeDSecureBillingAddress[@"extendedAddress"];
|
83
|
-
}
|
84
|
-
if(threeDSecureBillingAddress[@"locality"]) {
|
85
|
-
billingAddress.locality = threeDSecureBillingAddress[@"locality"];
|
86
|
-
}
|
87
|
-
if(threeDSecureBillingAddress[@"region"]) {
|
88
|
-
billingAddress.region = threeDSecureBillingAddress[@"region"];
|
89
|
-
}
|
90
|
-
if(threeDSecureBillingAddress[@"countryCodeAlpha2"]) {
|
91
|
-
billingAddress.countryCodeAlpha2 = threeDSecureBillingAddress[@"countryCodeAlpha2"];
|
92
|
-
}
|
93
|
-
if(threeDSecureBillingAddress[@"postalCode"]) {
|
94
|
-
billingAddress.postalCode = threeDSecureBillingAddress[@"postalCode"];
|
95
|
-
}
|
96
|
-
if(threeDSecureBillingAddress[@"phoneNumber"]) {
|
97
|
-
billingAddress.phoneNumber = threeDSecureBillingAddress[@"phoneNumber"];
|
98
|
-
}
|
99
|
-
threeDSecureRequest.billingAddress = billingAddress;
|
100
|
-
}
|
101
|
-
|
102
|
-
request.threeDSecureRequest = threeDSecureRequest;
|
103
|
-
|
104
|
-
}
|
105
|
-
|
106
|
-
BTAPIClient *apiClient = [[BTAPIClient alloc] initWithAuthorization:clientToken];
|
107
|
-
self.dataCollector = [[BTDataCollector alloc] initWithAPIClient:apiClient];
|
108
|
-
[self.dataCollector collectDeviceData:^(NSString * _Nonnull deviceDataCollector) {
|
109
|
-
// Save deviceData
|
110
|
-
self.deviceDataCollector = deviceDataCollector;
|
111
|
-
}];
|
112
|
-
|
113
|
-
if([options[@"vaultManager"] boolValue]){
|
114
|
-
request.vaultManager = YES;
|
115
|
-
}
|
116
|
-
|
117
|
-
if([options[@"cardDisabled"] boolValue]){
|
118
|
-
request.cardDisabled = YES;
|
119
|
-
}
|
120
|
-
|
121
|
-
if([options[@"applePay"] boolValue]){
|
122
|
-
NSString* merchantIdentifier = options[@"merchantIdentifier"];
|
123
|
-
NSString* countryCode = options[@"countryCode"];
|
124
|
-
NSString* currencyCode = options[@"currencyCode"];
|
125
|
-
NSString* merchantName = options[@"merchantName"];
|
126
|
-
NSDecimalNumber* orderTotal = [NSDecimalNumber decimalNumberWithDecimal:[options[@"orderTotal"] decimalValue]];
|
127
|
-
if(!merchantIdentifier || !countryCode || !currencyCode || !merchantName || !orderTotal){
|
128
|
-
reject(@"MISSING_OPTIONS", @"Not all required Apple Pay options were provided", nil);
|
129
|
-
return;
|
130
|
-
}
|
131
|
-
self.braintreeClient = [[BTAPIClient alloc] initWithAuthorization:clientToken];
|
132
|
-
|
133
|
-
self.paymentRequest = [[PKPaymentRequest alloc] init];
|
134
|
-
self.paymentRequest.merchantIdentifier = merchantIdentifier;
|
135
|
-
self.paymentRequest.merchantCapabilities = PKMerchantCapability3DS;
|
136
|
-
self.paymentRequest.countryCode = countryCode;
|
137
|
-
self.paymentRequest.currencyCode = currencyCode;
|
138
|
-
self.paymentRequest.supportedNetworks = @[PKPaymentNetworkAmex, PKPaymentNetworkVisa, PKPaymentNetworkMasterCard, PKPaymentNetworkDiscover, PKPaymentNetworkChinaUnionPay];
|
139
|
-
self.paymentRequest.paymentSummaryItems =
|
140
|
-
@[
|
141
|
-
[PKPaymentSummaryItem summaryItemWithLabel:merchantName amount:orderTotal]
|
142
|
-
];
|
143
|
-
if (@available(iOS 11.0, *)) {
|
144
|
-
self.paymentRequest.requiredBillingContactFields = [[NSSet<PKContactField> alloc] initWithObjects: PKContactFieldPostalAddress, PKContactFieldEmailAddress, PKContactFieldName, nil];
|
145
|
-
} else {
|
146
|
-
reject(@"MISSING_OPTIONS", @"Not all required Apple Pay options were provided", nil);
|
147
|
-
}
|
148
|
-
self.viewController = [[PKPaymentAuthorizationViewController alloc] initWithPaymentRequest: self.paymentRequest];
|
149
|
-
self.viewController.delegate = self;
|
150
|
-
}else{
|
151
|
-
request.applePayDisabled = YES;
|
152
|
-
}
|
153
|
-
|
154
|
-
if(![options[@"payPal"] boolValue]){ //disable paypal
|
155
|
-
request.paypalDisabled = YES;
|
156
|
-
}
|
157
|
-
|
158
|
-
BTDropInController *dropIn = [[BTDropInController alloc] initWithAuthorization:clientToken request:request handler:^(BTDropInController * _Nonnull controller, BTDropInResult * _Nullable result, NSError * _Nullable error) {
|
159
|
-
[self.reactRoot dismissViewControllerAnimated:YES completion:nil];
|
160
|
-
|
161
|
-
//result.paymentOptionType == .ApplePay
|
162
|
-
//NSLog(@"paymentOptionType = %ld", result.paymentOptionType);
|
163
|
-
|
164
|
-
if (error != nil) {
|
165
|
-
reject(error.localizedDescription, error.localizedDescription, error);
|
166
|
-
} else if (result.canceled) {
|
167
|
-
reject(@"USER_CANCELLATION", @"The user cancelled", nil);
|
168
|
-
} else {
|
169
|
-
if (threeDSecureOptions && [result.paymentMethod isKindOfClass:[BTCardNonce class]]) {
|
170
|
-
BTCardNonce *cardNonce = (BTCardNonce *)result.paymentMethod;
|
171
|
-
if (!cardNonce.threeDSecureInfo.liabilityShiftPossible && cardNonce.threeDSecureInfo.wasVerified) {
|
172
|
-
reject(@"3DSECURE_NOT_ABLE_TO_SHIFT_LIABILITY", @"3D Secure liability cannot be shifted", nil);
|
173
|
-
} else if (!cardNonce.threeDSecureInfo.liabilityShifted && cardNonce.threeDSecureInfo.wasVerified) {
|
174
|
-
reject(@"3DSECURE_LIABILITY_NOT_SHIFTED", @"3D Secure liability was not shifted", nil);
|
175
|
-
} else{
|
176
|
-
[[self class] resolvePayment:result deviceData:self.deviceDataCollector resolver:resolve];
|
177
|
-
}
|
178
|
-
} else if(result.paymentMethod == nil && (result.paymentMethodType == 16 || result.paymentMethodType == 17 || result.paymentMethodType == 18)){ //Apple Pay
|
179
|
-
// UIViewController *ctrl = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
|
180
|
-
// [ctrl presentViewController:self.viewController animated:YES completion:nil];
|
181
|
-
UIViewController *rootViewController = RCTPresentedViewController();
|
182
|
-
[rootViewController presentViewController:self.viewController animated:YES completion:nil];
|
183
|
-
} else{
|
184
|
-
[[self class] resolvePayment:result deviceData:self.deviceDataCollector resolver:resolve];
|
185
|
-
}
|
186
|
-
}
|
187
|
-
}];
|
188
|
-
|
189
|
-
if (dropIn != nil) {
|
190
|
-
[self.reactRoot presentViewController:dropIn animated:YES completion:nil];
|
191
|
-
} else {
|
192
|
-
reject(@"INVALID_CLIENT_TOKEN", @"The client token seems invalid", nil);
|
193
|
-
}
|
194
|
-
}
|
195
|
-
|
196
|
-
RCT_EXPORT_METHOD(getDeviceData:(NSString*)clientToken resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
|
197
|
-
{
|
198
|
-
BTAPIClient *braintreeClient = [[BTAPIClient alloc] initWithAuthorization:clientToken];
|
199
|
-
BTDataCollector *dataCollector = [[BTDataCollector alloc] initWithAPIClient:braintreeClient];
|
200
|
-
[dataCollector collectDeviceData:^(NSString * _Nonnull deviceData) {
|
201
|
-
resolve(deviceData);
|
202
|
-
}];
|
203
|
-
}
|
204
|
-
|
205
|
-
RCT_EXPORT_METHOD(fetchMostRecentPaymentMethod:(NSString*)clientToken
|
206
|
-
resolver:(RCTPromiseResolveBlock)resolve
|
207
|
-
rejecter:(RCTPromiseRejectBlock)reject)
|
208
|
-
{
|
209
|
-
[BTDropInResult mostRecentPaymentMethodForClientToken:clientToken completion:^(BTDropInResult * _Nullable result, NSError * _Nullable error) {
|
210
|
-
if (error != nil) {
|
211
|
-
reject(error.localizedDescription, error.localizedDescription, error);
|
212
|
-
} else if (result.canceled) {
|
213
|
-
reject(@"USER_CANCELLATION", @"The user cancelled", nil);
|
214
|
-
} else {
|
215
|
-
[[self class] resolvePayment:result deviceData:result.deviceData resolver:resolve];
|
216
|
-
}
|
217
|
-
}];
|
218
|
-
}
|
219
|
-
|
220
|
-
RCT_EXPORT_METHOD(tokenizeCard:(NSString*)clientToken
|
221
|
-
info:(NSDictionary*)cardInfo
|
222
|
-
resolver:(RCTPromiseResolveBlock)resolve
|
223
|
-
rejecter:(RCTPromiseRejectBlock)reject)
|
224
|
-
{
|
225
|
-
NSString *number = cardInfo[@"number"];
|
226
|
-
NSString *expirationMonth = cardInfo[@"expirationMonth"];
|
227
|
-
NSString *expirationYear = cardInfo[@"expirationYear"];
|
228
|
-
NSString *cvv = cardInfo[@"cvv"];
|
229
|
-
NSString *postalCode = cardInfo[@"postalCode"];
|
230
|
-
|
231
|
-
if (!number || !expirationMonth || !expirationYear || !cvv || !postalCode) {
|
232
|
-
reject(@"INVALID_CARD_INFO", @"Invalid card info", nil);
|
233
|
-
return;
|
234
|
-
}
|
235
|
-
|
236
|
-
BTAPIClient *braintreeClient = [[BTAPIClient alloc] initWithAuthorization:clientToken];
|
237
|
-
BTCardClient *cardClient = [[BTCardClient alloc] initWithAPIClient:braintreeClient];
|
238
|
-
BTCard *card = [[BTCard alloc] init];
|
239
|
-
card.number = number;
|
240
|
-
card.expirationMonth = expirationMonth;
|
241
|
-
card.expirationYear = expirationYear;
|
242
|
-
card.cvv = cvv;
|
243
|
-
card.postalCode = postalCode;
|
244
|
-
|
245
|
-
[cardClient tokenizeCard:card
|
246
|
-
completion:^(BTCardNonce *tokenizedCard, NSError *error) {
|
247
|
-
if (error == nil) {
|
248
|
-
resolve(tokenizedCard.nonce);
|
249
|
-
} else {
|
250
|
-
reject(@"TOKENIZE_ERROR", @"Error tokenizing card.", error);
|
251
|
-
}
|
252
|
-
}];
|
253
|
-
}
|
254
|
-
|
255
|
-
- (void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller
|
256
|
-
didAuthorizePayment:(PKPayment *)payment
|
257
|
-
handler:(nonnull void (^)(PKPaymentAuthorizationResult * _Nonnull))completion
|
258
|
-
{
|
259
|
-
|
260
|
-
// Example: Tokenize the Apple Pay payment
|
261
|
-
BTApplePayClient *applePayClient = [[BTApplePayClient alloc]
|
262
|
-
initWithAPIClient:self.braintreeClient];
|
263
|
-
[applePayClient tokenizeApplePayPayment:payment
|
264
|
-
completion:^(BTApplePayCardNonce *tokenizedApplePayPayment,
|
265
|
-
NSError *error) {
|
266
|
-
if (tokenizedApplePayPayment) {
|
267
|
-
// On success, send nonce to your server for processing.
|
268
|
-
// If applicable, address information is accessible in `payment`.
|
269
|
-
// NSLog(@"description = %@", tokenizedApplePayPayment.localizedDescription);
|
270
|
-
|
271
|
-
completion([[PKPaymentAuthorizationResult alloc] initWithStatus:PKPaymentAuthorizationStatusSuccess errors:nil]);
|
272
|
-
self.applePayAuthorized = YES;
|
273
|
-
|
274
|
-
|
275
|
-
NSMutableDictionary* result = [NSMutableDictionary new];
|
276
|
-
[result setObject:tokenizedApplePayPayment.nonce forKey:@"nonce"];
|
277
|
-
[result setObject:@"Apple Pay" forKey:@"type"];
|
278
|
-
[result setObject:[NSString stringWithFormat: @"%@ %@", @"", tokenizedApplePayPayment.type] forKey:@"description"];
|
279
|
-
[result setObject:[NSNumber numberWithBool:false] forKey:@"isDefault"];
|
280
|
-
[result setObject:self.deviceDataCollector forKey:@"deviceData"];
|
281
|
-
if(payment.billingContact && payment.billingContact.postalAddress) {
|
282
|
-
[result setObject:payment.billingContact.name.givenName forKey:@"firstName"];
|
283
|
-
[result setObject:payment.billingContact.name.familyName forKey:@"lastName"];
|
284
|
-
if(payment.billingContact.emailAddress) {
|
285
|
-
[result setObject:payment.billingContact.emailAddress forKey:@"email"];
|
286
|
-
}
|
287
|
-
NSString *street = payment.billingContact.postalAddress.street;
|
288
|
-
NSArray *splitArray = [street componentsSeparatedByString:@"\n"];
|
289
|
-
[result setObject:splitArray[0] forKey:@"addressLine1"];
|
290
|
-
if([splitArray count] > 1 && splitArray[1]) {
|
291
|
-
[result setObject:splitArray[1] forKey:@"addressLine2"];
|
292
|
-
}
|
293
|
-
[result setObject:payment.billingContact.postalAddress.city forKey:@"city"];
|
294
|
-
[result setObject:payment.billingContact.postalAddress.state forKey:@"state"];
|
295
|
-
[result setObject:payment.billingContact.postalAddress.ISOCountryCode forKey:@"country"];
|
296
|
-
[result setObject:payment.billingContact.postalAddress.postalCode forKey:@"zip1"];
|
297
|
-
}
|
298
|
-
self.resolve(result);
|
299
|
-
|
300
|
-
} else {
|
301
|
-
// Tokenization failed. Check `error` for the cause of the failure.
|
302
|
-
|
303
|
-
// Indicate failure via the completion callback:
|
304
|
-
completion([[PKPaymentAuthorizationResult alloc] initWithStatus:PKPaymentAuthorizationStatusFailure errors:nil]);
|
305
|
-
}
|
306
|
-
}];
|
307
|
-
}
|
308
|
-
|
309
|
-
// Be sure to implement -paymentAuthorizationViewControllerDidFinish:
|
310
|
-
- (void)paymentAuthorizationViewControllerDidFinish:(PKPaymentAuthorizationViewController *)controller{
|
311
|
-
[self.reactRoot dismissViewControllerAnimated:YES completion:nil];
|
312
|
-
if(self.applePayAuthorized == NO){
|
313
|
-
self.reject(@"USER_CANCELLATION", @"The user cancelled", nil);
|
314
|
-
}
|
315
|
-
}
|
316
|
-
|
317
|
-
+ (void)resolvePayment:(BTDropInResult* _Nullable)result deviceData:(NSString * _Nonnull)deviceDataCollector resolver:(RCTPromiseResolveBlock _Nonnull)resolve {
|
318
|
-
//NSLog(@"result = %@", result);
|
319
|
-
|
320
|
-
if (!result) {
|
321
|
-
resolve(nil);
|
322
|
-
return;
|
323
|
-
}
|
324
|
-
|
325
|
-
NSMutableDictionary* jsResult = [NSMutableDictionary new];
|
326
|
-
|
327
|
-
//NSLog(@"paymentMethod = %@", result.paymentMethod);
|
328
|
-
//NSLog(@"paymentIcon = %@", result.paymentIcon);
|
329
|
-
|
330
|
-
[jsResult setObject:result.paymentMethod.nonce forKey:@"nonce"];
|
331
|
-
[jsResult setObject:result.paymentMethod.type forKey:@"type"];
|
332
|
-
[jsResult setObject:result.paymentDescription forKey:@"description"];
|
333
|
-
[jsResult setObject:[NSNumber numberWithBool:result.paymentMethod.isDefault] forKey:@"isDefault"];
|
334
|
-
[jsResult setObject:deviceDataCollector forKey:@"deviceData"];
|
335
|
-
|
336
|
-
resolve(jsResult);
|
337
|
-
}
|
338
|
-
|
339
|
-
- (UIViewController*)reactRoot {
|
340
|
-
UIViewController *root = [UIApplication sharedApplication].keyWindow.rootViewController;
|
341
|
-
UIViewController *maybeModal = root.presentedViewController;
|
342
|
-
|
343
|
-
UIViewController *modalRoot = root;
|
344
|
-
|
345
|
-
if (maybeModal != nil) {
|
346
|
-
modalRoot = maybeModal;
|
347
|
-
}
|
348
|
-
|
349
|
-
return modalRoot;
|
350
|
-
}
|
351
|
-
|
352
|
-
@end
|
1
|
+
#import "RNBraintreeDropIn.h"
|
2
|
+
#import <React/RCTUtils.h>
|
3
|
+
#import "BTThreeDSecureRequest.h"
|
4
|
+
#import "BTThreeDSecurePostalAddress.h"
|
5
|
+
#import "BTThreeDSecureAdditionalInformation.h"
|
6
|
+
|
7
|
+
@implementation RNBraintreeDropIn
|
8
|
+
|
9
|
+
- (dispatch_queue_t)methodQueue
|
10
|
+
{
|
11
|
+
return dispatch_get_main_queue();
|
12
|
+
}
|
13
|
+
RCT_EXPORT_MODULE(RNBraintreeDropIn)
|
14
|
+
|
15
|
+
RCT_EXPORT_METHOD(show:(NSDictionary*)options resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
|
16
|
+
{
|
17
|
+
BTDropInColorScheme colorScheme;
|
18
|
+
|
19
|
+
if([options[@"darkTheme"] boolValue]){
|
20
|
+
if (@available(iOS 13.0, *)) {
|
21
|
+
colorScheme = BTDropInColorSchemeDynamic;
|
22
|
+
} else {
|
23
|
+
colorScheme = BTDropInColorSchemeDark;
|
24
|
+
}
|
25
|
+
} else {
|
26
|
+
colorScheme = BTDropInColorSchemeLight;
|
27
|
+
}
|
28
|
+
|
29
|
+
BTDropInUICustomization *uiCustomization = [[BTDropInUICustomization alloc] initWithColorScheme:colorScheme];
|
30
|
+
|
31
|
+
if(options[@"fontFamily"]){
|
32
|
+
uiCustomization.fontFamily = options[@"fontFamily"];
|
33
|
+
}
|
34
|
+
if(options[@"boldFontFamily"]){
|
35
|
+
uiCustomization.boldFontFamily = options[@"boldFontFamily"];
|
36
|
+
}
|
37
|
+
|
38
|
+
self.resolve = resolve;
|
39
|
+
self.reject = reject;
|
40
|
+
self.applePayAuthorized = NO;
|
41
|
+
|
42
|
+
NSString* clientToken = options[@"clientToken"];
|
43
|
+
if (!clientToken) {
|
44
|
+
reject(@"NO_CLIENT_TOKEN", @"You must provide a client token", nil);
|
45
|
+
return;
|
46
|
+
}
|
47
|
+
|
48
|
+
BTDropInRequest *request = [[BTDropInRequest alloc] init];
|
49
|
+
request.uiCustomization = uiCustomization;
|
50
|
+
|
51
|
+
NSDictionary* threeDSecureOptions = options[@"threeDSecure"];
|
52
|
+
if (threeDSecureOptions) {
|
53
|
+
NSNumber* threeDSecureAmount = threeDSecureOptions[@"amount"];
|
54
|
+
if (!threeDSecureAmount) {
|
55
|
+
reject(@"NO_3DS_AMOUNT", @"You must provide an amount for 3D Secure", nil);
|
56
|
+
return;
|
57
|
+
}
|
58
|
+
|
59
|
+
BTThreeDSecureRequest *threeDSecureRequest = [[BTThreeDSecureRequest alloc] init];
|
60
|
+
threeDSecureRequest.amount = [NSDecimalNumber decimalNumberWithString:threeDSecureAmount.stringValue];
|
61
|
+
threeDSecureRequest.versionRequested = BTThreeDSecureVersion2;
|
62
|
+
|
63
|
+
NSString *threeDSecureEmail = threeDSecureOptions[@"email"];
|
64
|
+
if(threeDSecureEmail) {
|
65
|
+
threeDSecureRequest.email = threeDSecureEmail;
|
66
|
+
}
|
67
|
+
|
68
|
+
NSDictionary* threeDSecureBillingAddress = threeDSecureOptions[@"billingAddress"];
|
69
|
+
if(threeDSecureBillingAddress) {
|
70
|
+
BTThreeDSecurePostalAddress *billingAddress = [BTThreeDSecurePostalAddress new];
|
71
|
+
|
72
|
+
if(threeDSecureBillingAddress[@"givenName"]) {
|
73
|
+
billingAddress.givenName = threeDSecureBillingAddress[@"givenName"];
|
74
|
+
}
|
75
|
+
if(threeDSecureBillingAddress[@"surname"]) {
|
76
|
+
billingAddress.surname = threeDSecureBillingAddress[@"surname"];
|
77
|
+
}
|
78
|
+
if(threeDSecureBillingAddress[@"streetAddress"]) {
|
79
|
+
billingAddress.streetAddress = threeDSecureBillingAddress[@"streetAddress"];
|
80
|
+
}
|
81
|
+
if(threeDSecureBillingAddress[@"extendedAddress"]) {
|
82
|
+
billingAddress.extendedAddress = threeDSecureBillingAddress[@"extendedAddress"];
|
83
|
+
}
|
84
|
+
if(threeDSecureBillingAddress[@"locality"]) {
|
85
|
+
billingAddress.locality = threeDSecureBillingAddress[@"locality"];
|
86
|
+
}
|
87
|
+
if(threeDSecureBillingAddress[@"region"]) {
|
88
|
+
billingAddress.region = threeDSecureBillingAddress[@"region"];
|
89
|
+
}
|
90
|
+
if(threeDSecureBillingAddress[@"countryCodeAlpha2"]) {
|
91
|
+
billingAddress.countryCodeAlpha2 = threeDSecureBillingAddress[@"countryCodeAlpha2"];
|
92
|
+
}
|
93
|
+
if(threeDSecureBillingAddress[@"postalCode"]) {
|
94
|
+
billingAddress.postalCode = threeDSecureBillingAddress[@"postalCode"];
|
95
|
+
}
|
96
|
+
if(threeDSecureBillingAddress[@"phoneNumber"]) {
|
97
|
+
billingAddress.phoneNumber = threeDSecureBillingAddress[@"phoneNumber"];
|
98
|
+
}
|
99
|
+
threeDSecureRequest.billingAddress = billingAddress;
|
100
|
+
}
|
101
|
+
|
102
|
+
request.threeDSecureRequest = threeDSecureRequest;
|
103
|
+
|
104
|
+
}
|
105
|
+
|
106
|
+
BTAPIClient *apiClient = [[BTAPIClient alloc] initWithAuthorization:clientToken];
|
107
|
+
self.dataCollector = [[BTDataCollector alloc] initWithAPIClient:apiClient];
|
108
|
+
[self.dataCollector collectDeviceData:^(NSString * _Nonnull deviceDataCollector) {
|
109
|
+
// Save deviceData
|
110
|
+
self.deviceDataCollector = deviceDataCollector;
|
111
|
+
}];
|
112
|
+
|
113
|
+
if([options[@"vaultManager"] boolValue]){
|
114
|
+
request.vaultManager = YES;
|
115
|
+
}
|
116
|
+
|
117
|
+
if([options[@"cardDisabled"] boolValue]){
|
118
|
+
request.cardDisabled = YES;
|
119
|
+
}
|
120
|
+
|
121
|
+
if([options[@"applePay"] boolValue]){
|
122
|
+
NSString* merchantIdentifier = options[@"merchantIdentifier"];
|
123
|
+
NSString* countryCode = options[@"countryCode"];
|
124
|
+
NSString* currencyCode = options[@"currencyCode"];
|
125
|
+
NSString* merchantName = options[@"merchantName"];
|
126
|
+
NSDecimalNumber* orderTotal = [NSDecimalNumber decimalNumberWithDecimal:[options[@"orderTotal"] decimalValue]];
|
127
|
+
if(!merchantIdentifier || !countryCode || !currencyCode || !merchantName || !orderTotal){
|
128
|
+
reject(@"MISSING_OPTIONS", @"Not all required Apple Pay options were provided", nil);
|
129
|
+
return;
|
130
|
+
}
|
131
|
+
self.braintreeClient = [[BTAPIClient alloc] initWithAuthorization:clientToken];
|
132
|
+
|
133
|
+
self.paymentRequest = [[PKPaymentRequest alloc] init];
|
134
|
+
self.paymentRequest.merchantIdentifier = merchantIdentifier;
|
135
|
+
self.paymentRequest.merchantCapabilities = PKMerchantCapability3DS;
|
136
|
+
self.paymentRequest.countryCode = countryCode;
|
137
|
+
self.paymentRequest.currencyCode = currencyCode;
|
138
|
+
self.paymentRequest.supportedNetworks = @[PKPaymentNetworkAmex, PKPaymentNetworkVisa, PKPaymentNetworkMasterCard, PKPaymentNetworkDiscover, PKPaymentNetworkChinaUnionPay];
|
139
|
+
self.paymentRequest.paymentSummaryItems =
|
140
|
+
@[
|
141
|
+
[PKPaymentSummaryItem summaryItemWithLabel:merchantName amount:orderTotal]
|
142
|
+
];
|
143
|
+
if (@available(iOS 11.0, *)) {
|
144
|
+
self.paymentRequest.requiredBillingContactFields = [[NSSet<PKContactField> alloc] initWithObjects: PKContactFieldPostalAddress, PKContactFieldEmailAddress, PKContactFieldName, nil];
|
145
|
+
} else {
|
146
|
+
reject(@"MISSING_OPTIONS", @"Not all required Apple Pay options were provided", nil);
|
147
|
+
}
|
148
|
+
self.viewController = [[PKPaymentAuthorizationViewController alloc] initWithPaymentRequest: self.paymentRequest];
|
149
|
+
self.viewController.delegate = self;
|
150
|
+
}else{
|
151
|
+
request.applePayDisabled = YES;
|
152
|
+
}
|
153
|
+
|
154
|
+
if(![options[@"payPal"] boolValue]){ //disable paypal
|
155
|
+
request.paypalDisabled = YES;
|
156
|
+
}
|
157
|
+
|
158
|
+
BTDropInController *dropIn = [[BTDropInController alloc] initWithAuthorization:clientToken request:request handler:^(BTDropInController * _Nonnull controller, BTDropInResult * _Nullable result, NSError * _Nullable error) {
|
159
|
+
[self.reactRoot dismissViewControllerAnimated:YES completion:nil];
|
160
|
+
|
161
|
+
//result.paymentOptionType == .ApplePay
|
162
|
+
//NSLog(@"paymentOptionType = %ld", result.paymentOptionType);
|
163
|
+
|
164
|
+
if (error != nil) {
|
165
|
+
reject(error.localizedDescription, error.localizedDescription, error);
|
166
|
+
} else if (result.canceled) {
|
167
|
+
reject(@"USER_CANCELLATION", @"The user cancelled", nil);
|
168
|
+
} else {
|
169
|
+
if (threeDSecureOptions && [result.paymentMethod isKindOfClass:[BTCardNonce class]]) {
|
170
|
+
BTCardNonce *cardNonce = (BTCardNonce *)result.paymentMethod;
|
171
|
+
if (!cardNonce.threeDSecureInfo.liabilityShiftPossible && cardNonce.threeDSecureInfo.wasVerified) {
|
172
|
+
reject(@"3DSECURE_NOT_ABLE_TO_SHIFT_LIABILITY", @"3D Secure liability cannot be shifted", nil);
|
173
|
+
} else if (!cardNonce.threeDSecureInfo.liabilityShifted && cardNonce.threeDSecureInfo.wasVerified) {
|
174
|
+
reject(@"3DSECURE_LIABILITY_NOT_SHIFTED", @"3D Secure liability was not shifted", nil);
|
175
|
+
} else{
|
176
|
+
[[self class] resolvePayment:result deviceData:self.deviceDataCollector resolver:resolve];
|
177
|
+
}
|
178
|
+
} else if(result.paymentMethod == nil && (result.paymentMethodType == 16 || result.paymentMethodType == 17 || result.paymentMethodType == 18)){ //Apple Pay
|
179
|
+
// UIViewController *ctrl = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
|
180
|
+
// [ctrl presentViewController:self.viewController animated:YES completion:nil];
|
181
|
+
UIViewController *rootViewController = RCTPresentedViewController();
|
182
|
+
[rootViewController presentViewController:self.viewController animated:YES completion:nil];
|
183
|
+
} else{
|
184
|
+
[[self class] resolvePayment:result deviceData:self.deviceDataCollector resolver:resolve];
|
185
|
+
}
|
186
|
+
}
|
187
|
+
}];
|
188
|
+
|
189
|
+
if (dropIn != nil) {
|
190
|
+
[self.reactRoot presentViewController:dropIn animated:YES completion:nil];
|
191
|
+
} else {
|
192
|
+
reject(@"INVALID_CLIENT_TOKEN", @"The client token seems invalid", nil);
|
193
|
+
}
|
194
|
+
}
|
195
|
+
|
196
|
+
RCT_EXPORT_METHOD(getDeviceData:(NSString*)clientToken resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
|
197
|
+
{
|
198
|
+
BTAPIClient *braintreeClient = [[BTAPIClient alloc] initWithAuthorization:clientToken];
|
199
|
+
BTDataCollector *dataCollector = [[BTDataCollector alloc] initWithAPIClient:braintreeClient];
|
200
|
+
[dataCollector collectDeviceData:^(NSString * _Nonnull deviceData) {
|
201
|
+
resolve(deviceData);
|
202
|
+
}];
|
203
|
+
}
|
204
|
+
|
205
|
+
RCT_EXPORT_METHOD(fetchMostRecentPaymentMethod:(NSString*)clientToken
|
206
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
207
|
+
rejecter:(RCTPromiseRejectBlock)reject)
|
208
|
+
{
|
209
|
+
[BTDropInResult mostRecentPaymentMethodForClientToken:clientToken completion:^(BTDropInResult * _Nullable result, NSError * _Nullable error) {
|
210
|
+
if (error != nil) {
|
211
|
+
reject(error.localizedDescription, error.localizedDescription, error);
|
212
|
+
} else if (result.canceled) {
|
213
|
+
reject(@"USER_CANCELLATION", @"The user cancelled", nil);
|
214
|
+
} else {
|
215
|
+
[[self class] resolvePayment:result deviceData:result.deviceData resolver:resolve];
|
216
|
+
}
|
217
|
+
}];
|
218
|
+
}
|
219
|
+
|
220
|
+
RCT_EXPORT_METHOD(tokenizeCard:(NSString*)clientToken
|
221
|
+
info:(NSDictionary*)cardInfo
|
222
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
223
|
+
rejecter:(RCTPromiseRejectBlock)reject)
|
224
|
+
{
|
225
|
+
NSString *number = cardInfo[@"number"];
|
226
|
+
NSString *expirationMonth = cardInfo[@"expirationMonth"];
|
227
|
+
NSString *expirationYear = cardInfo[@"expirationYear"];
|
228
|
+
NSString *cvv = cardInfo[@"cvv"];
|
229
|
+
NSString *postalCode = cardInfo[@"postalCode"];
|
230
|
+
|
231
|
+
if (!number || !expirationMonth || !expirationYear || !cvv || !postalCode) {
|
232
|
+
reject(@"INVALID_CARD_INFO", @"Invalid card info", nil);
|
233
|
+
return;
|
234
|
+
}
|
235
|
+
|
236
|
+
BTAPIClient *braintreeClient = [[BTAPIClient alloc] initWithAuthorization:clientToken];
|
237
|
+
BTCardClient *cardClient = [[BTCardClient alloc] initWithAPIClient:braintreeClient];
|
238
|
+
BTCard *card = [[BTCard alloc] init];
|
239
|
+
card.number = number;
|
240
|
+
card.expirationMonth = expirationMonth;
|
241
|
+
card.expirationYear = expirationYear;
|
242
|
+
card.cvv = cvv;
|
243
|
+
card.postalCode = postalCode;
|
244
|
+
|
245
|
+
[cardClient tokenizeCard:card
|
246
|
+
completion:^(BTCardNonce *tokenizedCard, NSError *error) {
|
247
|
+
if (error == nil) {
|
248
|
+
resolve(tokenizedCard.nonce);
|
249
|
+
} else {
|
250
|
+
reject(@"TOKENIZE_ERROR", @"Error tokenizing card.", error);
|
251
|
+
}
|
252
|
+
}];
|
253
|
+
}
|
254
|
+
|
255
|
+
- (void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller
|
256
|
+
didAuthorizePayment:(PKPayment *)payment
|
257
|
+
handler:(nonnull void (^)(PKPaymentAuthorizationResult * _Nonnull))completion
|
258
|
+
{
|
259
|
+
|
260
|
+
// Example: Tokenize the Apple Pay payment
|
261
|
+
BTApplePayClient *applePayClient = [[BTApplePayClient alloc]
|
262
|
+
initWithAPIClient:self.braintreeClient];
|
263
|
+
[applePayClient tokenizeApplePayPayment:payment
|
264
|
+
completion:^(BTApplePayCardNonce *tokenizedApplePayPayment,
|
265
|
+
NSError *error) {
|
266
|
+
if (tokenizedApplePayPayment) {
|
267
|
+
// On success, send nonce to your server for processing.
|
268
|
+
// If applicable, address information is accessible in `payment`.
|
269
|
+
// NSLog(@"description = %@", tokenizedApplePayPayment.localizedDescription);
|
270
|
+
|
271
|
+
completion([[PKPaymentAuthorizationResult alloc] initWithStatus:PKPaymentAuthorizationStatusSuccess errors:nil]);
|
272
|
+
self.applePayAuthorized = YES;
|
273
|
+
|
274
|
+
|
275
|
+
NSMutableDictionary* result = [NSMutableDictionary new];
|
276
|
+
[result setObject:tokenizedApplePayPayment.nonce forKey:@"nonce"];
|
277
|
+
[result setObject:@"Apple Pay" forKey:@"type"];
|
278
|
+
[result setObject:[NSString stringWithFormat: @"%@ %@", @"", tokenizedApplePayPayment.type] forKey:@"description"];
|
279
|
+
[result setObject:[NSNumber numberWithBool:false] forKey:@"isDefault"];
|
280
|
+
[result setObject:self.deviceDataCollector forKey:@"deviceData"];
|
281
|
+
if(payment.billingContact && payment.billingContact.postalAddress) {
|
282
|
+
[result setObject:payment.billingContact.name.givenName forKey:@"firstName"];
|
283
|
+
[result setObject:payment.billingContact.name.familyName forKey:@"lastName"];
|
284
|
+
if(payment.billingContact.emailAddress) {
|
285
|
+
[result setObject:payment.billingContact.emailAddress forKey:@"email"];
|
286
|
+
}
|
287
|
+
NSString *street = payment.billingContact.postalAddress.street;
|
288
|
+
NSArray *splitArray = [street componentsSeparatedByString:@"\n"];
|
289
|
+
[result setObject:splitArray[0] forKey:@"addressLine1"];
|
290
|
+
if([splitArray count] > 1 && splitArray[1]) {
|
291
|
+
[result setObject:splitArray[1] forKey:@"addressLine2"];
|
292
|
+
}
|
293
|
+
[result setObject:payment.billingContact.postalAddress.city forKey:@"city"];
|
294
|
+
[result setObject:payment.billingContact.postalAddress.state forKey:@"state"];
|
295
|
+
[result setObject:payment.billingContact.postalAddress.ISOCountryCode forKey:@"country"];
|
296
|
+
[result setObject:payment.billingContact.postalAddress.postalCode forKey:@"zip1"];
|
297
|
+
}
|
298
|
+
self.resolve(result);
|
299
|
+
|
300
|
+
} else {
|
301
|
+
// Tokenization failed. Check `error` for the cause of the failure.
|
302
|
+
|
303
|
+
// Indicate failure via the completion callback:
|
304
|
+
completion([[PKPaymentAuthorizationResult alloc] initWithStatus:PKPaymentAuthorizationStatusFailure errors:nil]);
|
305
|
+
}
|
306
|
+
}];
|
307
|
+
}
|
308
|
+
|
309
|
+
// Be sure to implement -paymentAuthorizationViewControllerDidFinish:
|
310
|
+
- (void)paymentAuthorizationViewControllerDidFinish:(PKPaymentAuthorizationViewController *)controller{
|
311
|
+
[self.reactRoot dismissViewControllerAnimated:YES completion:nil];
|
312
|
+
if(self.applePayAuthorized == NO){
|
313
|
+
self.reject(@"USER_CANCELLATION", @"The user cancelled", nil);
|
314
|
+
}
|
315
|
+
}
|
316
|
+
|
317
|
+
+ (void)resolvePayment:(BTDropInResult* _Nullable)result deviceData:(NSString * _Nonnull)deviceDataCollector resolver:(RCTPromiseResolveBlock _Nonnull)resolve {
|
318
|
+
//NSLog(@"result = %@", result);
|
319
|
+
|
320
|
+
if (!result) {
|
321
|
+
resolve(nil);
|
322
|
+
return;
|
323
|
+
}
|
324
|
+
|
325
|
+
NSMutableDictionary* jsResult = [NSMutableDictionary new];
|
326
|
+
|
327
|
+
//NSLog(@"paymentMethod = %@", result.paymentMethod);
|
328
|
+
//NSLog(@"paymentIcon = %@", result.paymentIcon);
|
329
|
+
|
330
|
+
[jsResult setObject:result.paymentMethod.nonce forKey:@"nonce"];
|
331
|
+
[jsResult setObject:result.paymentMethod.type forKey:@"type"];
|
332
|
+
[jsResult setObject:result.paymentDescription forKey:@"description"];
|
333
|
+
[jsResult setObject:[NSNumber numberWithBool:result.paymentMethod.isDefault] forKey:@"isDefault"];
|
334
|
+
[jsResult setObject:deviceDataCollector forKey:@"deviceData"];
|
335
|
+
|
336
|
+
resolve(jsResult);
|
337
|
+
}
|
338
|
+
|
339
|
+
- (UIViewController*)reactRoot {
|
340
|
+
UIViewController *root = [UIApplication sharedApplication].keyWindow.rootViewController;
|
341
|
+
UIViewController *maybeModal = root.presentedViewController;
|
342
|
+
|
343
|
+
UIViewController *modalRoot = root;
|
344
|
+
|
345
|
+
if (maybeModal != nil) {
|
346
|
+
modalRoot = maybeModal;
|
347
|
+
}
|
348
|
+
|
349
|
+
return modalRoot;
|
350
|
+
}
|
351
|
+
|
352
|
+
@end
|