Advanced Cloud Code

Using Stripe into Android Apps

Introduction

This section explains how you can integrate Stripe with a Cloud Code function. After completing this guide with step-by-step instructions, you will be ready to use your function in your App.

Prerequisites

To complete this tutorial, you will need:

What is Stripe?

Stripe is a Tech Company, operating in over 25 countries, which allows both individuals and businesses to accept payments over the Internet. Stripe focuses on providing the technical, fraud prevention and banking infrastructure required to operate online payment systems.

This tutorial will walk you through the steps of creating a function and integrating Stripe API to your Parse Server into your Android App.

To be precise, we will create a Purchase Button that, whenever clicked will be accountable to place an order when purchasing a product from the database and generate a fake (demo) financial transaction via Stripe Payments to confirm whether it’s working appropriately or not. Also, you will be guided on how to set up the whole process as well as test if the connection to the server and the Stripe API is working properly.

After following this tutorial, you will be able to do this:

App working in Back4App!

Step 1 - Create a Stripe Account

Go to Stripe and click on the sign up to create an account. There, you just need to provide your personal information, as shown below:

Create a New Account in Stripe

Next, open the email account you used to register yourself and verify your Stripe Account (you’ll receive an email compromising a verification link from Stripe). Click on that link, and then provide your a contact info. For that, you need to click on Activate your account button and you will be redirected to the following page:

Business details

Step 2 - Get your Stripe Key

Now, to find your Stripe Keys, navigate to the menu list at the left, and click on Developers and API Keys. In that section, you will be able to see your Publishable key and your secret key. Next, click on the Reveal test key token to get your secret key. The Publishable key will be the value that is blurred in the image below.

Account Settings

After completing this step, you can easily copy your Stripe Keys.

Step 3 - Set up your Purchase Class

After configuring the Stripe environment for Step 1 and 2, go to your Parse Dashboard and create a class called Item. Inside that class, we will need to create the following Columns:

  • ItemName (String)
  • Price (Number)
  • quantityAvailable (Number)

Afterward, create a new object with the following information:

  • ItemName: test
  • Price: 10
  • quantityAvailable: 5

Step 4 - Set up your Order Class

Now, let’s create a class to receive the order details from the payment gateway. This class will be called Order with the columns:

  • name (String)
  • email (String)
  • address (String)
  • zip (String)
  • city_state (String)
  • item (String)
  • fulfilled (Boolean)
  • charged (Boolean)
  • stripePaymentId (String)

Order Class

To this point, we’ve successfully configured the Stripe Account and set up the classes Order and Item, plus the columns for both.

Step 5 - Implementing Cloud Code

In this section, we will learn to work with the Cloud Functions in the app.

5.1 - How does the Cloud Code work?

Simple, we just need to call a function in the Application, which will be functioning using the Order and Item classes created in your Parse Dashboard.

5.2 - Working with modules

After configuring the environment for the Command Line Interface in your terminal, you will need to create a file called package.json. Inside the cloud directory, install the Stripe module, like:

1
2
3
4
5
{
  "dependencies": {
    "stripe": "*"
  }
}

5.3 - Using our purchaseItem Function

