Im trying to add in app billing that will allow the user to make a purchase as many times as they like (no limit). Therefore it must be consumed. The first time I run the code on a new device it works fine and the test purchase is made successfully. However it fails to be consumed and doesnt let me make another purchase. The problem seems to be in this method, as it always ends up with result.isFailure() thus, the purchase is not consumed (and can only be made once).
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
public void onIabPurchaseFinished(IabResult result, Purchase purchase)
{
if (result.isFailure()) {
Toast.makeText(getApplicationContext(), "Failed to make purchase.", Toast.LENGTH_LONG).show();
return;
}
else if (purchase.getSku().equals(ITEM_SKU)) {
consumeItem();
}
}
};
Does anyone know how I can fix the problem?
Here is the rest of the code:
Preference removeAds = (Preference) findPreference("inAppBilling");
removeAds.setOnPreferenceClickListener(new OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference preference) {
mHelper.launchPurchaseFlow(About.this, ITEM_SKU, 10001, mPurchaseFinishedListener, "mypurchasetoken");
return true;
}
});
#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()) {
Toast.makeText(getApplicationContext(), "Failed to make purchase.", Toast.LENGTH_LONG).show();
return;
}
else if (purchase.getSku().equals(ITEM_SKU)) {
consumeItem();
}
}
};
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()) {
CustomAlerts.showBasicAlert("Thanks", "We appreciate your support.", About.this);
} else {
// handle error
}
}
};
#Override
public void onDestroy() {
super.onDestroy();
if (mHelper != null) mHelper.dispose();
mHelper = null;
}
You need to query the users inventory on app start. If there are any purchased but not yet redeemed products in it, you can just redeem them at this point. Here's the docu for retrieving it.
Related
How can I buy one thing multiple times? Here is my code:
// [...]
String base64EncodedPublicKey =
"MIIB...;
mHelper = new IabHelper(this, base64EncodedPublicKey);
mHelper.startSetup(new
IabHelper.OnIabSetupFinishedListener() {
public void onIabSetupFinished(IabResult result) {
if (!result.isSuccess()) {
Toast.makeText(gift.this, "Setup no Success", Toast.LENGTH_SHORT).show();
Log.d(TAG, "In-app Billing setup failed: " + result);
} else {
Toast.makeText(gift.this, "Setup Success", Toast.LENGTH_SHORT).show();
}
}
});
}
public void insert(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()) {
Toast.makeText(gift.this, "Error 1", Toast.LENGTH_SHORT).show();
}
else if (purchase.getSku().equals(ITEM_SKU)) {
consumeItem();
Toast.makeText(gift.this, "OK 1", Toast.LENGTH_SHORT).show();
// mHelper.consumeAsync(purchase, mConsumeFinishedListener);
}
}
};
public void consumeItem() {
mHelper.queryInventoryAsync(mReceivedInventoryListener);
}
IabHelper.QueryInventoryFinishedListener mReceivedInventoryListener
= new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result,
Inventory inventory) {
if (result.isFailure()) {
Toast.makeText(gift.this, "Error 2", Toast.LENGTH_SHORT).show();
} else {
mHelper.consumeAsync(inventory.getPurchase(ITEM_SKU),
mConsumeFinishedListener);
Toast.makeText(gift.this, "OK 2", Toast.LENGTH_SHORT).show();
}
}
};
IabHelper.OnConsumeFinishedListener mConsumeFinishedListener =
new IabHelper.OnConsumeFinishedListener() {
public void onConsumeFinished(Purchase purchase,
IabResult result) {
if (result.isSuccess()) {
Toast.makeText(gift.this, "Success 1", Toast.LENGTH_SHORT).show();
// mHelper.consumeAsync(purchase, mConsumeFinishedListener);
} else {
Toast.makeText(gift.this, "Error 3", Toast.LENGTH_SHORT).show();
}
}
};
#Override
public void onDestroy() {
super.onDestroy();
if (mHelper != null) mHelper.dispose();
mHelper = null;
}
}
When I click on my button it says: "payment successful" and after that when I click on my button again it does not do anything.
I have 2 questions:
How to buy a single in-app-purchase multiple times?
How can I display a Toast after the payment was successful?
Thanks for answers.
The purchase must be consumed after every purchase, then it can be purchased again. If you are able to purchase the item once but not again, then almost assuredly the problem is that you are not consuming it correctly.
There doesn't appear to be any problem with your code, Toast.makeText(...) should work fine.
I followed a tutorial online. I have all this code coming before my onCreate
IabHelper.OnConsumeFinishedListener mConsumeFinishedListener =
new IabHelper.OnConsumeFinishedListener() {
public void onConsumeFinished(Purchase purchase,
IabResult result) {
if (result.isSuccess()) {
btnPurchase.setEnabled(false);
btnStats.setBackgroundResource(R.drawable.purchasepressed);
test.setText("IT WORKS!!!");
} else {
// handle error
}
}
};
public void consumeItem() throws IabHelper.IabAsyncInProgressException {
mHelper.queryInventoryAsync(mReceivedInventoryListener);
}
#Override
protected void onActivityResult(int requestCode, int resultCode,
Intent data) {
try {
if (!mHelper.handleActivityResult(requestCode,
resultCode, data)) {
super.onActivityResult(requestCode, resultCode, data);
}
} catch (IabHelper.IabAsyncInProgressException e) {
e.printStackTrace();
}
}
IabHelper.QueryInventoryFinishedListener mReceivedInventoryListener
= new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result,
Inventory inventory) throws IabHelper.IabAsyncInProgressException {
if (result.isFailure()) {
// Handle failure
} else {
mHelper.consumeAsync(inventory.getPurchase(ITEM_SKU), mConsumeFinishedListener);
}
}
};
public void buyClick(View view) throws IabHelper.IabAsyncInProgressException {
mHelper.launchPurchaseFlow(this, ITEM_SKU, 10001,
mPurchaseFinishedListener, "mypurchasetoken");
}
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener
= new IabHelper.OnIabPurchaseFinishedListener() {
public void onIabPurchaseFinished(IabResult result,
Purchase purchase) throws IabHelper.IabAsyncInProgressException {
if (result.isFailure()) {
// Handle error
return;
} else if (purchase.getSku().equals(ITEM_SKU)) {
btnPurchase.setEnabled(false);
btnPurchase.setBackgroundResource(R.drawable.purchasepressed);
test.setText("IT WORKS!!!");
}
}
};
I was under the impression that after purchase.getSKU().equals(ITEM_SKU)
you put whatever code should be executed if the purchase was successful.
As you can see here, if the purchase is successful, my purchase button should be disabled and change its background image. Also I added a test text label to see if the error was somewhere else in my code.
When I run the code on my phone, I get the purchase dialog and the success, but the button and text don't change.
Please help.
I have a running version with String ITEM_SKU = "android.test.purchased"; So I can buy a (fake)product.
Now I realized that this is a consumable product. But I need a non consumable. If u use my in app purchase it is a premium upgrade.
1) What do I have to change that the users buy a non consumable product?
2) A second thing is that I want to check, if anybody already bought the premium product. Surly he/she should pay only once. How can I do this?
I searched a lot in boards or at the official Google API. There is a sample "Trivial Drive" from Google too, where I could find the solutions for my problem. But I didn't find the right code.
Here are some snippets of my code:
//a button click call this method
public void buyClick() {
mHelper.launchPurchaseFlow(this, ITEM_SKU, 10001,mPurchaseFinishedListener);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
if (!mHelper.handleActivityResult(requestCode, resultCode, data)) {
super.onActivityResult(requestCode, resultCode, data);
}
}
public void consumeItem() {
System.out.println("counsumeItem wurde aufgerufen");
mHelper.queryInventoryAsync(mReceivedInventoryListener);
}
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
#Override
public void onIabPurchaseFinished(IabResult result, Purchase info) {
if (result.isFailure()) {
return;
}
else if (info.getSku().equals(ITEM_SKU)) {
consumeItem();
buyButton.setEnabled(false);
}
}
};
IabHelper.OnConsumeFinishedListener mConsumeFinishedListener = new IabHelper.OnConsumeFinishedListener() {
public void onConsumeFinished(Purchase purchase, IabResult result) {
if (result.isSuccess()) {
clickButton.setEnabled(true); //hier den Datenbankzugriff reinmachen
} else {
System.out.println("Handle error"); // handle error
}
}
};
IabHelper.QueryInventoryFinishedListener mReceivedInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
if (result.isFailure()) {
// Handle failure
System.out.println("FAILURE");
} else {
mHelper.consumeAsync(inventory.getPurchase(ITEM_SKU), mConsumeFinishedListener);
}
}
};
If u need more code or infos, please give me a sign.
I'm trying to implment in app puchase/billing in my app so when the user buys the item i remove the ads. I have and example code that is working with SKU = "android.test.purchased". Now my question is how can I link the app to my items - I have uploaded new apk with billing enabled, created and published the item one hour ago, but when I try to buy the item I get this:
here is my code:
public class RemoveAds extends AthanBaseActivity implements OnClickListener {
private static final String TAG = "inappbilling";
IabHelper mHelper;
//ID from playstore 16xxxx15_removeads.
//android.test.purchased
static final String ITEM_SKU = "com.myapppackage.16xxxx15_removeads.";
#Override
protected void onCreate(Bundle arg0) {
super.onCreate(arg0);
setContentView(R.layout.remove_ads);
findViewById( R.id.remove_ads_).setOnClickListener(this);
setupInAppPurchase();
}
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);
}
}
};
#Override
public void onDestroy() {
super.onDestroy();
if (mHelper != null)
mHelper.dispose();
mHelper = null;
}
IabHelper.OnConsumeFinishedListener mConsumeFinishedListener = new IabHelper.OnConsumeFinishedListener() {
public void onConsumeFinished(Purchase purchase, IabResult result) {
if (result.isSuccess()) {
Toast.makeText(RemoveAds.this, "SUCCESS", Toast.LENGTH_LONG)
.show();
} else {
Toast.makeText(RemoveAds.this, "ERROR purchase",
Toast.LENGTH_LONG).show();
// handle error
}
}
};
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);
}
}
};
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (!mHelper.handleActivityResult(requestCode, resultCode, data)) {
super.onActivityResult(requestCode, resultCode, data);
}
}
private void setupInAppPurchase() {
String base64EncodedPublicKey = "MIIBIjANBgkqhkcccxxxxxdomr somelongstringdfsdfsdfsfsdofksdofkdsMXz0R4EJuw7YZkQ8jMPemymSbQGtLllH+fu85hfQIDAQAB";
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");
}
}
});
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.remove_ads_:
mHelper.launchPurchaseFlow(this, ITEM_SKU, 10001,
mPurchaseFinishedListener, "mypurchasetoken");
break;
}
}
}
You cannot make purchases if the primary account on your real android device is same as your developer account.
I downloaded the sample app
Got my key from the developer console
Put the proper permissions in my manifest
Nothing helps: I got always product not found...
Thanx - Ralf
here is the code, Java, Android Studio
// Does the user have the professional upgrade? should be an In-App product
private static Boolean _PROFESSIONAL = false;
// Debug tag, for logging
private static final String TAG_BILLING = "BillingService";
// (arbitrary) request code for the purchase flow
static final int RC_REQUEST = 10001; // 10002 does not help either...
// The helper object
IabHelper mHelper = null;
static final String SKU_PROFESSIONAL = "com...";
private String base64EncodedPublicKey = "KSRWbpF........... from Google play Developer Console
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
// Create the helper, passing it our context and the public key to verify signatures with
mHelper = new IabHelper(this, base64EncodedPublicKey);
// enable debug logging (for a production application, you should set this to false).
mHelper.enableDebugLogging(true);
// Start setup. This is asynchronous and the specified listener
// will be called once setup completes.
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
#Override
public void onIabSetupFinished(IabResult result) {
if (!result.isSuccess()) {
// Oh no, there was a problem.
return;
}
// Have we been disposed of in the meantime? If so, quit.
if (mHelper == null) return;
// IAB is fully set up. Now, let's get an inventory of stuff we own.
mHelper.queryInventoryAsync(true, null, mGotInventoryListener);
}
});
}
IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
Log.d(TAG_BILLING, "Query inventory finished.");
// Have we been disposed of in the meantime? If so, quit.
if (mHelper == null) return;
// Is it a failure?
if (result.isFailure()) {
complain("Failed to query inventory: " + result);
return;
}
// Do we have the premium upgrade?
Purchase premiumPurchase = inventory.getPurchase(SKU_PROFESSIONAL);
_PROFESSIONAL = (premiumPurchase != null && verifyDeveloperPayload(premiumPurchase));
}
};
// User clicked the menu upgrade professional
private void Upgrade() {
String payload = sMyPurchaseToken;
// tested, but no help
// define IabHelper.flagEndAsync() as public, and add iabHelper.flagEndAsync() before iabHelper.launchPurchaseFlow(...)
// mHelper.flagEndAsync();
// could be tested: this, "android.test.purchased", 10002
/////////// here the program shows the Google Play message that the programm does not exist... or is not configured for payment...
mHelper.launchPurchaseFlow(MyActivity.this, SKU_PROFESSIONAL, RC_REQUEST, mPurchaseFinishedListener, payload);
//mHelper.launchPurchaseFlow(this, "android.test.purchased", 10002, is ok
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.d(TAG_BILLING, "onActivityResult(" + requestCode + "," + resultCode + "," + data);
if (mHelper == null) return;
// Pass on the activity result to the helper for handling
if (!mHelper.handleActivityResult(requestCode, resultCode, data)) {
}
else {
}
}
boolean verifyDeveloperPayload(Purchase p) {
String payload = p.getDeveloperPayload();
return true;
}
// Callback for when a purchase is finished
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
// if we were disposed of in the meantime, quit.
if (mHelper == null) return;
if (result.isFailure()) {
complain("Error purchasing: " + result);
setWaitScreen(false);
return;
}
if (!verifyDeveloperPayload(purchase)) {
complain("Error purchasing. Authenticity verification failed.");
setWaitScreen(false);
return;
}
if (purchase.getSku().equals(SKU_PROFESSIONAL)) {
_PROFESSIONAL = true;
}
}
};
// Called when consumption is complete
IabHelper.OnConsumeFinishedListener mConsumeFinishedListener = new IabHelper.OnConsumeFinishedListener() {
public void onConsumeFinished(Purchase purchase, IabResult result) {
Log.d(TAG_BILLING, "Consumption finished. Purchase: " + purchase + ", result: " + result);
// if we were disposed of in the meantime, quit.
if (mHelper == null) return;
if (result.isSuccess()) {
}
else {
complain("Error while consuming: " + result);
}
}
};