@xbenjii/react-native-braintree-dropin-ui 2.4.0 → 2.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|