Now, let’s create a function that will be responsible to purchase an item in the Cloud Code named purchaseItem and can be called from the application.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
var Stripe = require("stripe")("sk_test_K5hIEEh5SWYxQdrrFas2tl1y");
  Parse.Cloud.define("purchaseItem", function(request, response) {
  var item, order;

  Parse.Promise.as().then(function() {

  var itemQuery = new Parse.Query('Item');
  itemQuery.equalTo('ItemName', request.params.ItemName);
    return itemQuery.first(null,{useMasterKey: true}).then(null, function(error) {
        return Parse.Promise.error('Sorry, this item is no longer available.');
    });
  },{useMasterKey: true}).then(function(result) {
    if (!result) {
      return Parse.Promise.error('Sorry, this item is no longer available.');
    } else if (result.get('quantityAvailable') <= 0) {
      return Parse.Promise.error('Sorry, this item is out of stock.');
    }
    item = result;
    item.increment('quantityAvailable', -1);
    return item.save(null,{useMasterKey: true}).then(null, function(error) {
      console.log('Decrementing quantity failed. Error: ' + error);
      return Parse.Promise.error('An error has occurred. Your credit card was not charged. 1');
    });

  },{useMasterKey: true}).then(function(result) {
    if (item.get('quantityAvailable') < 0) { // can be 0 if we took the last
      return Parse.Promise.error('Sorry, this item is out of stock.');
      }
    //Setting the columns to Order class
    order = new Parse.Object("Order");
    order.set('name', request.params.name);
    order.set('email', request.params.email);
    order.set('address', request.params.address);
    order.set('zip', request.params.zip);
    order.set('city_state', request.params.city_state);
    order.set('item', item.get('ItemName'));
    order.set('fulfilled', true);
    order.set('charged', false);

    return order.save(null,{useMasterKey:true}).then(null, function(error) {
      item.increment('quantityAvailable', 1);
      return Parse.Promise.error('An error has occurred. Your credit card was not charged.');
    });
  },{useMasterKey:true}).then(function(order) {
    return Stripe.charges.create({
      amount: item.get('Price')*100, // It needs to convert to cents
      currency: "usd",
      source: request.params.cardToken,
      description: "Charge for " + request.params.email
    }, function(err, charge) {
      if (!err){
        order.set('stripePaymentId', charge.id);            
        order.set('charged', true);
        order.save(null,{useMasterKey:true});
      }
    });
  },{useMasterKey:true}).then(function() {
    response.success('Success');
  }, function(error) {
    response.error(error);
  });
});

Until this step, you have configured your function that you can use to call on other platforms! After going through the step 6, we will learn to work with Android devices.

Step 6 - Let’s configure our Packages and Connection

First off, make sure that you have installed an IDE that will help you with this process (see prerequisites).

Let’s start with an Android Template from Back4App to install the necessary packages.

Step 6.1 - Add Stripe package to your project

./app/build.grandle

dependencies {
    /* Other lines */

    // Stripe Package
    implementation 'com.stripe:stripe-android:+'

    /* Other lines */
}

Step 6.2 - Checking internet permission

Don’t forget to add the below line to your code, as it’ll ensure that the device has an active internet connection.

./app/src/main/AndroidManifest.xml

1
    <uses-permission android:name="android.permission.INTERNET"/>

Step 7 - Let’s configure our Layout

In this step, we will configure the Layout and use it to insert a Button on the view. The following code is a template file to use in the Layout.

./app/src/main/res/layout/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <LinearLayout
        android:id="@+id/activity_main"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:orientation="vertical"
        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:weightSum="1"
        tools:layout_constraintTop_creator="1"
        tools:layout_constraintRight_creator="1"
        tools:layout_constraintBottom_creator="1"
        android:layout_marginStart="9dp"
        app:layout_constraintBottom_toBottomOf="parent"
        android:layout_marginEnd="9dp"
        app:layout_constraintRight_toRightOf="parent"
        android:layout_marginTop="8dp"
        tools:layout_constraintLeft_creator="1"
        android:layout_marginBottom="8dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginLeft="9dp"
        android:layout_marginRight="9dp">

    <Button
        android:id="@+id/purchase"
        android:layout_width="365dp"
        android:layout_height="60dp"
        android:text="Purchase Button"
        android:visibility="visible"
        android:layout_marginTop="5dp"
        android:layout_marginLeft="5dp"
        tools:layout_editor_absoluteX="11dp"
        tools:layout_editor_absoluteY="5dp" />

    </LinearLayout>

</android.support.constraint.ConstraintLayout>

Now, create a file named dimens.xml and add the code written below:

./app/src/main/res/values/dimens.xml

1
2
3
4
5
<resources>
    <!-- Default screen margins, per the Android Design guidelines. -->
    <dimen name="activity_horizontal_margin">16dp</dimen>
    <dimen name="activity_vertical_margin">16dp</dimen>
</resources>

Step 8 - Implementing the Logic code!

It’s not over yet! Let’s not forget about process that will send all data to our function created above in step 5.3.


./app/src/main/java/back4app/android_stripe_payment/MainActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
import android.app.ProgressDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import com.parse.FunctionCallback;
import com.parse.Parse;
import com.parse.ParseCloud;
import com.parse.ParseException;
import com.stripe.android.Stripe;
import com.stripe.android.TokenCallback;
import com.stripe.android.model.Card;
import com.stripe.android.model.Token;

