I have looked at other similar questions on SO regarding the same issue and all point to the same point. To check the ID of the product. I am implementing in-app purchases for the first time and i think i am using the correct product id in the code. I am following TrivialDrive sample.
So, the error is as follows:
My product id from Google Play:
My code is as follows:
package com.xx.xxx;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import com.xx.xxx.util.IabHelper;
import com.xx.xxx.util.IabResult;
import com.xx.xxx.util.Inventory;
import com.xx.xxx.util.Purchase;
public class UpgradeDonateActivity extends AppCompatActivity {
private String base64EncodedPublicKey = "PUBLIC_KEY_REPLACED";
private static final int PURCHASE_RESPONSE = 1;
private static final String PURCHASE_TOKEN = "purchase_token";
private static final String SKU_UPGRADE_2 = "test";
//private static final String SKU_UPGRADE = "Upgrade";
private static final String SKU_DONATE_10 = "donate_10";
private static final String SKU_DONATE_5 = "donate_5";
private static final String SKU_DONATE_3 = "donate_3";
private static final String SKU_DONATE_2 = "donate_2";
private boolean mIsUpgraded = false;
private Toolbar toolbar;
private TextView title;
private IabHelper mIabHelper;
private Button btnUpgrade;
IabHelper.QueryInventoryFinishedListener mGotInventoryListener
= new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result,
Inventory inventory) {
Log.d(Const.DEBUG, "Query inventory finished");
if (mIabHelper == null) return;
if (result.isFailure()) {
// Handle failure
Toast.makeText(UpgradeDonateActivity.this, "onQueryInventoryFinished Failed", Toast.LENGTH_LONG).show();
return;
}
Log.d(Const.DEBUG, "Query inventory successful");
Purchase upgradePurchase = inventory.getPurchase(SKU_UPGRADE_2);
mIsUpgraded = (upgradePurchase != null && verifyDeveloperPayload(upgradePurchase));
Log.d(Const.DEBUG, "User is " + (mIsUpgraded ? "Upgraded" : "Not Upgraded"));
}
};
boolean verifyDeveloperPayload(Purchase p) {
String payload = p.getDeveloperPayload();
return true;
}
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener
= new IabHelper.OnIabPurchaseFinishedListener() {
public void onIabPurchaseFinished(IabResult result,
Purchase purchase) {
Log.d(Const.DEBUG, "Purchase finished: " + result + ", purchase: " + purchase);
if(mIabHelper == null) return;
if (result.isFailure()) {
// Handle error
Log.d(Const.DEBUG, "Error Purchasing: "+result);
return;
}
if(!verifyDeveloperPayload(purchase)) {
Log.d(Const.DEBUG, "Error purchasing. Authenticity verification failed.");
return;
}
Log.d(Const.DEBUG, "Purchase successful.");
if(purchase.getSku().equals(SKU_UPGRADE_2)) {
Log.d(Const.DEBUG, "Purchase is upgrade. Congratulating user.");
mIsUpgraded = true;
}
}
};
IabHelper.OnConsumeFinishedListener mConsumeFinishedListener =
new IabHelper.OnConsumeFinishedListener() {
public void onConsumeFinished(Purchase purchase,
IabResult result) {
if (result.isSuccess()) {
//clickButton.setEnabled(true);
Toast.makeText(UpgradeDonateActivity.this, "", Toast.LENGTH_LONG).show();
} else {
// handle error
Toast.makeText(UpgradeDonateActivity.this, "Error", Toast.LENGTH_LONG).show();
}
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_upgrade_donate);
toolbar = (Toolbar) findViewById(R.id.toolbar);
title = (TextView) toolbar.findViewById(R.id.toolbar_title);
title.setText("");
setSupportActionBar(toolbar);
getSupportActionBar().setHomeButtonEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
btnUpgrade = (Button) findViewById(R.id.button_upgrade);
btnUpgrade.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mIabHelper = new IabHelper(UpgradeDonateActivity.this, base64EncodedPublicKey);
mIabHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
#Override
public void onIabSetupFinished(IabResult result) {
if (!result.isSuccess()) {
Log.d(Const.DEBUG, "In-app Billing setup Failed");
} else {
Log.d(Const.DEBUG, "In-app Billing setup OK");
Toast.makeText(UpgradeDonateActivity.this, "In-app Billing setup OK", Toast.LENGTH_SHORT).show();
mIabHelper.launchPurchaseFlow(UpgradeDonateActivity.this, SKU_UPGRADE_2, PURCHASE_RESPONSE, mPurchaseFinishedListener, PURCHASE_TOKEN);
}
}
});
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.d(Const.DEBUG, "onActivityResult(" + requestCode + "," + resultCode + "," + data);
if (mIabHelper == null) return;
// Pass on the activity result to the helper for handling
if (!mIabHelper.handleActivityResult(requestCode, resultCode, data)) {
// not handled, so handle it ourselves (here's where you'd
// perform any handling of activity results not related to in-app
// billing...
super.onActivityResult(requestCode, resultCode, data);
} else {
Log.d(Const.DEBUG, "onActivityResult handled by IABUtil.");
}
}
public void consumeItem() {
mIabHelper.queryInventoryAsync(mGotInventoryListener);
}
#Override
public void onDestroy() {
super.onDestroy();
if (mIabHelper != null) mIabHelper.dispose();
mIabHelper = null;
}
}
Can anyone tell me what is it that i am doing wrong in this case? How should i fix it?
Make sure your .apk with billing in place (and right permissions) is Published (be it alpha) and allow some time for Google Play to absorb the new .apk, may be a couple of hours.
Also, make sure the application version code in your current development build is the same as the one of the published billing-enabled build.
On upload APK page in ALPHA TESTING there is a link "Opt-in URL ". Go there and accept being a tester using the testing account.
Aso, here is a useful checklist https://stackoverflow.com/a/22469253/1819570
Related
i wanna make an in-app purchase app. I have a code.And i have google play console all set. But id doesn't work.It's giving me this error :
"IabResult: Error checking for billing v3 support. (response: 3:Billing Unavailable)"
So i wanna check if my device is supports in-app billing v3. Here is my code:
package com.khabuko.dtv;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import com.khabuko.dtv.util.IabHelper;
import com.khabuko.dtv.util.IabResult;
import com.khabuko.dtv.util.Inventory;
import com.khabuko.dtv.util.Purchase;
public class InAppBillingActivity extends AppCompatActivity {
private static final String TAG =
"InAppBilling";
IabHelper mHelper;
static final String ITEM_SKU = "com.khabuko.item";
private Button clickButton;
private Button buyButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_in_app_billing);
buyButton = (Button)findViewById(R.id.buyButton);
buyButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
buyClick(v);
}
});
clickButton = (Button)findViewById(R.id.clickButton);
clickButton.setEnabled(false);
String base64EncodedPublicKey =
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAn+naZOOOHNVdP0zQMkeX5mFwBb9BU78cg4oqAxtY8gaMMuEHAaHBwU7yXW6zVh9uTof23SO4GzxTJcIPXCeTyMFmcoFkNvPtqZSFqYcqA5M8Ief0tzpXr81aLEe0lxSy/t3VTN29UA+AaXjt3bvsDXQQPUQXr1HEONfix6TsudI6SCILftZTMIfRZYfOU+0OJdi7J8uDkU2TBjz40UhGc4SWmCoANXVM5yjZ8w4jspXXmej7pP52NMb5nAlK5NrAgIEjHhSDrf8Sl0DhNwLTJM7e2yOWOPt/MvdDsQo1ensm2sSH0jwn1K04RVC8AIGPqtzxLZgP+Ysby0HKpMSU3wIDAQAB";
mHelper = new IabHelper(this, base64EncodedPublicKey);
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
public void onIabSetupFinished(IabResult result) {
Log.d(TAG,"45-46");
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 buttonClicked (View view)
{
clickButton.setEnabled(false);
buyButton.setEnabled(true);
}
public void buyClick(View view) {
mHelper.launchPurchaseFlow(this, ITEM_SKU, 10001,
mPurchaseFinishedListener, "mypurchasetoken");
}
#Override
protected void onActivityResult(int requestCode, int resultCode,
Intent data)
{
Log.i(TAG, "onActivityResult(" + requestCode + "," + resultCode + "," + data);
if (!mHelper.handleActivityResult(requestCode,
resultCode, data)) {
super.onActivityResult(requestCode, resultCode, data);
}else {
Log.i(TAG, "onActivityResult handled by IABUtil.");
}
}
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
}
}
};
#Override
public void onDestroy() {
super.onDestroy();
if (mHelper != null) mHelper.dispose();
mHelper = null;
}
}
In-app-billing availability is checked in IabHelper.OnIabSetupFinishedListener().
But you have to wait some time after creating new SKUs. Any modification in Google Console doesn't happen immediately.
I set up a subscription product in my app and it works for purchasing. I see the purchase in the google developer console. When I logged out and then back in to the app, I am taken to the subscribe page again. The app does not recognize that the subscription was purchased and it should allow the user access. If I click the subscribe button again, it does say "You've already subscribed to... Manage Subscriptions." I am not sure what needs to be done to make it either send the user to the subscribed info after verifying the subscription, or reject if subscription not found and send user to the subscribe page. I think I just don't have the knowledge yet to be sure how to build it. Here is the code I have. Am I missing a chunk of code that would handle that?
I am using firebase as my backend for register/login. Not sure if I need to utilize firebase to keep the token, etc. Any help would be appreciated. I know I am a novice and learning, but my project is 98% complete and this is holding me back.
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import com.iliprivateequity.btfxforexalerts.Util.IabHelper;
import com.iliprivateequity.btfxforexalerts.Util.IabResult;
import com.iliprivateequity.btfxforexalerts.Util.Inventory;
import com.iliprivateequity.btfxforexalerts.Util.Purchase;
public class GoogleInAppBilling extends AppCompatActivity implements View.OnClickListener {
private String base64EncodedPublicKey = "*****";
public Button buttonSubscribe;
public Button buttonSubscribed;
IabHelper mHelper;
static final String SKU_SUBSCRIBE_BTFX = "btfx_alerts_service_50";
static final String TAG = "BTFX_Alerts";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_google_in_app_billing);
loadInAppPurchase();
buttonSubscribe = (Button) findViewById(R.id.buttonsubscribe);
buttonSubscribed = (Button) findViewById(R.id.button_subscribed);
buttonSubscribed.setEnabled(false); //todo remember to set back to false. its true just for testing the build
buttonSubscribe.setOnClickListener(this);
buttonSubscribed.setOnClickListener(this);
}
private void loadInAppPurchase() {
mHelper = new IabHelper(this, base64EncodedPublicKey);
mHelper.enableDebugLogging(true);
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
#Override
public void onIabSetupFinished(IabResult result) {
if (!result.isSuccess()) {
Log.d(TAG, "Problem setting up in-app billing: " + result);
} else {
Log.d(TAG, "Setup successful. Querying inventory.");
}
mHelper.queryInventoryAsync(mGotInventoryListener);
}
});
}
IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
#Override
public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
Log.d(TAG, "Query inventory finished.");
if (result.isFailure()) {
Log.d(TAG, "Failed to query inventory: " + result);
return;
}
Log.d(TAG, "Query inventory was successful.");
Purchase sku_purchase = inventory.getPurchase(SKU_SUBSCRIBE_BTFX);
if (sku_purchase != null) {
mHelper.consumeAsync(inventory.getPurchase(SKU_SUBSCRIBE_BTFX),
mConsumeFinishedListener);
return;
}
}
};
IabHelper.OnConsumeFinishedListener mConsumeFinishedListener = new IabHelper.OnConsumeFinishedListener(){
public void onConsumeFinished(Purchase purchase, IabResult result) {
Log.d("Tag", "Consumption finished. Purchase: " + purchase + ", result: " + result);
if (mHelper == null)
return;
if (result.isSuccess()) {
Log.d("TAG", "Consumption successful. Provisioning.");
} else {
Log.d("TAG", "Error while consuming: " + result);
}
Log.d("Tag", "End consumption flow.");
}
};
#Override
public void onClick(View v) {
if (v == buttonSubscribe) {
mHelper.launchPurchaseFlow(GoogleInAppBilling.this, SKU_SUBSCRIBE_BTFX, IabHelper.ITEM_TYPE_SUBS
, 10001, mPurchaseFinishedListener, "alertservicepurchased");
}
if (v == buttonSubscribed ){
startActivity(new Intent(this, ProfileActivity.class));
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
if (!mHelper.handleActivityResult(requestCode, resultCode, data)){
super.onActivityResult(requestCode,resultCode,data);
}else{
Log.d("TAG", "onActivityResult handled by IABUtil.");
}
}
// Callback for when a purchase is finished
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener
= new IabHelper.OnIabPurchaseFinishedListener() {
public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
Log.d(TAG, "Purchase finished: " + result + ", purchase: " + purchase);
if (mHelper == null) return;
if (result.isFailure()) {
Log.d(TAG, "Error purchasing: " + result);
return;
}
Log.d(TAG, "BTFX Alerts subscription purchased.");
if (purchase.getSku().equals(SKU_SUBSCRIBE_BTFX)) {
Log.d("TAG", "Thank you for subscribing!");
mHelper.consumeAsync(purchase, mConsumeFinishedListener);
// bought the btfx alerts subscription
buttonSubscribe.setEnabled(false);
buttonSubscribed.setEnabled(true);
}
}
};
};
You just need to check if user already have a subscription and depends on result show/hide payed stuff.
There is example how to do that. Also you can consider to use that library, which simplify work with IAP on android.
I want to use In-App purchase using Google API and JNI in C++ is there sample or tutorial that use JNI for In-app Billing ?
item in my Game is consumable.
i can use IAP in java and this is main activity class But how i call it From JNI
public class IAPActivity extends Activity {
public static final String RSA= "********";
// Debug tag, for logging
private static final String TAG = "LOG";
// SKUs for our products: the premium upgrade (non-consumable)
private static final String SKU_PREMIUM = "gp";
// Does the user have the premium upgrade?
private boolean mIsPremium = false;
// (arbitrary) request code for the purchase flow
//static final int RC_REQUEST = ;
// The helper object
private IabHelper mHelper;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// You can find it in your Bazaar console, in the Dealers section.
// It is recommended to add more security than just pasting it in your source code;
mHelper = new IabHelper(this, RSA);
final IabHelper.QueryInventoryFinishedListener onQueryInventoryFinished = new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
Log.d(TAG, "Query inventory finished.");
//kharid nakarde
if (result.isFailure()) {
Log.d(TAG, "Failed to query inventory: " + result);
return;
}
else {
Log.d(TAG, "Query inventory was successful.");
// does the user have the premium upgrade?
mIsPremium = inventory.hasPurchase(SKU_PREMIUM);
// update UI accordingly
Log.d(TAG, "User is " + (mIsPremium ? "PREMIUM" : "NOT PREMIUM"));
}
Log.d(TAG, "Initial inventory query finished; enabling main UI.");
}
};
final IabHelper.OnIabPurchaseFinishedListener onIabPurchaseFinished = new OnIabPurchaseFinishedListener() {
public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
// TODO Auto-generated method stub
if (result.isFailure()) {
Log.d(TAG, "Error purchasing: " + result);
return;
}
else if (purchase.getSku().equals(SKU_PREMIUM)) {
// give user access to premium content and update the UI
}
}
};
Log.d(TAG, "Starting setup.");
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
public void onIabSetupFinished(IabResult result) {
Log.d(TAG, "Setup finished.");
if (!result.isSuccess()) {
// Oh noes, there was a problem.
Log.d(TAG, "Problem setting up In-app Billing: " + result);
}
// Hooray, IAB is fully set up!
mHelper.queryInventoryAsync(onQueryInventoryFinished);
}
});
Button btnPurchase=(Button) findViewById(R.id.btnPurchaseGP);
btnPurchase .setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
// TODO Auto-generated method stub
mHelper.launchPurchaseFlow(IAPActivity.this, SKU_PREMIUM, 0, onIabPurchaseFinished, "payload-string");
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Log.d(TAG, "onActivityResult(" + requestCode + "," + resultCode + "," + data);
// Pass on the activity result to the helper for handling
if (!mHelper.handleActivityResult(requestCode, resultCode, data)) {
super.onActivityResult(requestCode, resultCode, data);
} else {
Log.d(TAG, "onActivityResult handled by IABUtil.");
}
}
#Override
public void onDestroy() {
super.onDestroy();
if (mHelper != null) mHelper.dispose();
mHelper = null;
}
}
Unfortunately JNI is very complex and i don't any idea for use it please Help me
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?
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");
}
}
});
I tried setting up InApp purchases for a donation with the guide provided by Google but when I call the activity (which should return if it was a success or not) but it throws this error:
In-app billing error: Illegal state for operation (launchPurchaseFlow): IAB helper is not set up
The activity is called with this method:
public boolean donation() {
int success = 0;
Intent intent = new Intent(Main.this, Donate.class);
startActivityForResult(intent, success);
if (success != 0) {
return true;
}
else return false;
}
And the Donate class (which I tried coding with the guide) looks like this:
import java.math.BigInteger;
import java.security.SecureRandom;
import maturaarbeit.nicola_pfister.marks.R;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Bundle;
import android.util.Log;
public class Donate extends Activity {
IabHelper mHelper;
private static final String TAG = "Donate";
private String payload;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String base64EncodedPublicKey = getKey();
mHelper = new IabHelper(this, base64EncodedPublicKey);
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
#Override
public void onIabSetupFinished(IabResult result) {
if (!result.isSuccess()) {
Log.d(TAG, "Problem setting up In-app Billing: " + result);
}
}
});
SharedPreferences prefs = getSharedPreferences(getPackageName() + "_preferences", MODE_PRIVATE); //Add shared preferences
payload = prefs.getString("devpayload", null);
if (payload == null) {
payload = getPayload();
Editor editor = prefs.edit();
editor.putString("devpayload", payload)
.apply();
}
mHelper.launchPurchaseFlow(this, "donation_1chf", 1, mPurchaseFinishedListener, payload);
finish();
}
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
#Override
public void onIabPurchaseFinished(IabResult result, Purchase info) {
if (result.isFailure()) {
Log.d(TAG, "Error purchasing: " +result);
return;
}
else if (info.getDeveloperPayload().equals(payload)) {
return;
}
}
};
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.i(TAG, "onActivityResult(" + requestCode + "," + resultCode + "," + data);
if (!mHelper.handleActivityResult(requestCode, resultCode, data)) {
super.onActivityResult(requestCode, resultCode, data);
} else {
Log.i(TAG, "onActivityResult handled by IABUtil.");
}
}
private String getKey() {
//Code for building public key
}
private String getPayload() {
SecureRandom random = new SecureRandom();
{
return new BigInteger(130, random).toString(32);
}
}
#Override
protected void onDestroy() {
if (mHelper != null) mHelper.dispose();
mHelper = null;
super.onDestroy();
}
}
It is supposed to generate a dev payload which is stored in shared prefs if there isn't already one. If you need any additional information feel free to ask.
Thanks for your help!
You have to wait for onIabSetupFinishedListener to return before calling launchPurchaseFlow - move those lines into your onIabSetupFinishedListener's onIabSetupFinished method to ensure that the IabHelper's setup is complete:
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
#Override
public void onIabSetupFinished(IabResult result) {
if (!result.isSuccess()) {
Log.d(TAG, "Problem setting up In-app Billing: " + result);
}
else { // Only launch the purchase flow if setup succeeded
mHelper.launchPurchaseFlow(Donate.this, "donation_1chf", 1,
mPurchaseFinishedListener, payload);
}
}
});
You should use real device for app billing because when using emulator some parameters are being null and it causes runtime errors.