Payment integration

When the user decides to make a purchase, you will initialize Fortumo's Android SDK and ask it to collect the payment. A persistent transaction is then created and will be processed. Whenever the payment processing is completed, your application will be notified using your implementations of the BroadcastReceiver class, this will be done even if the app is not currently running.

This section gives an overview of Fortumo's Android SDK capabilities and describes the required code for completing a payment.

Consumable and non-consumable products

Fortumo's Android SDK supports selling both consumable and non-consumable products.

  • Consumable products (sometimes called unmanaged products) can be purchased multiple times by every user. Good examples of consumable products are virtual credits, speedups in a car game. If your service type is Virtual Currency, product type should always be set to consumable.
  • Non-consumable products (sometimes called managed products) can be purchased only once by every user. Good examples of non-consumable products are full versions of a game, new levels, ad-free version of an application.

To specify whether a product is consumable or not you will use the setType() method in PaymentRequest class. You can check if the user has already bought an non-consumable item using getNonConsumablePaymentStatus(context, service-id, in-app secret, product_name). Here product_name is used to uniquely identify the non-consumable product being bought. If you have decided to also receive receipt verification requests to your server, the product_name value will also be included in each request.

Making a payment

To initialize a payment, PaymentActivity class needs to be extended and makePayment() should be called from somewhere in that activity's code. When a payment is completed, notification about that will be sent to the BroadcastReceiver class that was defined in AndroidManifest.xml file. After that the user should be given the virtual goods bought and the purchase should be stored on the device or on server-side so that users will keep access to the goods.

Fortumo's Android SDK uses broadcast intents to send billing responses to your application. To receive payment status changes even when the user has already closed the app, you need to create a BroadcastReceiver that can handle mp.info.PAYMENT_STATUS_CHANGED intent.

Call method enablePaymentBroadcast(Context ctx, String permission) to activate broadcast sending.

1
mp.MpUtils.enablePaymentBroadcast(this, Manifest.permission.PAYMENT_BROADCAST_PERMISSION);

Example TestActivity.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
package com.your.awesome.application;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;

import mp.MpUtils;
import mp.PaymentActivity;
import mp.PaymentRequest;
import mp.PaymentResponse;

/* Some helper class, stores current credit amount in shared preferences */
import com.your.awesome.application.model.Wallet;

public class YourActivity extends PaymentActivity {

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    MpUtils.enablePaymentBroadcast(this, Manifest.permission.PAYMENT_BROADCAST_PERMISSION);

    Button payButton = (Button) findViewById(R.id.payButton);
    payButton.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        PaymentRequest.PaymentRequestBuilder builder = new PaymentRequest.PaymentRequestBuilder();
        builder.setService("service id", "in-app secret");
        builder.setDisplayString("Level 1.");      // shown on user receipt
        builder.setProductName("gamerId_level1");  // non-consumable purchases are restored using this value
        builder.setType(MpUtils.PRODUCT_TYPE_NON_CONSUMABLE);        // non-consumable items can be later restored
        builder.setIcon(R.drawable.ic_launcher);
        builder.setColours(new CustomDialogColours.Builder()  // optional, there are default colours implemented.
          .setLightBackgroundColour()
          .setButtonBackgroundColour(0xff778899)
          .setButtonTextColour(0xff87CEEB)
          .setRoundCorners()
          .build());
        PaymentRequest pr = builder.build();
        makePayment(pr);
     } });
}
1
2
3
4
5
6
@Override protected void onResume() {
  super.onResume();
  TextView infoText = (TextView)findViewById(R.id.infoText);
  infoText.setText("Gold coins: " + Wallet.getCoins((Context)this));
  }
}

When initializing a payment in Android SDK Library, you use in-app secret. When verifying a payment using the receipt verification request, you use the other secret available in service information tab on Fortumo Dashboard.

Processing payment result

Once the purchase has been processed, a notification will be sent to your BroadcastReceiver class. You can decide to give users access to premium features upon the notification on the device or if you are keeping track of users purchases on your server you will update purchase data from there.

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
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.os.Bundle;

import mp.MpUtils;

import com.your.awesome.application.model.Wallet;

public class PaymentStatusReceiver extends BroadcastReceiver {
  private static String TAG = "PaymentStatusReceiver";