import java.util.HashMap;
import java.util.Map;

import java.util.HashMap;
import java.util.Map;

public class MainActivity extends AppCompatActivity {

    public static final String PUBLISHABLE_KEY = "Paste your Publishable key here";
    public static final String APPLICATION_ID = "Paste your App Id";
    public static final String CLIENT_KEY = "Paste your Client Key";
    public static final String BACK4PAPP_API = "https://parseapi.back4app.com/";
    private Card card;
    private ProgressDialog progress;
    private Button purchase;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // Connect to Your Back4app Account
        Parse.initialize(new Parse.Configuration.Builder(this)
        .applicationId(APPLICATION_ID)
        .clientKey(CLIENT_KEY)
        .server(BACK4PAPP_API).build());
        Parse.setLogLevel(Parse.LOG_LEVEL_VERBOSE);

        // Create a demo test credit Card
        // You can pass the payment form data to create a Real Credit card
        // But you need to implement youself.

        card = new Card(
                "4242424242424242", //card number
                12, //expMonth
                2016,//expYear
                "123"//cvc
        );
        progress = new ProgressDialog(this);
        purchase = (Button) findViewById(R.id.purchase);
        purchase.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                buy();
            }
        });
    }

    private void buy(){
        boolean validation = card.validateCard();
        if(validation){
            startProgress("Validating Credit Card");
            new Stripe(this).createToken(
                    card,
                    PUBLISHABLE_KEY,
                    new TokenCallback() {
                        @Override
                        public void onError(Exception error) {
                            Log.d("Stripe",error.toString());
                        }

                        @Override
                        public void onSuccess(Token token) {
                            finishProgress();
                            charge(token);
                        }
                    });
        } else if (!card.validateNumber()) {
            Log.d("Stripe","The card number that you entered is invalid");
        } else if (!card.validateExpiryDate()) {
            Log.d("Stripe","The expiration date that you entered is invalid");
        } else if (!card.validateCVC()) {
            Log.d("Stripe","The CVC code that you entered is invalid");
        } else {
            Log.d("Stripe","The card details that you entered are invalid");
        }
    }

    private void charge(Token cardToken){
        HashMap<String, Object> params = new HashMap<String, Object>();
        params.put("ItemName", "test");
        params.put("cardToken", cardToken.getId());
        params.put("name","Dominic Wong");
        params.put("email","[email protected]");
        params.put("address","HIHI");
        params.put("zip","99999");
        params.put("city_state","CA");
        startProgress("Purchasing Item");
        ParseCloud.callFunctionInBackground("purchaseItem", params, new FunctionCallback<Object>() {
            public void done(Object response, ParseException e) {
                finishProgress();
                if (e == null) {
                    Log.d("Cloud Response", "There were no exceptions! " + response.toString());
                    Toast.makeText(getApplicationContext(),
                            "Item Purchased Successfully ",
                            Toast.LENGTH_LONG).show();
                } else {
                    Log.d("Cloud Response", "Exception: " + e);
                    Toast.makeText(getApplicationContext(),
                            e.getMessage().toString(),
                            Toast.LENGTH_LONG).show();
                }
            }
        });
    }

    private void startProgress(String title){
        progress.setTitle(title);
        progress.setMessage("Please Wait");
        progress.show();
    }
    private void finishProgress(){
        progress.dismiss();
    }
}

An important point to remember: : You will need to replace your keys (App Id and Client Key) from Back4App with the Stripe keys (Secret Key and Publishable Key) in the Code.

Step 9 - Testing

By this time, your Android code should be working properly. After clicking the Purchase Button, it should easily pass through the loading phase and then display a message if the payment made for the item was successful or not. Your app will look like the picture below:

App working in Back4App!

If the integration was done correctly, your Parse Dashboard will display that the function is working properly. In the Item class, you should be able to see that the product quantity has been updated.

Item class

Also, in the Order class, you can see the newly created orders.

Order class

Step 10 - It’s done!

With the guide described above, you can use Stripe with a Cloud Code Function in Back4App as well as integrate payments to your apps!

In case you face any trouble while integrating Stripe or a function doesn’t work, please contact our team via chat!