Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ repositories {
}

android {
compileSdkVersion 28
compileSdkVersion 29
buildToolsVersion "28.0.3"

defaultConfig {
minSdkVersion 23
targetSdkVersion 28
minSdkVersion 24
targetSdkVersion 29
versionCode 1
versionName "1.0"
}
Expand All @@ -46,10 +46,13 @@ android {
}

dependencies {
implementation 'com.facebook.react:react-native:0.59.10'
api 'com.braintreepayments.api:braintree:3.9.0'
implementation 'com.facebook.react:react-native:0.61.5'
api 'com.braintreepayments.api:braintree:3.17.4'
api 'com.braintreepayments.api:data-collector:3.9.0'
api 'com.squareup.okhttp3:okhttp:3.14.4'
implementation 'com.braintreepayments.api:three-d-secure:3.8.0'
implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.6'

implementation 'com.braintreepayments.api:google-payment:3.5.0'
api 'com.google.android.gms:play-services-wallet:18.1.3'
}
120 changes: 115 additions & 5 deletions android/src/main/java/com/pw/droplet/braintree/Braintree.java
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
package com.pw.droplet.braintree;

import android.content.Intent;
import android.util.Log;

import androidx.appcompat.app.AppCompatActivity;

import com.braintreepayments.api.BraintreeFragment;
import com.braintreepayments.api.Card;
import com.braintreepayments.api.DataCollector;
import com.braintreepayments.api.GooglePayment;
import com.braintreepayments.api.PayPal;
import com.braintreepayments.api.exceptions.BraintreeError;
import com.braintreepayments.api.exceptions.ErrorWithResponse;
import com.braintreepayments.api.interfaces.BraintreeCancelListener;
import com.braintreepayments.api.interfaces.BraintreeErrorListener;
import com.braintreepayments.api.interfaces.BraintreeResponseListener;
import com.braintreepayments.api.interfaces.ConfigurationListener;
import com.braintreepayments.api.interfaces.PaymentMethodNonceCreatedListener;
import com.braintreepayments.api.models.CardBuilder;
import com.braintreepayments.api.models.Configuration;
import com.braintreepayments.api.models.GooglePaymentCardNonce;
import com.braintreepayments.api.models.GooglePaymentConfiguration;
import com.braintreepayments.api.models.GooglePaymentRequest;
import com.braintreepayments.api.models.PayPalAccountNonce;
import com.braintreepayments.api.models.PayPalRequest;
import com.braintreepayments.api.models.PaymentMethodNonce;
Expand All @@ -25,8 +30,9 @@
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.WritableNativeMap;
import com.google.android.gms.wallet.TransactionInfo;
import com.google.android.gms.wallet.WalletConstants;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

Expand Down Expand Up @@ -86,6 +92,7 @@ public void setup(final String token, final Callback successCallback, final Call
}

if (this.mBraintreeFragment != null) {
this.mBraintreeFragment.addListener(mConfigurationListener);
this.mBraintreeFragment.addListener(mCancelListener);
this.mBraintreeFragment.addListener(mPaymentNonceCreatedListener);
this.mBraintreeFragment.addListener(mErrorListener);
Expand Down Expand Up @@ -160,6 +167,86 @@ public void getCardNonce(final ReadableMap parameters, final Callback successCal
Card.tokenize(this.mBraintreeFragment, cardBuilder);
}

@ReactMethod
public void googlePayIsReadyToPay(final Callback successCallback, final Callback errorCallback) {
try {
GooglePayment.isReadyToPay(mBraintreeFragment, new BraintreeResponseListener<Boolean>() {
@Override
public void onResponse(Boolean isReadyToPay) {
successCallback.invoke(isReadyToPay);
}
});
} catch (Exception e) {
Log.e(TAG, "Error calling GooglePayment.isReadyToPay", e);
errorCallback.invoke(e.getMessage());
}
}

@ReactMethod
public void googlePayRequestPayment(final String googlePayMerchantId, final String amount, final String currencyCode, final boolean billingAddressRequired, final Callback successCallback, final Callback errorCallback) {
this.successCallback = successCallback;
this.errorCallback = errorCallback;

GooglePaymentRequest request = new GooglePaymentRequest()
.transactionInfo(TransactionInfo.newBuilder()
.setTotalPrice(amount) // format: 0.00
.setTotalPriceStatus(WalletConstants.TOTAL_PRICE_STATUS_FINAL)
.setCurrencyCode(currencyCode) // ISO 4217 currency code
.build());

request.billingAddressRequired(billingAddressRequired);
//request.setAllowedCardNetworks(); TODO: pass down array of allowed card networks
//request.allowPrepaidCards(); TODO: add as parameter
//request.environment(); TODO: add as parameter (PRODUCTION or TEST)

if (googlePayMerchantId != null && googlePayMerchantId.length() > 0) {
// Optional in sandbox; if set in sandbox, this value must be a valid production Google Merchant ID
request.googleMerchantId(googlePayMerchantId);
}

GooglePayment.requestPayment(mBraintreeFragment, request);
}

private void googlePayNonceCallback(GooglePaymentCardNonce googlePayNonce) {
if (googlePayNonce == null || googlePayNonce.getNonce() == null) {
this.errorCallback.invoke("GooglePay nonce is null");
this.errorCallback = null;
this.successCallback = null;
return;
}

WritableNativeMap map = new WritableNativeMap();
map.putString("nonce", googlePayNonce.getNonce());

if (googlePayNonce.getCardType() == null) {
this.errorCallback.invoke("GooglePay cardType is null");
this.errorCallback = null;
this.successCallback = null;
return;
}
map.putString("cardType", googlePayNonce.getCardType());

if (googlePayNonce.getLastFour() != null) {
map.putString("lastFour", googlePayNonce.getLastFour());
}

if (googlePayNonce.getEmail() != null) {
map.putString("email", googlePayNonce.getEmail());
}

if (googlePayNonce.getBillingAddress() != null) {
map.putMap("billingAddress", getAddressMap(googlePayNonce.getBillingAddress()));
}

if (googlePayNonce.getShippingAddress() != null) {
map.putMap("shippingAddress", getAddressMap(googlePayNonce.getShippingAddress()));
}

this.successCallback.invoke(map);
this.errorCallback = null;
this.successCallback = null;
}

@ReactMethod
public void payPalRequestOneTimePayment(final String amount, final String currencyCode, final Callback successCallback, final Callback errorCallback) {
PayPal.requestOneTimePayment(this.mBraintreeFragment, getPayPalRequest(amount, currencyCode, successCallback, errorCallback));
Expand Down Expand Up @@ -205,11 +292,11 @@ private void payPalNonceCallback(PayPalAccountNonce payPalAccountNonce) {
map.putString("lastName", payPalAccountNonce.getLastName());

if (payPalAccountNonce.getBillingAddress() != null) {
map.putMap("billingAddress", getPayPalAddressMap(payPalAccountNonce.getBillingAddress()));
map.putMap("billingAddress", getAddressMap(payPalAccountNonce.getBillingAddress()));
}

if (payPalAccountNonce.getShippingAddress() != null) {
map.putMap("shippingAddress", getPayPalAddressMap(payPalAccountNonce.getShippingAddress()));
map.putMap("shippingAddress", getAddressMap(payPalAccountNonce.getShippingAddress()));
}

this.successCallback.invoke(map);
Expand Down Expand Up @@ -242,7 +329,7 @@ private PayPalRequest getPayPalRequest(final @Nullable String amount, final Stri
.intent(PayPalRequest.INTENT_AUTHORIZE);
}

private WritableMap getPayPalAddressMap(PostalAddress address) {
private ReadableMap getAddressMap(PostalAddress address) {
WritableNativeMap map = new WritableNativeMap();
map.putString("recipientName", address.getRecipientName());
map.putString("streetAddress", address.getStreetAddress());
Expand All @@ -254,6 +341,27 @@ private WritableMap getPayPalAddressMap(PostalAddress address) {
return map;
}

private ConfigurationListener mConfigurationListener = new ConfigurationListener() {
@Override
public void onConfigurationFetched(Configuration configuration) {
GooglePaymentConfiguration gPayConfig = configuration.getGooglePayment();
if (gPayConfig != null) {
// TODO remove all these logs before going live
Log.d(TAG, "GooglePay environment: " + gPayConfig.getEnvironment());
Log.d(TAG, "GooglePay display name: " + gPayConfig.getDisplayName());
Log.d(TAG, "GooglePay authorization fingerprint: " + gPayConfig.getGoogleAuthorizationFingerprint());
if (gPayConfig.getSupportedNetworks() != null) {
for (String network : gPayConfig.getSupportedNetworks()) {
Log.d(TAG, "GooglePay supported network: " + network);
}
}
}
else {
Log.w(TAG, "GooglePay configuration is null");
}
}
};

private BraintreeCancelListener mCancelListener = new BraintreeCancelListener() {
@Override
public void onCancel(int requestCode) {
Expand All @@ -266,6 +374,8 @@ public void onCancel(int requestCode) {
public void onPaymentMethodNonceCreated(PaymentMethodNonce paymentMethodNonce) {
if (paymentMethodNonce instanceof PayPalAccountNonce) {
payPalNonceCallback((PayPalAccountNonce)paymentMethodNonce);
} else if (paymentMethodNonce instanceof GooglePaymentCardNonce) {
googlePayNonceCallback((GooglePaymentCardNonce)paymentMethodNonce);
} else {
nonceCallback(paymentMethodNonce.getNonce());
}
Expand Down
26 changes: 26 additions & 0 deletions index.android.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@ export type PayPalSuccess = {
shippingAddress: Address | null,
};

export type GooglePaySuccess = {
nonce: string,
cardType: string,
email: string | null,
lastFour: string | null,
billingAddress: Address | null,
shippingAddress: Address | null,
};

export type Address = {
recipientName: string | null,
streetAddress: string | null,
Expand All @@ -36,6 +45,23 @@ class Braintree {
});
}

checkIsGooglePayReadyToPay(): Promise<boolean> {
return new Promise((resolve: (result: boolean)=>void, reject: (reason: string)=>void) => {
NativeBraintree.googlePayIsReadyToPay(
(isReadyToPay: boolean) => resolve(isReadyToPay),
(error: string) => reject(error))
});
}

getGooglePayNonce(googlePayMerchantId: string, amount: number, currencyCode: string, isBillingAddressRequired: boolean): Promise<GooglePaySuccess> {
return new Promise((resolve: (result: GooglePaySuccess)=>void, reject: (reason: string)=>void) => {
NativeBraintree.googlePayRequestPayment(googlePayMerchantId, amount, currencyCode, isBillingAddressRequired,
(googlePaySuccess: GooglePaySuccess) => resolve(googlePaySuccess),
(error: string) => reject(error)
);
});
}

getPayPalOneTimePaymentNonce(amount: number, currencyCode: string): Promise<PayPalSuccess> {
return new Promise((resolve: (result: PayPalSuccess)=>void, reject: (reason: string)=>void) => {
NativeBraintree.payPalRequestOneTimePayment(amount, currencyCode,
Expand Down