EirikO EirikO - 6 months ago 36
Android Question

Android in-app billing, non consumable items

I'm implementing in-app billing where the user shall be able to buy access to premium content. This is typical non-consumable items. (Let's say the premium content is extra questions or categories in an question-app)

I have used this tutorial to create the first version. The problem is how I shall implement the non-consumable part..

How do I know that the user has bought the premium content? One solution I'm think of is to have a column in my question-table that is initially "0". When the user buy premium access, the this column is set to "1".
Is this a way to go?

Where in my code do I get the message from the billing API that the content is already bought? (If it is..)

My code.. (From tutorial, "buy the possibility to click a button")

public class BuyExtras extends Activity {

private static final String TAG = "inAppBilling";
static final String ITEM_SKU = "android.test.purchased";
IabHelper mHelper;
private Button clickButton;
private Button buyButton;

@Override
protected void onCreate(Bundle savedInstanceState) {
Log.i(TAG, "onCreate CALLED");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_buy_extras);


buyButton = (Button)findViewById(R.id.buyButton);
clickButton = (Button)findViewById(R.id.clickButton);
clickButton.setEnabled(false);



String base64EncodedPublicKey =
"<myKey>";

mHelper = new IabHelper(this, base64EncodedPublicKey);

mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
public void onIabSetupFinished(IabResult result)
{
if (!result.isSuccess()) {
Log.d(TAG, "In-app Billing setup failed: " +
result);
} else {
Log.d(TAG, "In-app Billing is set up OK");
}
}
});


}

public void buyClick(View view) {
mHelper.launchPurchaseFlow(this, ITEM_SKU, 10001, mPurchaseFinishedListener, "mypurchasetoken");
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
if (!mHelper.handleActivityResult(requestCode, resultCode, data)) {
super.onActivityResult(requestCode, resultCode, data);
}
}


IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
public void onIabPurchaseFinished(IabResult result, Purchase purchase)
{
if (result.isFailure()) {
// Handle error
return;
}
else if (purchase.getSku().equals(ITEM_SKU)) {
consumeItem();
buyButton.setEnabled(false);
}

}
};

public void consumeItem() {
mHelper.queryInventoryAsync(mReceivedInventoryListener);
}

IabHelper.QueryInventoryFinishedListener mReceivedInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
if (result.isFailure()) {
// Handle failure
} else {
mHelper.consumeAsync(inventory.getPurchase(ITEM_SKU), mConsumeFinishedListener);
}
}
};


IabHelper.OnConsumeFinishedListener mConsumeFinishedListener = new IabHelper.OnConsumeFinishedListener() {
public void onConsumeFinished(Purchase purchase, IabResult result) {

if (result.isSuccess()) {
clickButton.setEnabled(true);
} else {
// handle error
}
}
};

public void buttonClicked (View view)
{
clickButton.setEnabled(false);
buyButton.setEnabled(true);
}


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


}

I read this question indicating that I not should call the


mHelper.consumeAsync(purchase, mConsumeFinishedListener);


But is just removing it ok? Where should I handle the case that the user tries a second buy?

Answer

If you don't want consume, then don't use consumeAsync.

 @Override
public void onQueryInventoryFinished(IabResult result, Inventory inv)
{
    if (result.isFailure())
    {
        Log.e(TAG, "In-app Billing query failed: " + result);
        return;
    } else
    {
        boolean hasPurchased_ITEM_SKU_PURCHASE_1 = inv.hasPurchase(ITEM_SKU_PURCHASE_1);
        SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getActivity());
        SharedPreferences.Editor editor = sharedPref.edit();
        editor.putBoolean(KEY_PREF_PURCHASE_1_AVAILABLE, !hasPurchased_ITEM_SKU_PURCHASE_1);
        editor.commit();

        // You can update your UI here, ie. Buy buttons.
    }
}

You can use the sharedpref to store the purchase info, and also check every onCreate of the activity and update the sharedpref accordingly. The key part on how to check if a SKU is purchased is:

     boolean hasPurchased_ITEM_SKU_PURCHASE_1 = inv.hasPurchase(ITEM_SKU_PURCHASE_1);

Do your query sync in your IAP setup and update your UI accordingly.

 mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
    public void onIabSetupFinished(IabResult result) 
    {
        if (!result.isSuccess()) {
            Log.d(TAG, "In-app Billing setup failed: " + 
                    result);
        } else {             
              mHelper.queryInventoryAsync(mReceivedInventoryListener);
            Log.d(TAG, "In-app Billing is set up OK");
        }
    }
 });