  @Override
  public void onReceive(Context context, Intent intent) {
    Bundle extras = intent.getExtras();
    Log.d(TAG, "- billing_status:  " + String.valueOf(extras.getInt("billing_status")));
    Log.d(TAG, "- credit_amount:   " + extras.getString("credit_amount"));
    Log.d(TAG, "- credit_name:     " + extras.getString("credit_name"));
    Log.d(TAG, "- message_id:      " + extras.getString("message_id") );
    Log.d(TAG, "- payment_code:    " + extras.getString("payment_code"));
    Log.d(TAG, "- price_amount:    " + extras.getString("price_amount"));
    Log.d(TAG, "- price_currency:  " + extras.getString("price_currency"));
    Log.d(TAG, "- product_name:    " + extras.getString("product_name"));
    Log.d(TAG, "- service_id:      " + extras.getString("service_id"));
    Log.d(TAG, "- user_id:         " + extras.getString("user_id"));

    int billingStatus = extras.getInt("billing_status");
    if(billingStatus == MpUtils.MESSAGE_STATUS_BILLED) {
      int coins = Integer.parseInt(intent.getStringExtra("credit_amount"));
      Wallet.addCoins(context, coins);
    }
  }
}

It is important to always update the UI after the purchase has been completed and show the new amount of virtual credits to the user. For that you can have another BroadcastReceiver in your Activity that can update the UI elements more easily.

Saving purchase data

Each time billing status changes method onReceive method is executed, from given intent argument you can get all information related to the purchase including the payment status. This code will be executed even when the user has exited your app.

You should save this transaction information for later use (e.g. when the user re-launches your application). In the example, we update "credits count" when the payment was successful. Later on, when the user re-launches the app or the payment window is closed (onResume), we update the UI to reflect current credits count.

Here's a simple implementation of an in-app Wallet class for saving users credit amount to application preferences.

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
package com.fortumo.FortumoDemo;

import android.content.Context;
import android.content.SharedPreferences;

public class Wallet {
  private static final String PREFS = "com.fortumo.FortumoDemo.PREFS";
  private static final String CREDITS = "virtualcredits";

  public static int addCredits(Context context, int amount) {
    SharedPreferences prefs = context.getSharedPreferences(PREFS, Context.MODE_PRIVATE);
    int currentCredits = prefs.getInt(CREDITS, 0);

    SharedPreferences.Editor editor = prefs.edit();
    currentCredits += amount;
    editor.putInt(CREDITS, currentCredits);
    editor.commit();
    return currentCredits;
  }

  public static int getCredits(Context context) {
    SharedPreferences prefs = context.getSharedPreferences(PREFS, Context.MODE_PRIVATE);
    return prefs.getInt(CREDITS, 0);
  }
}
Credits multiplier

Multiplies amount of credits by some coefficient. For example, if by default user gets 100 credits for 1.00EUR, then with setCreditsMultiplier(1.5d) he will get 150 credits for the same price.

1
2
3
4
5
6
PaymentRequestBuilder builder = new PaymentRequestBuilder();
builder.setService("service id", "in-app secret");
builder.setDisplayString("Get 2x more credits for same price.");
builder.setCreditsMultiplier(2.00d);
builder.setIcon(R.drawable.ic_launcher);
makePayment(builder.build());
Setting custom icon

Shows a custom product icon in the payment window. The image needs to be added as a resource to the Android application.

1
builder.setIcon(R.drawable.ic_launcher);

Updating From Fortumo's Android SDK 9.0.x

Fortumo package and class names have changed. Rename the following in your Android manifest and in code:

  • Package names: com.fortumo.android.* to mp.*
  • com.fortumo.android.Fortumo to mp.MpUtils
  • Proguard configuration: -keep class mp.** { *; }
  • The intent your broadcast receiver is listening for: com.fortumo.android.PAYMENT_STATUS_CHANGED to mp.info.PAYMENT_STATUS_CHANGED
  • Setting your product type to consumable or non-consumable: from builder.setConsumable(true) to builder.setType(MpUtils.TYPE\_CONSUMABLE); from builder.setConsumable(false) to builder.setType(MpUtils.TYPE\_NON\_CONSUMABLE).
  • Change the way a payment request is built.

From:

1
2
3
PaymentRequestBuilder builder = new PaymentRequestBuilder();
builder.setService("service id", "in-app secret");
makePayment(builder.build());

To:

1
2
3
PaymentRequest.PaymentRequestBuilder builder = new PaymentRequest.PaymentRequestBuilder();
builder.setService(Constants.SERVICE_ID, Constants.IN_APP_SECRET);
makePayment(pr);

References

https://developer.android.com/reference/android/content/BroadcastReceiver.html

Help us improve our Merchants Portal. Was this article helpful?