Question Detail

How to implement In-App billing v3 in Android ?

5 years ago Views 2657 Visit Post Reply

In-app Billing Version 3 (IAP V3) easy to integrate In-app Purchase in an app.we can add our Products and Subscription Plans and offer the user to buy them and get the profit of that Service.
I am not able to Implement In-App Purchase or In-App Billing Functionality in my Android App.
Please elaborate In-App Purchase Tutorial with step by step.

I am using Android Studio for Developing Android App, What I have to import or add in SDK?

How to Implement In-App Billing Version3 in Android Application?

Image result for In-App Billing

I have to implement in-app purchases of the TrivialDrive sample app from google samples but I have got no proper details and not import this project into my Android Studio.


Thread Reply

Hemant Sharma

- 5 years ago

To implement In-App Billing subscription you can use Lib which helps Android Developers to implement In-app purchase easy
Follow me :

What needs to implement in-App Billing?
- You  should have Google Play Console
- You should have copy License KEY from Google Play Store Console
- Develop your app by copy below code.
- Subscription/ Product ID by clicking on In-app products -> SUBSCRIPTIONS / MANAGED PRODUCTS -> Create managed product
- You can see working subcription /Products working state only when your App live. (WAIT FOR APP LIVE)

 

 

Add dependency in your gradle file

compile 'com.anjlab.android.iab.v3:library:1.0.44'

 

InappBilling_Class.java

import android.app.Activity;
import android.app.Dialog;
import android.content.DialogInterface;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.app.AlertDialog;
import android.util.Log;
import android.widget.Toast;

import com.anjlab.android.iab.v3.BillingProcessor;
import com.anjlab.android.iab.v3.SkuDetails;
import com.anjlab.android.iab.v3.TransactionDetails;
import com.techximum.funbook.R;
import com.techximum.funbook.validationPack.CustomeDialogClass;

/**
 * Created by Hemant on 3/13/2018.
 */

public class InappBilling_Class {

    Activity activity;
    private BillingProcessor bp;
    Dialog progressDialog;
    String SUBSCRIPTION_ID = "";
    String LICENSE_KEY = "";
    int i = 0;
    // put your Google merchant id here (as stated in public profile of your Payments Merchant Center)
    // if filled library will provide protection against Freedom alike Play Market simulators
    private static final String MERCHANT_ID = "10001";// PUT YOUR MERCHANT KEY HERE;
    // SAMPLE APP CONSTANTS
    private static final String LOG_TAG = "fSUBSCRIPTION_TAG";

    public InappBilling_Class(Activity in_activity, BillingProcessor bpro) {
        this.activity = in_activity;
        this.bp = bpro;
        LICENSE_KEY = activity.getString(R.string.SUBSCRIPTION_LICENSE_KEY);
    }

    public BillingProcessor initMethod() {
        progressDialog = new Dialog(activity);
        CustomeDialogClass.show(progressDialog, "Initializing...", true);
        if (!BillingProcessor.isIabServiceAvailable(activity)) {
            AlertDialog.Builder builder = new AlertDialog.Builder(activity);
            CustomeDialogClass.oKDialogBox(builder, "ERROR!", "In-app billing service is unavailable, please upgrade Android Market/Play to version >= 3.9.16", R.drawable.ic_wait_crash, false, true);
        }
        bp = new BillingProcessor(activity, LICENSE_KEY, MERCHANT_ID, new BillingProcessor.IBillingHandler() {
            @Override
            public void onProductPurchased(@NonNull String productId, @Nullable TransactionDetails details) {
                //showToast("onProductPurchased: " + productId);
                System.out.println(productId+" ***TRANSACTION DETAILS*** " + details);
                updateTextViews(1);
            }

            @Override
            public void onBillingError(int errorCode, @Nullable Throwable error) {
                showToast("onBillingError: " + Integer.toString(errorCode)+" ___ "+error);
            }

            @Override
            public void onBillingInitialized() {
              //  showToast("onBillingInitialized");
                progressDialog.dismiss();
                updateTextViews(2);
            }

            @Override
            public void onPurchaseHistoryRestored() {
                 showToast("onPurchaseHistoryRestored");
                for (String sku : bp.listOwnedProducts())
                    Log.d(LOG_TAG, "Owned Managed Product: " + sku);
                for (String sku : bp.listOwnedSubscriptions()) {
                    Log.d(LOG_TAG, "Owned Subscription: " + sku);
                    SUBSCRIPTION_ID = sku;
                    showSunscriptionDetails();
                }
            }
        });
        return bp;
    }

