In the previous part Android Integrating PayPal using PHP, MySQL – Part 1,
we have covered building the PayPal server side part i.e creating mysql
database and writing the PHP services those interacts with android app
and PayPal REST API.
In this part we are going to cover the remaining things like building the android app and integrating the PayPal payment gateway. Finally we conclude this by doing few tests in local environment.
1. Create a new project in Eclipse by going to File ⇒ New ⇒ Android Application Project and fill the required information.
I gave my project name as PayPalClient and package name as info.androidhive.paypalclient
2. Now quickly create two packages named app and helper.
3. Paste all the contents of PayPal Android SDK’s libs folder into our project’s libs folder.
Below is the final project structure that we’re going to create. You should have all the PayPal lib files and the packages placed as shown below.
4. Open colors.xml under res ⇒ value and add below color resources.
5. Open strings.xml under res ⇒ values and add below string values.
6. I am using volley to make network calls. Download the volley.jar and paste it in libs folder. (If you are new to volley, this tutorial will give you a good overview about volley library).
7. Create class named LruBitmapCache.java under helper package. The purpose of this class to cache the downloaded images.
8. Crete a class named AppController.java under app package. This is a singleton class that extends from Application which will be executed on app launch. All the initialization of volley objects will be done here.
9. Now edit the AndroidManifest.xml and do below changes.
> Add the AppController class to <application> tag using android:name property.
> Add CAMERA, VIBRATE, ACCESS_NETWORK_STATE and INTERNET permissions.
> Add the camera feature. This should be added when user wants to pay using card.io feature.
> Add the PayPalService
> Add the PayPal SDK activities (PaymentActivity, LoginActivity, PaymentMethodActivity, PaymentConfirmActivity and CardIOActivity). These are necessary activities to make paypal payment.
Finally the AndroidManifest.xml should look like below.
10. Crete a class named Config.java under app package. This class contains all the configuration variables like PayPal client id & secret, paypal environment and url endpoints to our server which we built in the first part of this series.
11. Create a model class named Product.java under helper package. This class will be used while parsing the products json.
12. Under res ⇒ layout, create a file named list_item_product.xml. This layout file renders a single list item in products list view. This layout contains the product image on the left and other details like product name, description, price on the right.
13. As the product list view is customized, we need to write the custom list adapter class. Create a class named ProductListAdapter.java under helper package. This adapter class renders list_item_product.xml by filling appropriate product data in a single list row.
14. Now we have all the helpers classes ready. Let’s move to main activity and start adding the PayPal code. Create a layout file under res layout named activity_main.xml and add below code. This layout contains a ListView to display the product list and a button to do the ckeckout.
15. Open your MainActivity.java and do below changes. Basically to add PayPal support, we need to take below simple steps.
> Create a PayPalConfiguration object by setting necessary configuration like environment and client id.
> Start the PayPalService in onCreate()
> When user presses the checkout button, start the PaymentActivity by passing necessary information like final items, price, description etc.
> Once the payment is done, receive the PaymentConfirmation in onActivityResult(). This is where you will receives paypal response like payment id and other important information.
> Finally send the payment id and response json to our server for server side verification.
In the below code
fetchProducts() – Fetches the products json from our server.
verifyPaymentOnServer() – Verifies the mobile payment on the server.
prepareFinalCart() – Prepare the final cart information like total amount, items that needs to be submitted to paypal payment activity.
launchPayPalPayment() – Launches the PayPal payment activity
onAddToCartPressed() – Adds the item to cart when add to cart button is pressed.
Here we completed android part too. In order to test both the server and mobile apps in the local environment, follow below steps.
> Replace the PAYPAL_CLIENT_ID & PAYPAL_SECRET in Config.php with your paypal keys in your php project.
> Replace the PAYPAL_CLIENT_ID in Config.java with your paypal client id
> Run the WAMP server and get the ip address of the machine by executing ipconfig in cmd. (On mac, use ifconfig to get the ip address). We need to use this ip address in the url instead of localhost.
> Replace the ip address of URL_PRODUCTS and URL_VERIFY_PAYMENT with your ip address in Config.java.
> Deploy and run the android app on device. If you get the products list displayed, your app successfully connecting with the php server.
> Try selecting the products you want to buy and proceed with the checkout. You should able to see PayPal payment screens and do the payment. When it ask for paypal credentials, use the sandbox credentials.
When you are making your app live, read the guidelines ‘Going Live with Your Application‘ provided by PayPal to move your app to production environment.
In our app, change the environment from PayPalConfiguration.ENVIRONMENT_SANDBOX to PayPalConfiguration.ENVIRONMENT_PRODUCTION in Config.java
⇒ Supported Currencies
PayPal is not supporting all the currencies as of now. Here is the list of currencies PayPal is supporting. Unfortunately, for indian users INR is not in the list. But you can use google currency calculator to get realtime INR to USD currency convert rate.
References:
> Goto through PayPal REST API doc for detailed explanation of each REST API call.
> PayPal Android Mobile SDK
> PayPal PHP REST API SDK
> Server image used in the illustration
In this part we are going to cover the remaining things like building the android app and integrating the PayPal payment gateway. Finally we conclude this by doing few tests in local environment.
9. Downloading PayPal Android SDK
Just like PayPal PHP REST API SDK, PayPal provides SDK for mobile platforms too. Download the PayPal Android SDK and extract it. It comes with a Sample App, docs and libs. We would be interested in using the libs folder. If you want to try Future Payments and Profile Sharing, you can find example code in the sample app.10. Creating the Android Project
Now let’s start building the android app.1. Create a new project in Eclipse by going to File ⇒ New ⇒ Android Application Project and fill the required information.
I gave my project name as PayPalClient and package name as info.androidhive.paypalclient
2. Now quickly create two packages named app and helper.
3. Paste all the contents of PayPal Android SDK’s libs folder into our project’s libs folder.
Below is the final project structure that we’re going to create. You should have all the PayPal lib files and the packages placed as shown below.
<? xml version = "1.0" encoding = "utf-8" ?> < resources > < color name = "btn_bg_checkout" >#428bca</ color > < color name = "list_divider" >#dedede</ color > < color name = "white" >#ffffff</ color > < color name = "lbl_product_name" >#333333</ color > < color name = "lbl_product_description" >#444444</ color > < color name = "bg_msg_you" >#5eb964</ color > < color name = "bg_msg_from" >#e5e7eb</ color > < color name = "msg_border_color" >#a1a1a1</ color > < color name = "bg_btn_join" >#1e6258</ color > < color name = "bg_msg_input" >#e8e8e8</ color > < color name = "text_msg_input" >#626262</ color > < color name = "lblFromName" >#777777</ color > </ resources > |
5. Open strings.xml under res ⇒ values and add below string values.
<? xml version = "1.0" encoding = "utf-8" ?> < resources > < string name = "app_name" >PalPal Client</ string > < string name = "checkout" >Checkout</ string > < string name = "add_to_cart" >Add to Cart</ string > </ resources > |
6. I am using volley to make network calls. Download the volley.jar and paste it in libs folder. (If you are new to volley, this tutorial will give you a good overview about volley library).
7. Create class named LruBitmapCache.java under helper package. The purpose of this class to cache the downloaded images.
package info.androidhive.palpalclient.helper; import com.android.volley.toolbox.ImageLoader.ImageCache; import android.graphics.Bitmap; import android.support.v4.util.LruCache; public class LruBitmapCache extends LruCache<String, Bitmap> implements ImageCache { public static int getDefaultLruCacheSize() { final int maxMemory = ( int ) (Runtime.getRuntime().maxMemory() / 1024 ); final int cacheSize = maxMemory / 8 ; return cacheSize; } public LruBitmapCache() { this (getDefaultLruCacheSize()); } public LruBitmapCache( int sizeInKiloBytes) { super (sizeInKiloBytes); } @Override protected int sizeOf(String key, Bitmap value) { return value.getRowBytes() * value.getHeight() / 1024 ; } @Override public Bitmap getBitmap(String url) { return get(url); } @Override public void putBitmap(String url, Bitmap bitmap) { put(url, bitmap); } } |
8. Crete a class named AppController.java under app package. This is a singleton class that extends from Application which will be executed on app launch. All the initialization of volley objects will be done here.
package info.androidhive.palpalclient.app; import info.androidhive.palpalclient.helper.LruBitmapCache; import android.app.Application; import android.text.TextUtils; import com.android.volley.Request; import com.android.volley.RequestQueue; import com.android.volley.toolbox.ImageLoader; import com.android.volley.toolbox.Volley; public class AppController extends Application { public static final String TAG = AppController. class .getSimpleName(); private RequestQueue mRequestQueue; private ImageLoader mImageLoader; private static AppController mInstance; @Override public void onCreate() { super .onCreate(); mInstance = this ; } public static synchronized AppController getInstance() { return mInstance; } public RequestQueue getRequestQueue() { if (mRequestQueue == null ) { mRequestQueue = Volley.newRequestQueue(getApplicationContext()); } return mRequestQueue; } public ImageLoader getImageLoader() { getRequestQueue(); if (mImageLoader == null ) { mImageLoader = new ImageLoader( this .mRequestQueue, new LruBitmapCache()); } return this .mImageLoader; } public <T> void addToRequestQueue(Request<T> req, String tag) { // set the default tag if tag is empty req.setTag(TextUtils.isEmpty(tag) ? TAG : tag); getRequestQueue().add(req); } public <T> void addToRequestQueue(Request<T> req) { req.setTag(TAG); getRequestQueue().add(req); } public void cancelPendingRequests(Object tag) { if (mRequestQueue != null ) { mRequestQueue.cancelAll(tag); } } } |
9. Now edit the AndroidManifest.xml and do below changes.
> Add the AppController class to <application> tag using android:name property.
> Add CAMERA, VIBRATE, ACCESS_NETWORK_STATE and INTERNET permissions.
> Add the camera feature. This should be added when user wants to pay using card.io feature.
> Add the PayPalService
> Add the PayPal SDK activities (PaymentActivity, LoginActivity, PaymentMethodActivity, PaymentConfirmActivity and CardIOActivity). These are necessary activities to make paypal payment.
Finally the AndroidManifest.xml should look like below.
<? xml version = "1.0" encoding = "utf-8" ?> package = "info.androidhive.palpalclient" android:versionCode = "1" android:versionName = "1.0" > < uses-sdk android:minSdkVersion = "8" android:targetSdkVersion = "21" /> <!-- for card.io card scanning --> < uses-permission android:name = "android.permission.CAMERA" /> < uses-permission android:name = "android.permission.VIBRATE" /> < uses-feature android:name = "android.hardware.camera" android:required = "false" /> < uses-feature android:name = "android.hardware.camera.autofocus" android:required = "false" /> <!-- for most things, including card.io & paypal --> < uses-permission android:name = "android.permission.ACCESS_NETWORK_STATE" /> < uses-permission android:name = "android.permission.INTERNET" /> < application android:name = "info.androidhive.palpalclient.app.AppController" android:allowBackup = "true" android:icon = "@drawable/ic_launcher" android:label = "@string/app_name" > < activity android:name = "info.androidhive.palpalclient.MainActivity" android:label = "@string/app_name" > < intent-filter > < action android:name = "android.intent.action.MAIN" /> < category android:name = "android.intent.category.LAUNCHER" /> </ intent-filter > </ activity > < service android:name = "com.paypal.android.sdk.payments.PayPalService" android:exported = "false" /> < activity android:name = "com.paypal.android.sdk.payments.PaymentActivity" /> < activity android:name = "com.paypal.android.sdk.payments.LoginActivity" /> < activity android:name = "com.paypal.android.sdk.payments.PaymentMethodActivity" /> < activity android:name = "com.paypal.android.sdk.payments.PaymentConfirmActivity" /> < activity android:name = "io.card.payment.CardIOActivity" android:configChanges = "keyboardHidden|orientation" /> < activity android:name = "io.card.payment.DataEntryActivity" /> </ application > </ manifest > |
10. Crete a class named Config.java under app package. This class contains all the configuration variables like PayPal client id & secret, paypal environment and url endpoints to our server which we built in the first part of this series.
package info.androidhive.palpalclient.app; import com.paypal.android.sdk.payments.PayPalConfiguration; import com.paypal.android.sdk.payments.PayPalPayment; public class Config { // PayPal app configuration public static final String PAYPAL_CLIENT_ID = "AbLgy0hRsq0PmoGK-ws2-jlBIeBVKUUU0xRjbfW1-GAckylz_TDNsh1cMrIiSksc2wpqYC2PisTrKhko" ; public static final String PAYPAL_CLIENT_SECRET = "" ; public static final String PAYPAL_ENVIRONMENT = PayPalConfiguration.ENVIRONMENT_SANDBOX; public static final String PAYMENT_INTENT = PayPalPayment.PAYMENT_INTENT_SALE; public static final String DEFAULT_CURRENCY = "USD" ; // PayPal server urls public static final String URL_VERIFY_PAYMENT = "http://192.168.0.103/PayPalServer/v1/verifyPayment" ; } |
11. Create a model class named Product.java under helper package. This class will be used while parsing the products json.
package info.androidhive.palpalclient.helper; import java.math.BigDecimal; public class Product { private String id, name, description, image, sku; private BigDecimal price; public Product() { } public Product(String id, String name, String description, String image, BigDecimal price, String sku) { this .id = id; this .name = name; this .description = description; this .image = image; this .price = price; this .sku = sku; } public String getId() { return id; } public void setId(String id) { this .id = id; } public String getName() { return name; } public void setName(String name) { this .name = name; } public String getDescription() { return description; } public void setDescription(String description) { this .description = description; } public String getImage() { return image; } public void setImage(String image) { this .image = image; } public BigDecimal getPrice() { return price; } public void setPrice(BigDecimal price) { this .price = price; } public String getSku() { return sku; } public void setSku(String sku) { this .sku = sku; } } |
12. Under res ⇒ layout, create a file named list_item_product.xml. This layout file renders a single list item in products list view. This layout contains the product image on the left and other details like product name, description, price on the right.
<? xml version = "1.0" encoding = "utf-8" ?> android:layout_width = "match_parent" android:layout_height = "match_parent" android:background = "@color/white" android:paddingBottom = "10dp" > < com.android.volley.toolbox.NetworkImageView android:id = "@+id/productImage" android:layout_width = "100dp" android:layout_height = "wrap_content" android:layout_alignParentLeft = "true" android:layout_margin = "8dp" android:scaleType = "fitCenter" > </ com.android.volley.toolbox.NetworkImageView > < TextView android:id = "@+id/productName" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:layout_toRightOf = "@id/productImage" android:padding = "5dp" android:textColor = "@color/lbl_product_name" android:textSize = "16dp" android:textStyle = "bold" /> < TextView android:id = "@+id/productDescription" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:layout_below = "@id/productName" android:layout_toRightOf = "@id/productImage" android:padding = "5dp" android:textColor = "@color/lbl_product_description" /> < TextView android:id = "@+id/productPrice" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:layout_below = "@id/productDescription" android:layout_toRightOf = "@id/productImage" android:padding = "5dp" android:textColor = "@color/lbl_product_description" /> < Button android:id = "@+id/btnAddToCart" android:layout_width = "wrap_content" android:layout_height = "30dp" android:layout_below = "@id/productPrice" android:layout_margin = "5dp" android:layout_toRightOf = "@id/productImage" android:background = "#64d048" android:paddingLeft = "5dp" android:paddingRight = "5dp" android:text = "@string/add_to_cart" android:textColor = "@color/white" /> </ RelativeLayout > |
13. As the product list view is customized, we need to write the custom list adapter class. Create a class named ProductListAdapter.java under helper package. This adapter class renders list_item_product.xml by filling appropriate product data in a single list row.
package info.androidhive.palpalclient.helper; import info.androidhive.palpalclient.R; import info.androidhive.palpalclient.app.AppController; import java.util.List; import android.app.Activity; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.Button; import android.widget.TextView; import com.android.volley.toolbox.ImageLoader; import com.android.volley.toolbox.NetworkImageView; public class ProductListAdapter extends BaseAdapter { private Activity activity; private LayoutInflater inflater; private List<Product> products; private ProductListAdapterListener listener; ImageLoader imageLoader = AppController.getInstance().getImageLoader(); public ProductListAdapter(Activity activity, List<Product> feedItems, ProductListAdapterListener listener) { this .activity = activity; this .products = feedItems; this .listener = listener; } @Override public int getCount() { return products.size(); } @Override public Object getItem( int location) { return products.get(location); } @Override public long getItemId( int position) { return position; } @Override public View getView( int position, View convertView, ViewGroup parent) { if (inflater == null ) inflater = (LayoutInflater) activity .getSystemService(Context.LAYOUT_INFLATER_SERVICE); if (convertView == null ) convertView = inflater.inflate(R.layout.list_item_product, null ); if (imageLoader == null ) imageLoader = AppController.getInstance().getImageLoader(); TextView name = (TextView) convertView.findViewById(R.id.productName); TextView description = (TextView) convertView .findViewById(R.id.productDescription); TextView price = (TextView) convertView.findViewById(R.id.productPrice); NetworkImageView image = (NetworkImageView) convertView .findViewById(R.id.productImage); Button btnAddToCart = (Button) convertView .findViewById(R.id.btnAddToCart); final Product product = products.get(position); name.setText(product.getName()); description.setText(product.getDescription()); price.setText( "Price: $" + product.getPrice()); // user profile pic image.setImageUrl(product.getImage(), imageLoader); btnAddToCart.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { listener.onAddToCartPressed(product); } }); return convertView; } public interface ProductListAdapterListener { public void onAddToCartPressed(Product product); } } |
14. Now we have all the helpers classes ready. Let’s move to main activity and start adding the PayPal code. Create a layout file under res layout named activity_main.xml and add below code. This layout contains a ListView to display the product list and a button to do the ckeckout.
android:layout_width = "match_parent" android:layout_height = "match_parent" android:background = "@color/white" > < ListView android:id = "@+id/list" android:layout_width = "fill_parent" android:layout_height = "wrap_content" android:paddingBottom = "20dp" android:divider = "@color/list_divider" android:dividerHeight = "1dp" > </ ListView > < Button android:id = "@+id/btnCheckout" android:layout_width = "fill_parent" android:layout_height = "wrap_content" android:layout_alignParentBottom = "true" android:text = "@string/checkout" android:background = "@color/btn_bg_checkout" /> </ RelativeLayout > |
15. Open your MainActivity.java and do below changes. Basically to add PayPal support, we need to take below simple steps.
> Create a PayPalConfiguration object by setting necessary configuration like environment and client id.
> Start the PayPalService in onCreate()
> When user presses the checkout button, start the PaymentActivity by passing necessary information like final items, price, description etc.
> Once the payment is done, receive the PaymentConfirmation in onActivityResult(). This is where you will receives paypal response like payment id and other important information.
> Finally send the payment id and response json to our server for server side verification.
In the below code
fetchProducts() – Fetches the products json from our server.
verifyPaymentOnServer() – Verifies the mobile payment on the server.
prepareFinalCart() – Prepare the final cart information like total amount, items that needs to be submitted to paypal payment activity.
launchPayPalPayment() – Launches the PayPal payment activity
onAddToCartPressed() – Adds the item to cart when add to cart button is pressed.
package info.androidhive.palpalclient; import info.androidhive.palpalclient.app.AppController; import info.androidhive.palpalclient.app.Config; import info.androidhive.palpalclient.helper.Product; import info.androidhive.palpalclient.helper.ProductListAdapter; import info.androidhive.palpalclient.helper.ProductListAdapter.ProductListAdapterListener; import java.math.BigDecimal; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import android.app.Activity; import android.app.ProgressDialog; import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.ListView; import android.widget.Toast; import com.android.volley.DefaultRetryPolicy; import com.android.volley.Request.Method; import com.android.volley.Response; import com.android.volley.RetryPolicy; import com.android.volley.VolleyError; import com.android.volley.VolleyLog; import com.android.volley.toolbox.JsonObjectRequest; import com.android.volley.toolbox.StringRequest; import com.paypal.android.sdk.payments.PayPalConfiguration; import com.paypal.android.sdk.payments.PayPalItem; import com.paypal.android.sdk.payments.PayPalPayment; import com.paypal.android.sdk.payments.PayPalPaymentDetails; import com.paypal.android.sdk.payments.PayPalService; import com.paypal.android.sdk.payments.PaymentActivity; import com.paypal.android.sdk.payments.PaymentConfirmation; public class MainActivity extends Activity implements ProductListAdapterListener { private static final String TAG = MainActivity. class .getSimpleName(); private ListView listView; private Button btnCheckout; // To store all the products private List<Product> productsList; // To store the products those are added to cart private List<PayPalItem> productsInCart = new ArrayList<PayPalItem>(); private ProductListAdapter adapter; // Progress dialog private ProgressDialog pDialog; private static final int REQUEST_CODE_PAYMENT = 1 ; // PayPal configuration private static PayPalConfiguration paypalConfig = new PayPalConfiguration() .environment(Config.PAYPAL_ENVIRONMENT).clientId( Config.PAYPAL_CLIENT_ID); @Override protected void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); listView = (ListView) findViewById(R.id.list); btnCheckout = (Button) findViewById(R.id.btnCheckout); productsList = new ArrayList<Product>(); adapter = new ProductListAdapter( this , productsList, this ); listView.setAdapter(adapter); pDialog = new ProgressDialog( this ); pDialog.setCancelable( false ); // Starting PayPal service Intent intent = new Intent( this , PayPalService. class ); intent.putExtra(PayPalService.EXTRA_PAYPAL_CONFIGURATION, paypalConfig); startService(intent); // Checkout button click listener btnCheckout.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { // Check for empty cart if (productsInCart.size() > 0 ) { launchPayPalPayment(); } else { Toast.makeText(getApplicationContext(), "Cart is empty! Please add few products to cart." , Toast.LENGTH_SHORT).show(); } } }); // Fetching products from server fetchProducts(); } /** * Fetching the products from our server * */ private void fetchProducts() { // Showing progress dialog before making request pDialog.setMessage( "Fetching products..." ); showpDialog(); // Making json object request JsonObjectRequest jsonObjReq = new JsonObjectRequest(Method.GET, Config.URL_PRODUCTS, null , new Response.Listener<JSONObject>() { @Override public void onResponse(JSONObject response) { Log.d(TAG, response.toString()); try { JSONArray products = response .getJSONArray( "products" ); // looping through all product nodes and storing // them in array list for ( int i = 0 ; i < products.length(); i++) { JSONObject product = (JSONObject) products .get(i); String id = product.getString( "id" ); String name = product.getString( "name" ); String description = product .getString( "description" ); String image = product.getString( "image" ); BigDecimal price = new BigDecimal(product .getString( "price" )); String sku = product.getString( "sku" ); Product p = new Product(id, name, description, image, price, sku); productsList.add(p); } // notifying adapter about data changes, so that the // list renders with new data adapter.notifyDataSetChanged(); } catch (JSONException e) { e.printStackTrace(); Toast.makeText(getApplicationContext(), "Error: " + e.getMessage(), Toast.LENGTH_LONG).show(); } // hiding the progress dialog hidepDialog(); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { VolleyLog.d(TAG, "Error: " + error.getMessage()); Toast.makeText(getApplicationContext(), error.getMessage(), Toast.LENGTH_SHORT).show(); // hide the progress dialog hidepDialog(); } }); // Adding request to request queue AppController.getInstance().addToRequestQueue(jsonObjReq); } /** * Verifying the mobile payment on the server to avoid fraudulent payment * */ private void verifyPaymentOnServer( final String paymentId, final String payment_client) { // Showing progress dialog before making request pDialog.setMessage( "Verifying payment..." ); showpDialog(); StringRequest verifyReq = new StringRequest(Method.POST, Config.URL_VERIFY_PAYMENT, new Response.Listener<String>() { @Override public void onResponse(String response) { Log.d(TAG, "verify payment: " + response.toString()); try { JSONObject res = new JSONObject(response); boolean error = res.getBoolean( "error" ); String message = res.getString( "message" ); // user error boolean flag to check for errors Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show(); if (!error) { // empty the cart productsInCart.clear(); } } catch (JSONException e) { e.printStackTrace(); } // hiding the progress dialog hidepDialog(); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Log.e(TAG, "Verify Error: " + error.getMessage()); Toast.makeText(getApplicationContext(), error.getMessage(), Toast.LENGTH_SHORT).show(); // hiding the progress dialog hidepDialog(); } }) { @Override protected Map<String, String> getParams() { Map<String, String> params = new HashMap<String, String>(); params.put( "paymentId" , paymentId); params.put( "paymentClientJson" , payment_client); return params; } }; // Setting timeout to volley request as verification request takes sometime int socketTimeout = 60000 ; RetryPolicy policy = new DefaultRetryPolicy(socketTimeout, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT); verifyReq.setRetryPolicy(policy); // Adding request to request queue AppController.getInstance().addToRequestQueue(verifyReq); } /** * Preparing final cart amount that needs to be sent to PayPal for payment * */ private PayPalPayment prepareFinalCart() { PayPalItem[] items = new PayPalItem[productsInCart.size()]; items = productsInCart.toArray(items); // Total amount BigDecimal subtotal = PayPalItem.getItemTotal(items); // If you have shipping cost, add it here BigDecimal shipping = new BigDecimal( "0.0" ); // If you have tax, add it here BigDecimal tax = new BigDecimal( "0.0" ); PayPalPaymentDetails paymentDetails = new PayPalPaymentDetails( shipping, subtotal, tax); BigDecimal amount = subtotal.add(shipping).add(tax); PayPalPayment payment = new PayPalPayment( amount, Config.DEFAULT_CURRENCY, "Description about transaction. This will be displayed to the user." , Config.PAYMENT_INTENT); payment.items(items).paymentDetails(paymentDetails); // Custom field like invoice_number etc., payment.custom( "This is text that will be associated with the payment that the app can use." ); return payment; } /** * Launching PalPay payment activity to complete the payment * */ private void launchPayPalPayment() { PayPalPayment thingsToBuy = prepareFinalCart(); Intent intent = new Intent(MainActivity. this , PaymentActivity. class ); intent.putExtra(PayPalService.EXTRA_PAYPAL_CONFIGURATION, paypalConfig); intent.putExtra(PaymentActivity.EXTRA_PAYMENT, thingsToBuy); startActivityForResult(intent, REQUEST_CODE_PAYMENT); } /** * Receiving the PalPay payment response * */ @Override protected void onActivityResult( int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_CODE_PAYMENT) { if (resultCode == Activity.RESULT_OK) { PaymentConfirmation confirm = data .getParcelableExtra(PaymentActivity.EXTRA_RESULT_CONFIRMATION); if (confirm != null ) { try { Log.e(TAG, confirm.toJSONObject().toString( 4 )); Log.e(TAG, confirm.getPayment().toJSONObject() .toString( 4 )); String paymentId = confirm.toJSONObject() .getJSONObject( "response" ).getString( "id" ); String payment_client = confirm.getPayment() .toJSONObject().toString(); Log.e(TAG, "paymentId: " + paymentId + ", payment_json: " + payment_client); // Now verify the payment on the server side verifyPaymentOnServer(paymentId, payment_client); } catch (JSONException e) { Log.e(TAG, "an extremely unlikely failure occurred: " , e); } } } else if (resultCode == Activity.RESULT_CANCELED) { Log.e(TAG, "The user canceled." ); } else if (resultCode == PaymentActivity.RESULT_EXTRAS_INVALID) { Log.e(TAG, "An invalid Payment or PayPalConfiguration was submitted." ); } } } private void showpDialog() { if (!pDialog.isShowing()) pDialog.show(); } private void hidepDialog() { if (pDialog.isShowing()) pDialog.dismiss(); } @Override public void onAddToCartPressed(Product product) { PayPalItem item = new PayPalItem(product.getName(), 1 , product.getPrice(), Config.DEFAULT_CURRENCY, product.getSku()); productsInCart.add(item); Toast.makeText(getApplicationContext(), item.getName() + " added to cart!" , Toast.LENGTH_SHORT).show(); } } |
Here we completed android part too. In order to test both the server and mobile apps in the local environment, follow below steps.
11. Testing the App
> Make sure that both devices (the device running the php project and the android device) are connected to same wifi network.> Replace the PAYPAL_CLIENT_ID & PAYPAL_SECRET in Config.php with your paypal keys in your php project.
> Replace the PAYPAL_CLIENT_ID in Config.java with your paypal client id
> Run the WAMP server and get the ip address of the machine by executing ipconfig in cmd. (On mac, use ifconfig to get the ip address). We need to use this ip address in the url instead of localhost.
> Replace the ip address of URL_PRODUCTS and URL_VERIFY_PAYMENT with your ip address in Config.java.
> Deploy and run the android app on device. If you get the products list displayed, your app successfully connecting with the php server.
> Try selecting the products you want to buy and proceed with the checkout. You should able to see PayPal payment screens and do the payment. When it ask for paypal credentials, use the sandbox credentials.
12. Final Thoughts
⇒ Making Your App LiveWhen you are making your app live, read the guidelines ‘Going Live with Your Application‘ provided by PayPal to move your app to production environment.
In our app, change the environment from PayPalConfiguration.ENVIRONMENT_SANDBOX to PayPalConfiguration.ENVIRONMENT_PRODUCTION in Config.java
⇒ Supported Currencies
PayPal is not supporting all the currencies as of now. Here is the list of currencies PayPal is supporting. Unfortunately, for indian users INR is not in the list. But you can use google currency calculator to get realtime INR to USD currency convert rate.
References:
> Goto through PayPal REST API doc for detailed explanation of each REST API call.
> PayPal Android Mobile SDK
> PayPal PHP REST API SDK
> Server image used in the illustration