Integrated Braintree payment gateway in android application

Posted By : Keshav Gupta | 24-Nov-2017

Key points to understand integration flow in the android client:

The 1android application will send Braintree token request to the local server where Braintree is configured.

2.The server will send Braintree token in response which will be used to invoke braintree gateway in android.

3.Now android app will communicate to Braintree server and get payment nounce in response.

4.Next amount and nounce are sent to payment api in local server.

5.Finally server will communicate to braintree server and will respond to android client with braintree server response.

Step1:In app/build.gradle add these dependencies.

 compile 'com.braintreepayments.api:drop-in:3.0.8'
 compile 'com.android.volley:volley:1.0.0'

In above code, volley dependecy is required to invoke server interaction.

Step2 :We will create a layout for hosting payment.In layout we will take a

EditText for taking user amount as input and Button to naviagate to braintree gateway.

 

 

Step3 : We will create a class named as BrainTreePaymentActivity. and  will initialize all ui elements and we will firstly set visibility of our layout to gone so that no ui interaction can be done till we get the braintree token.Below there is my method you can use your own method to call Rest Api for braintree token.

 private void callForGetBrainTreeToken() {
        if (UtilityMethods.isInternetAvailable(activity)) {
            Map<String, String> header = NetworkConstants.setNetworkCallHeader(userData.getToken());
            Map<String, String> params = new HashMap<>();
            apiManager.callNonJsonRequestApi(WebserviceUrl.BRAINTREETOKEN_URL, NetworkConstants.apimethod[0],
                    ApiRequestCodes.requestCode_GetBraintreeToken, header, params, true);
        } else {
            Toast.makeText(activity,R.string.internetalert,Toast.LENGTH_SHORT).show();
        }
    }

 

 

Step4:Now on success of previous Api call, you will get braintree token from server and set whole layout visibility to visible and Now initate braintree Dropin call.Code will be like this

public void onBraintreeSubmit() {
        DropInRequest dropInRequest = new DropInRequest()
                .clientToken(token);
        dropInRequest.disablePayPal();
        startActivityForResult(dropInRequest.getIntent(this), REQUEST_CODE);
    }

Above code will open a dropin which will  show credit card drop in section.Now user can select here and can enter card info.

 

 

Step5:Now we will handle activity call back where will handle success or failure of transactions.We will override onActivityResult() where we will get nonce of payment which will be sending to our local server for further processing using a REST Api.Code will be like this

@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == REQUEST_CODE) {
            if (resultCode == Activity.RESULT_OK) {
                DropInResult result = data.getParcelableExtra(DropInResult.EXTRA_DROP_IN_RESULT);
                PaymentMethodNonce nonce = result.getPaymentMethodNonce();
                String stringNonce = nonce.getNonce();
                Logger.LogDebug("mylog", "Result: " + stringNonce);
                // Send payment price with the nonce
                // use the result to update your UI and send the payment method nonce to your server
                    amount = String.valueOf(tvAmount.getText().toString());
                    callForBrainTreePayment(amount,stringNonce);
            } else if (resultCode == Activity.RESULT_CANCELED) {
                // the user canceled
                Logger.LogDebug("mylog", "user canceled");
            } else {
                // handle errors here, an exception may be available in
                Exception error = (Exception) data.getSerializableExtra(DropInActivity.EXTRA_ERROR);
                Logger.LogDebug("mylog", "Error : " + error.toString());
            }
        }
    }

Step6: Finally nonce generated by braintree server above will be sent to local server using REST api is defined by method listed below.

 private void callForBrainTreePayment(String amount,String nonce) {
        if (UtilityMethods.isInternetAvailable(activity)) {
            Map<String, String> header = NetworkConstants.setNetworkCallHeader(userData.getToken());
            Map<String, String> params = new HashMap<>();
            String updatedUrl=WebserviceUrl.BRAINTREEPAYMENT_URL+"?amount="+amount+"&nonce="+nonce;
            apiManager.callNonJsonRequestApi(updatedUrl,NetworkConstants.apimethod[1],ApiRequestCodes.requestCode_BraintreePayment,header,params,true);
        } else {
            Toast.makeText(activity,R.string.internetalert,Toast.LENGTH_SHORT).show();
        }
    }