    public boolean subscribemethod(String SKU_CODE) {
        SUBSCRIPTION_ID=SKU_CODE;
       return bp.subscribe(activity, SKU_CODE);
    }

    public void updateTextViews(int ia) {
        if(!SUBSCRIPTION_ID.isEmpty()) {
            i++;
//        TextView protext = (TextView)findViewById(R.id.productIdTextView);
//        protext.setText(String.format("%s is%s purchased", PRODUCT_ID, bp.isPurchased(PRODUCT_ID) ? "" : " not"));
//        TextView subtext = (TextView)findViewById(R.id.subscriptionIdTextView);
//        subtext.setText(String.format("%s is%s subscribed", SUBSCRIPTION_ID, bp.isSubscribed(SUBSCRIPTION_ID) ? "" : " not"));
            showToast(String.format(" %s is%s subscribed", SUBSCRIPTION_ID, bp.isSubscribed(SUBSCRIPTION_ID) ? "" : " not") + " | " + SUBSCRIPTION_ID);
            if (bp.isSubscribed(SUBSCRIPTION_ID)) {
                showSunscriptionDetails();
            } else {
                showToast(String.format("is not subscribed") + " | " + SUBSCRIPTION_ID);
            }
        }
    }

    private void showToast(String message) {
        Toast.makeText(activity, message, Toast.LENGTH_LONG).show();
    }

    void showSunscriptionDetails() {
        SkuDetails subs = bp.getSubscriptionListingDetails(SUBSCRIPTION_ID);
        System.out.println("***__SUBSCRIPTION__*** " + subs);
        //showToast(subs != null ? subs.toString() : "Failed to load subscription details");
        AlertDialog.Builder builderDetails = new AlertDialog.Builder(activity);
        builderDetails.setPositiveButton("Okay!",
                new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        activity.onBackPressed();
                    }
                });
        CustomeDialogClass.oKDialogBox(builderDetails, "Subscribed Plan : "+subs.title, subs.description + "\nPrice : "+subs.priceText+ "\nSubscription Period : "+subs.introductoryPriceCycles, R.drawable.ic_wallet, false, false);
    }
}

Now come on your SubscriptionActivity.java

public class SubscriptionActivity extends Activity {

    InappBilling_Class inapp;
    private BillingProcessor bp;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_subscription);
...
inapp = new InappBilling_Class(SubscriptionActivity.this, bp);
bp = inapp.initMethod();
....
}
@Override
protected void onResume() {
    super.onResume();
    inapp.updateTextViews(3);
}

@Override
public void onDestroy() {
    if (bp != null)
        bp.release();
    super.onDestroy();
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (!bp.handleActivityResult(requestCode, resultCode, data))
        super.onActivityResult(requestCode, resultCode, data);
    System.out.println("**********" + data.getData() + "**********");
}}

 

Enjoy your subscription/ Products showing In-App.

Hemant Sharma

- 5 years ago

To implement In-App Billing subscription you can use Lib which helps Android Developers to implement In-app purchase easy
Follow me :

What needs to implement in-App Billing?
- You  should have Google Play Console
- You should have copy License KEY from Google Play Store Console
- Develop your app by copy below code.
- Subscription/ Product ID by clicking on In-app products -> SUBSCRIPTIONS / MANAGED PRODUCTS -> Create managed product
- You can see working subcription /Products working state only when your App live. (WAIT FOR APP LIVE)

 

 

Add dependency in your gradle file

compile 'com.anjlab.android.iab.v3:library:1.0.44'

 

InappBilling_Class.java

import android.app.Activity;
import android.app.Dialog;
import android.content.DialogInterface;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.app.AlertDialog;
import android.util.Log;
import android.widget.Toast;

import com.anjlab.android.iab.v3.BillingProcessor;
import com.anjlab.android.iab.v3.SkuDetails;
import com.anjlab.android.iab.v3.TransactionDetails;
import com.techximum.funbook.R;
import com.techximum.funbook.validationPack.CustomeDialogClass;

/**
 * Created by Hemant on 3/13/2018.
 */

public class InappBilling_Class {

    Activity activity;
    private BillingProcessor bp;
    Dialog progressDialog;
    String SUBSCRIPTION_ID = "";
    String LICENSE_KEY = "";
    int i = 0;
    // put your Google merchant id here (as stated in public profile of your Payments Merchant Center)
    // if filled library will provide protection against Freedom alike Play Market simulators
    private static final String MERCHANT_ID = "10001";// PUT YOUR MERCHANT KEY HERE;
    // SAMPLE APP CONSTANTS
    private static final String LOG_TAG = "fSUBSCRIPTION_TAG";

