Android Ecommerce Shopping App With PayPal Payment Integration Part 2

This is the second and final part of our android tutorial on Android Ecommerce Shopping app with PayPal payment integration.

If you have not read the first part of the tutorial I will suggest you go over it because this part is a continuation of the previous part.

The link to the first part is here – Android Ecommerce Shopping App with PayPal Integration

Also checkout paid version of complete android ecommerce shopping app

Once more, this is screen-shot of the application that we are creating to give you an idea what we plan to achieve.

ANDROID PROJECT SCREENSHOT
androidpaypal

We finished discussing about the content of the network package folder in the first part of the android shopping cart now we will continue to discussion about other packages we used in this application and the files they content.

 

Helpers Package Folder

Create a new package folder and name it helpers. This folder will continue all our helper java files. Each of the files has a distinct feature they add to the application. The list of the file as below.

 

Constants.java

Create a new java file inside the helpers package folder and name it Constants.java. This is hold all the constant variables we will use in android shopping cart application.

Open the file and add the code below to it.

public static final String PRODUCT_ID = "product_id";
package com.inducesmile.androidpayexample.helpers;
import com.google.android.gms.wallet.WalletConstants;
public class Constants {
    public static final int WALLET_ENVIRONMENT = WalletConstants.ENVIRONMENT_TEST;
    public static final String MERCHANT_NAME = "Fashion Store";
    public static final String CURRENCY_CODE_USD = "USD";
    public static final String PUBLISHABLE_KEY = "key";
    public static final String VERSION = "version";
    public static final String SHARED_PREF = "shared_pref";
    public static final String PRODUCT_COUNT = "product_count";
    public static final String PRODUCT_ID = "product_id";
}

 

MySharedPreference.java

Follow the same process of creating a new java file in helpers package folder but now we will name this file MySharedPreference.java.

Open the file and add below code to it.

import android.content.Context;
import android.content.SharedPreferences;
public class MySharedPreference {
    private SharedPreferences prefs;
    private Context context;
    public MySharedPreference(Context context){
        this.context = context;
        prefs = context.getSharedPreferences(Constants.SHARED_PREF, Context.MODE_PRIVATE);
    }
    public void addProductToTheCart(String product){
        SharedPreferences.Editor edits = prefs.edit();
        edits.putString(Constants.PRODUCT_ID, product);
        edits.apply();
    }
    public String retrieveProductFromCart(){
        return prefs.getString(Constants.PRODUCT_ID, "");
    }
    public void addProductCount(int productCount){
        SharedPreferences.Editor edits = prefs.edit();
        edits.putInt(Constants.PRODUCT_COUNT, productCount);
        edits.apply();
    }
    public int retrieveProductCount(){
       return prefs.getInt(Constants.PRODUCT_COUNT, 0);
    }
}

 

SimpleDividerItemDecoration.java

This file is a decorator class file that add a line break after each item in the RecyclerView. Create a new java class with the name as above. Copy and paste the code below to it.

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import com.inducesmile.androidpayexample.R;
public class SimpleDividerItemDecoration extends RecyclerView.ItemDecoration {
    private Drawable mDivider;
    public SimpleDividerItemDecoration(Context context) {
        mDivider = ContextCompat.getDrawable(context, R.drawable.line_divider);
    }
    @Override
    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
        int left = parent.getPaddingLeft();
        int right = parent.getWidth() - parent.getPaddingRight();
        int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            View child = parent.getChildAt(i);
            RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
            int top = child.getBottom() + params.bottomMargin;
            int bottom = top + mDivider.getIntrinsicHeight();
            mDivider.setBounds(left, top, right, bottom);
            mDivider.draw(c);
        }
    }
}

 

SpacesItemDecorator.java

Just like the previous class, this class is also a decorator class that adds some specified margin in between items in a GridLayout in RecyclerView.

Open the file and add the code below to it.