Step7:Now local server will return braintree server response to android application.We can navigate to any page for further on success result.

Final Code for this class be like this: 

public class BrainTreePaymentActivity extends AppCompatActivity implements MaritalStatusSelected {
    final int REQUEST_CODE = 1;
    String token, amount;
    @BindView(R.id.btnPay) CustomButton btnpay;
    @BindView(R.id.llHolder) LinearLayout llHolder;
    @BindView(R.id.ivBackBtn)ImageView iv_BackBtn;
    @BindView(R.id.tv_screen_title)CustomTextView tvscreentitle;
    @BindView(R.id.ll_vlayout_packages)LinearLayout llVlayoutPackages;
    @BindView(R.id.et_packages)CustomTextView etPackages;
    @BindView(R.id.tvAmount)CustomTextView tvAmount;

    private ApiManager apiManager;
    private ApiResponseInterface apiResponseInterface;
    private AppCompatActivity activity;
    private SessionManager sm;
    private LoginData userData;
    private ArrayList<String> arrayListPackages;
    private PopupWindow popupWindow1;
    private NonPrimitiveMethod nPM;
    private double amountPacakges;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.active_layout_braintree_payment);
        ButterKnife.bind(this);
        initClass();
        setUpNetworkApiCall();
        callForGetPackages();
        /*  api call class to get token   */
        //callForGetBrainTreeToken();
    }
   private void initClass()
   {
       activity=BrainTreePaymentActivity.this;
       sm=new SessionManager(activity);
       nPM=new NonPrimitiveMethod(activity);
       userData=sm.getLoginData();
       tvscreentitle.setText(getString(R.string.Payment));
   }
    @OnClick({R.id.btnPay,R.id.ivBackBtn,R.id.et_packages})
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btnPay:
                onBraintreeSubmit();
                break;
            case R.id.et_packages:
                if (arrayListPackages != null && arrayListPackages.size() > 0) {
                  showPopUpMStatus(etPackages,arrayListPackages,llVlayoutPackages,this);
                }
                break;
            case R.id.ivBackBtn:
                finish();
                overridePendingTransition(R.anim.slide_from_right,R.anim.slide_to_left);
                break;
        }
    }


    private void showPopUpMStatus(CustomTextView et, ArrayList<String> arrayListPopup,LinearLayout llLayout, MaritalStatusSelected maritalStatusSelected) {
        popupWindow1 = nPM.runpopupmaritalstatus(activity, arrayListPopup, et,llLayout,maritalStatusSelected);
        popupWindow1.setBackgroundDrawable(new BitmapDrawable());
        popupWindow1.setOutsideTouchable(true);
        int marginHeight = getResources().getDimensionPixelSize(R.dimen.margin_250);
        popupWindow1.setHeight(marginHeight);
        popupWindow1.showAsDropDown(et);
    }
    private void setUpNetworkApiCall()
    {
        apiResponseInterface=new ApiResponseInterface() {
            @Override
            public void isError(VolleyError volleyError, int ServiceCode) {
                String message = NetworkConstants.errorMesg(activity, volleyError);
                if(activity!=null) {
                    if (message != null && !(message.equals(getString(R.string.valid_mesg_session_expiry))))
                        Toast.makeText(activity, message, Toast.LENGTH_SHORT).show();
                    if(ServiceCode==ApiRequestCodes.requestCode_GetBraintreeToken) {
                        llHolder.setVisibility(View.GONE);
                    }
                }
            }

            @Override
            public void isSuccess(String response, int ServiceCode) {
                Logger.LogError("RESPONSE", response);
                JSONObject jsonObject = null;
                switch (ServiceCode) {
                    case ApiRequestCodes.requestCode_GetBraintreeToken:
                        try {
                            jsonObject = new JSONObject(response);
                             token=jsonObject.optString("data");
                            llHolder.setVisibility(View.VISIBLE);
                        } catch (JSONException e) {
                        }
                        break;
                    case ApiRequestCodes.requestCode_GetPackagesInfo:
                        try {
                            jsonObject = new JSONObject(response);
                            JSONObject dataObj=jsonObject.optJSONObject("data");
                            String maxnopackages=dataObj.optString("maxNoPackagesCanPurchase");
                            amountPacakges=dataObj.optDouble(NetworkConstants.amount);
                            arrayListPackages=new ArrayList<>();
                            for (int i = 1; i <= Integer.valueOf(maxnopackages); i++) {
                                arrayListPackages.add(i + " Package");
                            }
                            Logger.LogInfo("Size",""+arrayListPackages.size()+""+arrayListPackages.toString());
                            callForGetBrainTreeToken();
                        } catch (JSONException e) {
                        }
                        break;
                    case ApiRequestCodes.requestCode_BraintreePayment:
                        try {
                            jsonObject = new JSONObject(response);


                        } catch (JSONException e) {
                        }
                        break;
                }
            }
        };
        apiManager=new ApiManager(activity,apiResponseInterface);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == REQUEST_CODE) {
            if (resultCode == Activity.RESULT_OK) {
                DropInResult result = data.getParcelableExtra(DropInResult.EXTRA_DROP_IN_RESULT);
                PaymentMethodNonce nonce = result.getPaymentMethodNonce();
                String stringNonce = nonce.getNonce();
                Logger.LogDebug("mylog", "Result: " + stringNonce);
                // Send payment price with the nonce
                // use the result to update your UI and send the payment method nonce to your server
                    amount = String.valueOf(tvAmount.getText().toString());
                    callForBrainTreePayment(amount,stringNonce);
            } else if (resultCode == Activity.RESULT_CANCELED) {
                // the user canceled
                Logger.LogDebug("mylog", "user canceled");
            } else {
                // handle errors here, an exception may be available in
                Exception error = (Exception) data.getSerializableExtra(DropInActivity.EXTRA_ERROR);
                Logger.LogDebug("mylog", "Error : " + error.toString());
            }
        }
    }

    public void onBraintreeSubmit() {
        DropInRequest dropInRequest = new DropInRequest()
                .clientToken(token);
        dropInRequest.disablePayPal();
        startActivityForResult(dropInRequest.getIntent(this), REQUEST_CODE);
    }

    private void callForGetBrainTreeToken() {
        if (UtilityMethods.isInternetAvailable(activity)) {
            Map<String, String> header = NetworkConstants.setNetworkCallHeader(userData.getToken());
            Map<String, String> params = new HashMap<>();
            apiManager.callNonJsonRequestApi(WebserviceUrl.BRAINTREETOKEN_URL, NetworkConstants.apimethod[0],
                    ApiRequestCodes.requestCode_GetBraintreeToken, header, params, true);
        } else {
            Toast.makeText(activity,R.string.internetalert,Toast.LENGTH_SHORT).show();
        }
    }
    private void callForGetPackages() {
        if (UtilityMethods.isInternetAvailable(activity)) {
            Map<String, String> params = new HashMap<>();
            apiManager.callNonJsonRequestApi(WebserviceUrl.PACKAGESINFO_URL, NetworkConstants.apimethod[0],
                    ApiRequestCodes.requestCode_GetPackagesInfo,params, params, false);
        } else {
            Toast.makeText(activity,R.string.internetalert,Toast.LENGTH_SHORT).show();
        }
    }
    private void callForBrainTreePayment(String amount,String nonce) {
        if (UtilityMethods.isInternetAvailable(activity)) {
            Map<String, String> header = NetworkConstants.setNetworkCallHeader(userData.getToken());
            Map<String, String> params = new HashMap<>();
            String updatedUrl=WebserviceUrl.BRAINTREEPAYMENT_URL+"?amount="+amount+"&nonce="+nonce;
            apiManager.callNonJsonRequestApi(updatedUrl,NetworkConstants.apimethod[1],ApiRequestCodes.requestCode_BraintreePayment,header,params,true);
        } else {
            Toast.makeText(activity,R.string.internetalert,Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    public void setMaritalStatus(int selected) {
        tvAmount.setText(String.valueOf((selected+1)* amountPacakges));
    }
}

Please note that you can find all discussed methods above and their uses.So you can consider this class for integration as referrence.

About Author

Author Image
Keshav Gupta

Keshav Gupta is Android Developer in Oodles, he always look forward for new tasks and new things to learn more.

Request for Proposal

Name is required

Comment is required

Sending message..