    public InappBilling_Class(Activity in_activity, BillingProcessor bpro) {
        this.activity = in_activity;
        this.bp = bpro;
        LICENSE_KEY = activity.getString(R.string.SUBSCRIPTION_LICENSE_KEY);
    }

    public BillingProcessor initMethod() {
        progressDialog = new Dialog(activity);
        CustomeDialogClass.show(progressDialog, "Initializing...", true);
        if (!BillingProcessor.isIabServiceAvailable(activity)) {
            AlertDialog.Builder builder = new AlertDialog.Builder(activity);
            CustomeDialogClass.oKDialogBox(builder, "ERROR!", "In-app billing service is unavailable, please upgrade Android Market/Play to version >= 3.9.16", R.drawable.ic_wait_crash, false, true);
        }
        bp = new BillingProcessor(activity, LICENSE_KEY, MERCHANT_ID, new BillingProcessor.IBillingHandler() {
            @Override
            public void onProductPurchased(@NonNull String productId, @Nullable TransactionDetails details) {
                //showToast("onProductPurchased: " + productId);
                System.out.println(productId+" ***TRANSACTION DETAILS*** " + details);
                updateTextViews(1);
            }

            @Override
            public void onBillingError(int errorCode, @Nullable Throwable error) {
                showToast("onBillingError: " + Integer.toString(errorCode)+" ___ "+error);
            }

            @Override
            public void onBillingInitialized() {
              //  showToast("onBillingInitialized");
                progressDialog.dismiss();
                updateTextViews(2);
            }

            @Override
            public void onPurchaseHistoryRestored() {
                 showToast("onPurchaseHistoryRestored");
                for (String sku : bp.listOwnedProducts())
                    Log.d(LOG_TAG, "Owned Managed Product: " + sku);
                for (String sku : bp.listOwnedSubscriptions()) {
                    Log.d(LOG_TAG, "Owned Subscription: " + sku);
                    SUBSCRIPTION_ID = sku;
                    showSunscriptionDetails();
                }
            }
        });
        return bp;
    }

    public boolean subscribemethod(String SKU_CODE) {
        SUBSCRIPTION_ID=SKU_CODE;
       return bp.subscribe(activity, SKU_CODE);
    }

    public void updateTextViews(int ia) {
        if(!SUBSCRIPTION_ID.isEmpty()) {
            i++;
//        TextView protext = (TextView)findViewById(R.id.productIdTextView);
//        protext.setText(String.format("%s is%s purchased", PRODUCT_ID, bp.isPurchased(PRODUCT_ID) ? "" : " not"));
//        TextView subtext = (TextView)findViewById(R.id.subscriptionIdTextView);
//        subtext.setText(String.format("%s is%s subscribed", SUBSCRIPTION_ID, bp.isSubscribed(SUBSCRIPTION_ID) ? "" : " not"));
            showToast(String.format(" %s is%s subscribed", SUBSCRIPTION_ID, bp.isSubscribed(SUBSCRIPTION_ID) ? "" : " not") + " | " + SUBSCRIPTION_ID);
            if (bp.isSubscribed(SUBSCRIPTION_ID)) {
                showSunscriptionDetails();
            } else {
                showToast(String.format("is not subscribed") + " | " + SUBSCRIPTION_ID);
            }
        }
    }

    private void showToast(String message) {
        Toast.makeText(activity, message, Toast.LENGTH_LONG).show();
    }

    void showSunscriptionDetails() {
        SkuDetails subs = bp.getSubscriptionListingDetails(SUBSCRIPTION_ID);
        System.out.println("***__SUBSCRIPTION__*** " + subs);
        //showToast(subs != null ? subs.toString() : "Failed to load subscription details");
        AlertDialog.Builder builderDetails = new AlertDialog.Builder(activity);
        builderDetails.setPositiveButton("Okay!",
                new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        activity.onBackPressed();
                    }
                });
        CustomeDialogClass.oKDialogBox(builderDetails, "Subscribed Plan : "+subs.title, subs.description + "\nPrice : "+subs.priceText+ "\nSubscription Period : "+subs.introductoryPriceCycles, R.drawable.ic_wallet, false, false);
    }
}

Now come on your SubscriptionActivity.java