import android.graphics.Rect;
import android.support.v7.widget.RecyclerView;
import android.view.View;
public class SpacesItemDecoration extends RecyclerView.ItemDecoration {
    private int spanCount;
    private int spacing;
    private boolean includeEdge;
    public SpacesItemDecoration(int spanCount, int spacing, boolean includeEdge) {
        this.spanCount = spanCount;
        this.spacing = spacing;
        this.includeEdge = includeEdge;
    }
    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        int position = parent.getChildAdapterPosition(view);
        int column = position % spanCount;
        if (includeEdge) {
            outRect.left = spacing - column * spacing / spanCount;
            outRect.right = (column + 1) * spacing / spanCount;
            if (position < spanCount) {
                outRect.top = spacing;
            }
            outRect.bottom = spacing;
        } else {
            outRect.left = column * spacing / spanCount;
            outRect.right = spacing - (column + 1) * spacing / spanCount;
            if (position >= spanCount) {
                outRect.top = spacing;
            }
        }
    }
}

 

Entities Package Folder

we are going to create a new package folder in our android shopping cart application. This time we will name it entities. It will contain some Entity class.

 

ProductObject.java

Inside the entities package folder, create a new file and name it ProductObject.java. Open the file and add the code below to it.

public class ProductObject {
    private int productId;
    private String productName;
    private int productImage;
    private String productDescription;
    private double productPrice;
    private int productSize;
    private String productColor;
    public ProductObject(int productId, String productName, int productImage, String productDescription, double productPrice, int productSize, String productColor) {
        this.productId = productId;
        this.productName = productName;
        this.productImage = productImage;
        this.productDescription = productDescription;
        this.productPrice = productPrice;
        this.productSize = productSize;
        this.productColor = productColor;
    }
    public int getProductId() {
        return productId;
    }
    public String getProductName() {
        return productName;
    }
    public int getProductImage() {
        return productImage;
    }
    public String getProductDescription() {
        return productDescription;
    }
    public double getProductPrice() {
        return productPrice;
    }
    public int getProductSize() {
        return productSize;
    }
    public String getProductColor() {
        return productColor;
    }
    @Override
    public String toString() {
        return "Product id and name: " + productId + " " + productName;
    }
}

Now we will move over to see how we can integrate PayPal in our android shopping cart as a way to receive payment from product purchase.

 

Android PayPal Integration

PayPal is one of the best company in the world when it come to accepting and making payment in a reliable and secure way.

Paypal has made available android SDK library for developers who will like to integrate it in the application as a means of getting payment from their client.

Before we proceed into details on how to integrate PayPal in Android, we are required to create a text or Sandbox account that we will use to test our application to make sure that it is working before we move it to production. This also have an advantage of not letting you use a real money to test your application while still in development.

 

Create a Sandbox Account

