How to integrate Stripe on Android App using Cloud Functionss
Introduction
In this guide, we are going to show you how to integrate a hosted backend in Back4App with Stripe API. The best architecture choice to build it on Back4App is using a very powerful feature called Cloud Functions. Once you finish the cloud function integration with Stripe you’ll be able to use this integration for all your front-end projects (Web, iOS, Android). This guide presents a complete Stripe integration using an Android App example.
Prerequisites
To complete this tutorial, you will need:
- An app created at Back4App.
- Follow the Create New App tutorial to learn how to create an app at Back4App.
- An account created at Stripe.
- Android Studio.
- A device (or virtual device) running Android 4.0 (Ice Cream Sandwich) or the latest version.
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:
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:
Next, verify your Stripe Account (you’ll receive an email compromising a verification link from Stripe). Click on that link, and then follow the steps to confirm your Stripe email address.
Step 2 - Set up your Purchase Class
After configuring the Stripe environment for Step 1, go to Back4App Website, log in, find your app and click on Dashboard
> Create a class
, then enter with the name Item
. Check below:
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 3 - 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)
To this point, we’ve successfully configured the Stripe Account and set up the classes Order
and Item
, plus the columns for both.
Step 4 - Implementing Cloud Code
In this section, let’s configure the Cloud Code Function in the app, we will install the Stripe module and deploy the Code.
If you want to better understand the Cloud Code enviroment, check this guide.
4.1 - Get your Stripe Key
Now, open the Stripe Dashboard and 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
is the first value that is blurred in the image below.
After completing this step, you can easily copy your Stripe Keys.
4.2 - Cloud Code files
On your computer, create the following files, that will be responsible to install the module and to purchase an item using a Cloud Code Function.
package.json
1
2
3
4
5
{
"dependencies": {
"stripe": "*"
}
}
In the code below, don’t forget to paste your Secret key, more specifically in space: PASTE_YOUR_SECRECT_KEY_HERE.
main.js
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
let stripe_key = "PASTE_YOUR_SECRECT_KEY_HERE"; //Secret Key here
let Stripe = require("stripe")(stripe_key);
Parse.Cloud.define("purchaseItem", async (request) => {
let item, order;
let itemQuery = new Parse.Query('Item');
itemQuery.equalTo('ItemName', request.params.ItemName);
const result = await itemQuery.first(null,{useMasterKey: true});
if(!result){
throw new Error('Sorry, this item is no longer available.');
} else if(result.get('quantityAvailable') <= 0){
throw new Error('Sorry, this item is out of stock.');
} else {
item = result;
const charge = await 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
})
item.increment('quantityAvailable', -1);
const object = await item.save(null,{useMasterKey: true})
const 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);
order.set('stripePaymentId', charge.id);
order.set('charged', true);
await order.save(null,{useMasterKey:true});
}
return 'OK';
});
main.js
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
let stripe_key = "PASTE_YOUR_SECRECT_KEY_HERE";
let Stripe = require("stripe")(stripe_key);
Parse.Cloud.define("purchaseItem", function(request, response) {
let item, order;
Parse.Promise.as().then(function() {
let 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);
});
});
Step 5 - Upload function to Cloud Code
Go to Back4App website, log in and then find your app. After that, click on Dashboard
link and you will end up in the page shown below. To deploy your Cloud Code, simply click on the + ADD
button and select the main.js
and package.json
file that you created at previous step, then click on the DEPLOY
button.
Until this step, you have configured the Cloud Code function that you can use to call on other platforms! Check the Deploy & call functions guide to learn how to call it. After the next step, you will work with a Android Project.
Step 6 - Let’s configure our Project
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
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
2
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<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/activity_main.xml
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 the process that will send all data to our function created above in step 4.2.
./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
132
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 = "PASTER_YOUR_PUBLISHABLE_KEY_HERE";
private Card card;
private ProgressDialog progress;
private Button purchase;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 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
2030,//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) {
Toast.makeText(MainActivity.this,
"Stripe -" + error.toString(),
Toast.LENGTH_LONG).show();
}
@Override
public void onSuccess(Token token) {
finishProgress();
charge(token);
}
});
} else if (!card.validateNumber()) {
Toast.makeText(MainActivity.this,
"Stripe - The card number that you entered is invalid",
Toast.LENGTH_LONG).show();
} else if (!card.validateExpiryDate()) {
Toast.makeText(MainActivity.this,
"Stripe - The expiration date that you entered is invalid",
Toast.LENGTH_LONG).show();
} else if (!card.validateCVC()) {
Toast.makeText(MainActivity.this,
"Stripe - The CVC code that you entered is invalid",
Toast.LENGTH_LONG).show();
} else {
Toast.makeText(MainActivity.this,
"Stripe - The card details that you entered are invalid",
Toast.LENGTH_LONG).show();
}
}
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 in the
string.xml
file and also, the Publishable Key in the Code above.
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:
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.
Also, in the Order class, you can see the newly created orders.
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!