public class SubscriptionActivity extends Activity {

    InappBilling_Class inapp;
    private BillingProcessor bp;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_subscription);
...
inapp = new InappBilling_Class(SubscriptionActivity.this, bp);
bp = inapp.initMethod();
....
}
@Override
protected void onResume() {
    super.onResume();
    inapp.updateTextViews(3);
}

@Override
public void onDestroy() {
    if (bp != null)
        bp.release();
    super.onDestroy();
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (!bp.handleActivityResult(requestCode, resultCode, data))
        super.onActivityResult(requestCode, resultCode, data);
    System.out.println("**********" + data.getData() + "**********");
}}

 

Enjoy your subscription/ Products showing In-App.

iTching bRains.

- 4 years ago

CustomeDialogClass not importing in my app?

 

iTching bRains.

- 4 years ago

 public void updateTextViews(int ia) {
        if(!SUBSCRIPTION_ID.isEmpty()) {
            i++;
//        TextView protext = (TextView)findViewById(R.id.productIdTextView);
//        protext.setText(String.format("%s is%s purchased", PRODUCT_ID, bp.isPurchased(PRODUCT_ID) ? "" : " not"));
//        TextView subtext = (TextView)findViewById(R.id.subscriptionIdTextView);
//        subtext.setText(String.format("%s is%s subscribed", SUBSCRIPTION_ID, bp.isSubscribed(SUBSCRIPTION_ID) ? "" : " not"));
            showToast(String.format(" %s is%s subscribed", SUBSCRIPTION_ID, bp.isSubscribed(SUBSCRIPTION_ID) ? "" : " not") + " | " + SUBSCRIPTION_ID);
            if (bp.isSubscribed(SUBSCRIPTION_ID)) {
                showSunscriptionDetails();
            } else {
                showToast(String.format("is not subscribed") + " | " + SUBSCRIPTION_ID);
            }
        }
    }

 

 

why did you comment first 4 lines of the code in method?

alex levine

- 4 years ago

Add Customize Dialog Class

import android.app.Activity;
import android.app.Dialog;
import android.content.DialogInterface;
import android.graphics.drawable.Drawable;
import android.support.v7.app.AlertDialog;

public class CustomeDialogClass {
    public static void show(final Dialog dialog, String title, boolean cancelable) {
        dialog.setContentView(R.layout.custome_progressdialog_lay);
        dialog.setTitle(title);
        dialog.setCancelable(cancelable);
        /*//there are a lot of settings, for dialog, check them all out!

        //set up text
        TextView text = (TextView) dialog.findViewById(R.id.TextView01);
        text.setText(R.string.lots_of_text);

        //set up image view
        ImageView img = (ImageView) dialog.findViewById(R.id.ImageView01);
        img.setImageResource(R.drawable.nista_logo);

        //set up button
        Button button = (Button) dialog.findViewById(R.id.Button01);
        button.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });*/
        //now that the dialog is set up, it's time to show it
      /*  if (startStop) {
            dialog.show();
        } else {
            dialog.dismiss();
        }
        Toast.makeText(getBaseContext(), startStop + "", Toast.LENGTH_SHORT).show();*/
        dialog.show();
    }

    public static void yesNoDialogBox(final AlertDialog.Builder dialog, String title, String msg, int icon, boolean cancelable) {
        //AlertDialog.Builder builder = new AlertDialog.Builder(this);
        dialog.setTitle(title);
        dialog.setIcon(icon);
        dialog.setCancelable(cancelable);
        dialog.setMessage(msg);
        /*dialog.setPositiveButton("Delete",
                new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        onBackPressed();
                    }
                });*/
        dialog.setNegativeButton("Not Now", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
            }
        });
        AlertDialog dialogs = dialog.create();
        // display dialog
        dialogs.show();
    }


    public static void oKDialogBox(final AlertDialog.Builder dialog, String title, String msg, int icon, boolean cancelable, boolean nativebtn) {
        //AlertDialog.Builder builder = new AlertDialog.Builder(this);
        dialog.setTitle(title);
        dialog.setIcon(icon);
        dialog.setCancelable(cancelable);
        dialog.setMessage(msg);
        /*dialog.setPositiveButton("Delete",
                new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        onBackPressed();
                    }
                });*/
        if (nativebtn) {
            dialog.setNegativeButton("Okay!", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    dialog.dismiss();
                }
            });
        }
        AlertDialog dialogs = dialog.create();
        // display dialog
        dialogs.show();
    }

}