If you ready have a PayPal account, your can click this link (https://developer.paypal.com/developer/accounts/create) to go to the PayPal developer page

Fill the form in the page as shown below

pal1

Then choose to create a new app and your will see a page like the image shown below.

pal2

When you submit the page, you will be provide with your client id information. This value will be add to your application and make sure you keep it in a safe place. See Image below.

pal3

 

Add PayPal SDK

For our application to make use of all the classes and method provided by PayPal library, we are going to add PayPal SDK to get access to this classes.

In the app build.gradle file, open the file and in the dependence section, add this code to it.

compile('com.paypal.sdk:paypal-android-sdk:2.14.4') {
    exclude group: 'io.card'
}

You can see that we are excluding the use of Card.io library. This is an android library you can use to scan a credit card detail for card payment.

I wrote a tutorial on Android Card,io Integration Example and I will suggest you have a look at the library.

We are going to create a new activity and we will name the new activity class PayPalCheckoutActivity.java with its corresponding layout. This will contain a Button View control that will initiate payment with PayPal.

 

Activity_pay_pal_checkout.xml

Open the activity_pay_pal_checkout.xml file and add the Button View to it.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    android:gravity="center"
    android:background="@color/colorPrimaryLight"
    tools:context="com.inducesmile.androidpayexample.PayPalCheckoutActivity">
    <Button
        android:id="@+id/pay_pal_button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="@dimen/_12sdp"
        android:textSize="@dimen/_16sdp"
        android:textColor="@color/icons"
        android:background="@color/colorPrimaryDark"
        android:text="@string/pay_with_paypal" />
</LinearLayout>

 

PayPalCheckoutActivity.java

The PayPalCheckoutActivity class will get the instance of the button view control and attach a click listener to it.

A configuration member class is add to this class which will contain the PayPal client Id information as shown.

private static PayPalConfiguration config = new PayPalConfiguration()
        .environment(PayPalConfiguration.ENVIRONMENT_NO_NETWORK)
        .clientId("CLIENT_ID");

We will create a method that will initialize payment and call the method startActivityForResult(intent, 0);

private void initializePayPalPayment(){
    PayPalPayment payment = new PayPalPayment(new BigDecimal(String.valueOf(totalCostPrice)), "USD", "Female Cloths", PayPalPayment.PAYMENT_INTENT_SALE);
    Intent intent = new Intent(this, PaymentActivity.class);
    intent.putExtra(PayPalService.EXTRA_PAYPAL_CONFIGURATION, config);
    intent.putExtra(PaymentActivity.EXTRA_PAYMENT, payment);
    startActivityForResult(intent, 0);
}

In OnActivityResult() method, we are going to check if the payment with PayPal is successful or not.

If the payment is successful, we are going to retrieve the Payment Id and state of the payment and send it to our server for payment verification.

PayPal recommended that we implement this system like this in other to eliminate the chance of fraudulent payment.

So the complete code for this class is shown below.

import android.app.Activity;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import com.android.volley.DefaultRetryPolicy;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.inducesmile.androidpayexample.jsonEntityObjects.PaymentResponseObject;
import com.inducesmile.androidpayexample.jsonEntityObjects.ServerObject;
import com.inducesmile.androidpayexample.network.GsonRequest;
import com.inducesmile.androidpayexample.network.VolleySingleton;
import com.paypal.android.sdk.payments.PayPalConfiguration;
import com.paypal.android.sdk.payments.PayPalPayment;
import com.paypal.android.sdk.payments.PayPalService;
import com.paypal.android.sdk.payments.PaymentActivity;
import com.paypal.android.sdk.payments.PaymentConfirmation;
import org.json.JSONException;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
public class PayPalCheckoutActivity extends AppCompatActivity {
    private static final String TAG = PayPalCheckoutActivity.class.getSimpleName();
    private static final int MY_SOCKET_TIMEOUT_MS = 5000;
    private static final String SERVER_PATH = "PATH_TO_YOUR_SERVER/token.php";
    private double totalCostPrice;
    private static PayPalConfiguration config = new PayPalConfiguration()
            .environment(PayPalConfiguration.ENVIRONMENT_NO_NETWORK)
            .clientId("CLIENT_ID");
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_pay_pal_checkout);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        setTitle(getString(R.string.pay_with_paypal));
        totalCostPrice = getIntent().getExtras().getDouble("TOTAL_PRICE");
        Log.d(TAG, "Price " + totalCostPrice);
        Intent intent = new Intent(this, PayPalService.class);
        intent.putExtra(PayPalService.EXTRA_PAYPAL_CONFIGURATION, config);
        startService(intent);
        Button payPalButton = (Button)findViewById(R.id.pay_pal_button);
        assert payPalButton != null;
        payPalButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                initializePayPalPayment();
            }
        });
    }
    private void initializePayPalPayment(){
        PayPalPayment payment = new PayPalPayment(new BigDecimal(String.valueOf(totalCostPrice)), "USD", "Female Cloths", PayPalPayment.PAYMENT_INTENT_SALE);
        Intent intent = new Intent(this, PaymentActivity.class);
        intent.putExtra(PayPalService.EXTRA_PAYPAL_CONFIGURATION, config);
        intent.putExtra(PaymentActivity.EXTRA_PAYMENT, payment);
        startActivityForResult(intent, 0);
    }
    @Override
    protected void onActivityResult (int requestCode, int resultCode, Intent data) {
        if (resultCode == Activity.RESULT_OK) {
            PaymentConfirmation confirm = data.getParcelableExtra(PaymentActivity.EXTRA_RESULT_CONFIRMATION);
            if (confirm != null) {
                try {
                    Log.i("paymentExample", confirm.toJSONObject().toString(4));
                    String jsonPaymentResponse = confirm.toJSONObject().toString(4);
                    GsonBuilder builder = new GsonBuilder();
                    Gson gson = builder.create();
                    PaymentResponseObject responseObject = gson.fromJson(jsonPaymentResponse, PaymentResponseObject.class);
                    if(responseObject != null){
                        String paymentId = responseObject.getResponse().getId();
                        String paymentState = responseObject.getResponse().getState();
                        Log.d(TAG, "Log payment id and state " + paymentId + " " + paymentState);
                        //send to your server for verification.
                        sendPaymentVerificationToServer(paymentId, paymentState);
                    }
                } catch (JSONException e) {
                    Log.e("paymentExample", "an extremely unlikely failure occurred: ", e);
                }
            }
        }
        else if (resultCode == Activity.RESULT_CANCELED) {
            Log.i("paymentExample", "The user canceled.");
        }
        else if (resultCode == PaymentActivity.RESULT_EXTRAS_INVALID) {
            Log.i("paymentExample", "An invalid Payment or PayPalConfiguration was submitted. Please see the docs.");
        }
    }
    private void sendPaymentVerificationToServer(String id, String state){
        Map<String, String> params = new HashMap<String,String>();
        params.put("PAYMENT_ID", id);
        params.put("PAYMENT_STATE", state);
        GsonRequest<ServerObject> serverRequest = new GsonRequest<ServerObject>(
                Request.Method.POST,
                SERVER_PATH,
                ServerObject.class,
                params,
                createRequestSuccessListener(),
                createRequestErrorListener());
        serverRequest.setRetryPolicy(new DefaultRetryPolicy(
                MY_SOCKET_TIMEOUT_MS,
                DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
                DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
        VolleySingleton.getInstance(PayPalCheckoutActivity.this).addToRequestQueue(serverRequest);
    }
    private Response.Listener<ServerObject> createRequestSuccessListener() {
        return new Response.Listener<ServerObject>() {
            @Override
            public void onResponse(ServerObject response) {
                try {
                    Log.d(TAG, "Json Response " + response.getSuccess());
                    if(!TextUtils.isEmpty(response.getSuccess())){
                        Toast.makeText(PayPalCheckoutActivity.this, getString(R.string.successful_payment), Toast.LENGTH_LONG).show();
                    }else{
                        Toast.makeText(PayPalCheckoutActivity.this, getString(R.string.server_error), Toast.LENGTH_LONG).show();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            };
        };
    }
    private Response.ErrorListener createRequestErrorListener() {
        return new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                error.printStackTrace();
            }
        };
    }
    @Override
    public void onDestroy() {
        stopService(new Intent(this, PayPalService.class));
        super.onDestroy();
    }
}

 

JsonEntityObjects Package Folder

We are going to create another folder package and we will name it jsonEntityObjects. As you can see, the returned Json response we obtained after payment is in Json String Format. So we will convert the Json string to its equivalent Plain Java Object class.

{
   "client": {
   "environment": "mock",
   "paypal_sdk_version": "2.14.4",
   "platform": "Android",
   "product_name": "PayPal-Android-SDK"
   },
   "response": {
   "create_time": "2014-07-18T18:46:55Z",
   "id": "PAY-18X32451H0459092JKO7KFUI",
   "intent": "sale",
   "state": "approved"
   },
  "response_type": "payment"
}

The following entity object classes will be create to map the Json response object to our java classes.

 

Client.java class

public class client {
    private String environment;
    private String paypal_sdk_version;
    private String platform;
    private String product_name;
    public client(String environment, String paypal_sdk_version, String platform, String product_name) {
        this.environment = environment;
        this.paypal_sdk_version = paypal_sdk_version;
        this.platform = platform;
        this.product_name = product_name;
    }
    public String getEnvironment() {
        return environment;
    }
    public String getPaypal_sdk_version() {
        return paypal_sdk_version;
    }
    public String getPlatform() {
        return platform;
    }
    public String getProduct_name() {
        return product_name;
    }
}

 

response.java class

public class response {
    private String create_time;
    private String id;
    private String intent;
    private String state;
    public response(String create_time, String id, String intent, String state) {
        this.create_time = create_time;
        this.id = id;
        this.intent = intent;
        this.state = state;
    }
    public String getCreate_time() {
        return create_time;
    }
    public String getId() {
        return id;
    }
    public String getIntent() {
        return intent;
    }
    public String getState() {
        return state;
    }
}

 

PaymentResponseObject.java

public class PaymentResponseObject {
    private client client;
    private response response;
    private String response_type;
    public PaymentResponseObject(client client, response response, String response_type) {
        this.client = client;
        this.response = response;
        this.response_type = response_type;
    }
    public client getClient() {
        return client;
    }
    public response getResponse() {
        return response;
    }
    public String getResponse_type() {
        return response_type;
    }
}

 

ServerObject class

public class ServerObject {
    private String success;
    public ServerObject(String success) {
        this.success = success;
    }
    public String getSuccess() {
        return success;
    }
}

 

PayPal Payment Verification

You can stop here if you do not want to verify your PayPal payment. You should also understand that there are many fraud going on in the world especially when it comes with online payment.

We are going to create a simple back end that gets the payment information we post from our android app and it will store it in our database.

Thereafter, we can make a Restful call to PayPal server that is server to server call with the payment id append to PayPal API endpoint.

If the payment is authenticated, we can use the returned information to compare the state of the payment, amount and currency type. It all depend on what you feel like doing.

 

Create Server Web Application

Create a new root folder for the web application and name it paypal. Inside the folder, we are going to create a config.php file and other file that will help use to connect to our database and store the PayPal payment information we will receive from android.

 

Config.php

You need to enter your database configuration details in the constants.

<?php
define("DB_HOST", "");
define("DB_USER", "");
define("DB_PASSWORD", "");
define("DB_NAME", "");
?>

 

db.php

<?php
include_once 'config.php';
class DbConnect{
    private $connect;
    public function __construct(){
        $this->connect = mysqli_connect(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
        if (mysqli_connect_errno($this->connect))
        {
            echo "Failed to connect to MySQL: " . mysqli_connect_error();
        }
    }
    public function getDb(){
        return $this->connect;
    }
}

 

Save.php

The Save.php will contain a method name savePaymentDetails() that will save our PayPal payment details to the database.

<?php
include_once 'db.php';
class Save{
    private $db;
    public function __construct(){
        $this->db = new DbConnect();
    }
    public function savePaymentDetail($payment_id, $payment_state){
        $query = "insert into paypal_verification(payment_id, state) values ('$payment_id', '$payment_state')";
        $inserted = mysqli_query($this->db->getDb(), $query);
        if($inserted == 1){
            $json = Array('success' => '1');
        }else{
            $json = Array('success' => '0');
        }
        mysqli_close($this->db->getDb());
        echo json_encode($json, JSON_PRETTY_PRINT);
    }
}
?>

 

token.php

This will get the posted PayPal payment details and pass it to above method which will store it in the database table.

<?php
 include_once 'Save.php';
 if($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST)){
 $payment_id = $_POST['PAYMENT_ID'];
 $payment_state = $_POST['PAYMENT_STATE'];
 $saveObject = new Save();
 $saveObject->savePaymentDetail($payment_id, $payment_state);
 }
?>

 

Database Creation

Move over to your database and create a new database . Name the database whatever you like. Inside the database, create a new table and name it paypal_verification. The code below will generate the table structure for you.

CREATE TABLE IF NOT EXISTS `paypal_verification` (
    `id` int(20) NOT NULL AUTO_INCREMENT,
    `payment_id` varchar(255) NOT NULL,
    `state` varchar(70) NOT NULL,
    PRIMARY KEY (`id`)
    ) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

 

Server to Server API call

url https://api.sandbox.paypal.com/v1/payments/payment/$payment_id \
-H "Content-Type: application/json" \
-H "Authorization: Bearer accessToken"

This brings us to the end of this tutorial. I hope that you have learn something new. Run your app and see for yourself.

You can download the code for this tutorial below. If you are having hard time downloading the tutorial, kindly contact me.

Remember to subscribe with your email address so that you will be among the first to receive my new android blog post once it is published.

 

OTHER INTERESTING POSTS:

16 Comments

Add a Comment