I just wrote a test application to test in app purchases, it's just a test application where you have to press a button and you purchase a "premium" membership that will make that button invisible (this is just a test app)
So after my friend pressed the button he got the payment screen, he paid, but when he got back to the app the button was still there
This is how i start the purchase
// User clicked the "Upgrade to Premium" button.
public void onUpgradeAppButtonClicked(View arg0) {
Log.d(TAG, "Upgrade button clicked; launching purchase flow for upgrade.");
// setWaitScreen(true);
mHelper.launchPurchaseFlow(this, SKU_PREMIUM, RC_REQUEST, mPurchaseFinishedListener);
}
and when the purchase is finished
// 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);
int duration = Toast.LENGTH_SHORT;
if (result.isFailure()) {
// Oh noes!
// complain("Error purchasing: " + result);
// setWaitScreen(false);
Toast.makeText(getBaseContext(), "Failed to purchase", duration).show();
return;
}
Log.d(TAG, "Purchase successful.");
if (purchase.getSku().equals(SKU_PREMIUM)) {
// bought the premium upgrade!
Log.d(TAG, "Purchase is premium upgrade. Congratulating user.");
// alert("Thank you for upgrading to premium!");
mIsPremium = true;
Toast.makeText(getBaseContext(), "You are now premium", duration).show();
Button test = (Button) findViewById(R.id.test);
test.setVisibility(View.INVISIBLE);
// updateUi();
// setWaitScreen(false);
}
}
};
The code was taken from the sample app that was provided by google,i removed the parts i didn't need, maybe i removed something that was needed?
Indeed, you must also copy the onActivityResult method from the example activity into your activity. When you have done this, it should work.
Related
I would like to make an in app purchase in my android app. I use for this the google sample: http://developer.android.com/training/in-app-billing/preparing-iab-app.html#GetSample
I implemented this in my android studio project. In the developer console I set the in app purchase and a gmail address as test account.
on my device (not emulator), I logged in with this test account. I start my app and klick on "Buy Premium" and can finish this process.
now I would like to show a Button (Text "Restore) where the user can restore his in app purchase, IF he / she bought the premium function before.
I have this code:
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
Log.e("-->", "Purchase finished: " + result);
if (mHelper == null) return;
if (result.isFailure()) {
Log.e("-->","Error purchasing: " + result);
return;
}
if (!verifyDeveloperPayload(purchase)) {
Log.e("-->","Error purchasing. Authenticity verification failed.");
return;
}
SharedPreferences prefs = this.getSharedPreferences("xxx", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean("Premium", true);
editor.commit();
Log.e("-->", "Premium: " + prefs.getBoolean("Premium", false));
}
};
If I press on the "buy" button again and I had bought this before, I get this message in log cat:
-->: Purchase finished: IabResult: Unable to buy item (response: 7:Item Already Owned), purchase: null
-->: Error purchasing: IabResult: Unable to buy item (response: 7:Item Already Owned)
My Question is, how can I check if the in app purchase was bought before or not?
mIabHelper.queryInventoryAsync(true, "your_sku", mGotInventoryListener);
// Listener that's called when we finish querying the items and subscriptions we own
IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
Log.d("PAY", "Query inventory finished.");
// Have we been disposed of in the meantime? If so, quit.
if (mIabHelper == null) return;
Purchase purchase = inventory.getPurchase("your_sku");
if (purchase != null) {
//purchased
}
}
I am currently working on in app purchase in my application, when it launches I have always the error code -1003 querying owned items response signature verification failed when I arrive in IabHelper.QueryInventoryFinishedListener method.
I currently uses the example version of Google "Trivial Drive", I guess my signature is correct because I get to buy much when I use android.app.purchassed ...
The key seems correct to me because when I click like to buy a product that tells me that the publisher can not buy the product which is normal in itself (If I put anything I have another error saying the product does not exist). For cons, I have the same error when I put the test product "android.test.purchasse" then I should be able to test with it.
I made a purchase with android.test.purchasse there and I can not reset if you have already succeeded I'm interested.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// load game data
loadData();
String base64EncodedPublicKey = "MY_KEY_BASE64";
PublicKey key = Security.generatePublicKey(base64EncodedPublicKey);
// Create the helper, passing it our context and the public key to verify signatures with
Log.d(TAG, "Creating IAB helper.");
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.
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.
complain("Problem setting up in-app billing: " + result);
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.
Log.d(TAG, "Setup successful. Querying inventory.");
mHelper.queryInventoryAsync(mGotInventoryListener);
}
});
}
// Listener that's called when we finish querying the items and subscriptions we own
IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
Log.d(TAG, "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;
}
Log.d(TAG, "Query inventory was successful.");
/*
* Check for items we own. Notice that for each purchase, we check
* the developer payload to see if it's correct! See
* verifyDeveloperPayload().
*/
if(inventory.hasPurchase(SKU_GAS))
{
Toast.makeText(getApplicationContext(),"PREMIUM",Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(getApplicationContext(),"NOT PREMIUM", Toast.LENGTH_SHORT).show();
}
// Do we have the premium upgrade?
Purchase premiumPurchase = inventory.getPurchase(SKU_PREMIUM);
mIsPremium = (premiumPurchase != null && verifyDeveloperPayload(premiumPurchase));
Log.d(TAG, "User is " + (mIsPremium ? "PREMIUM" : "NOT PREMIUM"));
// Do we have the infinite gas plan?
Purchase infiniteGasPurchase = inventory.getPurchase(SKU_INFINITE_GAS);
mSubscribedToInfiniteGas = (infiniteGasPurchase != null && verifyDeveloperPayload(infiniteGasPurchase));
Log.d(TAG, "User " + (mSubscribedToInfiniteGas ? "HAS" : "DOES NOT HAVE")
+ " infinite gas subscription.");
if (mSubscribedToInfiniteGas) mTank = TANK_MAX;
// Check for gas delivery -- if we own gas, we should fill up the tank immediately
Purchase gasPurchase = inventory.getPurchase(SKU_GAS);
if (gasPurchase != null && verifyDeveloperPayload(gasPurchase)) {
Log.d(TAG, "We have gas. Consuming it.");
mHelper.consumeAsync(inventory.getPurchase(SKU_GAS), mConsumeFinishedListener);
return;
}
updateUi();
setWaitScreen(false);
Log.d(TAG, "Initial inventory query finished; enabling main UI.");
}
};
Have you ever been concerned? I see no way out for this bug help from you will be appreciated.
thank you
You need to create a test account, and put it in the playstore admin page.
For buy i have code
public void onClick(View v)
{
// FIRST CHECK IF THE USER IS ALREADY A SUBSCRIBER.
mHelper.launchPurchaseFlow(SubscribeIntroActivity.this, SUBSCRIBE_SKU, RC_REQUEST, mPurchaseFinishedListener);
}
public void onClick(View v)
{
// FIRST CHECK IF THE USER IS ALREADY A SUBSCRIBER.
mHelper.launchPurchaseFlow(SubscribeIntroActivity.this, SUBSCRIBE_SKU, RC_REQUEST, mPurchaseFinishedListener);
}
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
Log.d(TAG, "Purchase finished: " + result + ", purchase: " + purchase);
// if we were disposed of in the meantime, quit.
if (mHelper == null) return;
if (result.isFailure()) {
Log.d(TAG,"Error purchasing: " + result);
return;
}
if (!verifyDeveloperPayload(purchase)) {
Log.d(TAG,"Error purchasing. Authenticity verification failed.");
return;
}
Log.d(TAG, "Purchase successful.");
if (purchase.getSku().equals(SKU_PREMIUM)) {
// bought the premium upgrade!
Log.d(TAG, "Purchase is premium upgrade. Congratulating user.");
Log.d(TAG,"Thank you for upgrading to premium!");
mIsPremium = true;
isShortVersion=false;
DrawIsShortVersion();
}
}
};
Error in LOG IS
Caused by: java.lang.IllegalStateException: Can't start async operation (launchPurchaseFlow) because another async operation(launchPurchaseFlow) is in progress.
when i click button its open buyer dialog and i can buy without any problem, but if i click button dialog is opened, Push BACK hardware button on device (didnt buy) i see first activity with button BUY, push it for buy again and raise error. May be somebody know about this error? what i do wrong?
... added if (mHelper != null) mHelper.flagEndAsync(); before call launchPurchaseFlow, now no errors, but mHelper.flagEndAsync(); kill previos task ?
Can you post your Logs?
In most cases an error occours when an Async PurcaseFlow is running and yout try to run an other Purcase.
what are you doing in your Purcase Listener?
Edit: you have multiple Coices to make that:
First: create a global boolean -> mTaskIsRunning;
private void doBuyProduct(int id){
if(!mTaskIsRunning){
mHelper.launchPurchaseFlow(SubscribeIntroActivity.this, SUBSCRIBE_SKU, RC_REQUEST, mPurchaseFinishedListener);
mTaskIsRunning=true;
}
}
Then in your Listener:
....
mTaskIsRunning=false;
Or you can disable the Buttons while a Task is Running
Same Procedure :
private void doBuyProduct(int id){
disableBuyButtons();
mHelper.launchPurchaseFlow(SubscribeIntroActivity.this, SUBSCRIBE_SKU, RC_REQUEST, mPurchaseFinishedListener);
}
and in the FinishListener:
enableButtons();
I am working on an app which has IAB, and that when the purchase is finished through the OnConsumeFinishedListener, it will save through SharePreference that the user has paid for the additional function (the function wont be depleted).
Users are able to buy again for the same product.
Code:
// Called when consumption is complete
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())
{
Toast.makeText(InAppBillingActivity.this, "Thank you!!", Toast.LENGTH_SHORT).show();
if ((purchase.getSku().equals(ITEM_SKU10))) {countQ(10);}
buy10Button.setEnabled(true);
}
else
{
// handle error
}
Log.d(TAG, "End consumption flow.");
}
};
public void countQ(int Q)
{
SharedPreferences settings = this.getSharedPreferences("MyApp",0);
if (Q==10)
{
SharedPreferences settings1 = this.getSharedPreferences("MyApp",0);
SharedPreferences.Editor e1 = settings1.edit();
e1.putBoolean("userpaid", true);
e1.commit();
}
Question:
I see that users are able to cancel their purchase. In that way, saving through Sharepreference that the user has paid for additional functions will have loophole? The user can first purchase to make the sharepreference to become true and then cancel the purchase order?
In that way, how can be the process be improved? Checking the inventory seem not possible as the additional function is consumed in the IAB process.
It seems a little odd that you have a non-consumable item that can be purchased multiple times. The idea is generally that an item that can be purchased multiple times is consumable.
To answer your question IAB purchases cannot be cancelled like an app purchase can, the 15 minute refund window is removed and the purchase is non-refundable unless they contact you and you decide to issue a refund manually.
I hope someone can help me. I need to notify user after he successfully purchased an item via in-app billing service. [...deleted confusing text...]
EDIT
TO be precise. From the demo Google project, I see that they use onRequestPurchaseResponse to catch RESULT_OK code. Inside of that method, I added the Toast and initiated the test purchase via android.test.purchased item. I got the Market's windows and message "Authorizing purchase". After the process completed, my Toast appeared.
#Override
public void onRequestPurchaseResponse(BillingService.RequestPurchase request,
Consts.ResponseCode responseCode) {
if (Consts.DEBUG) {
Log.d(TAG, request.mProductId + ": " + responseCode);
}
if (responseCode == Consts.ResponseCode.RESULT_OK) {
if (Consts.DEBUG) {
Log.i(TAG, "purchase was successfully sent to server");
}
showToast("purchase was successfully sent to server");//<- MY TOAST!
logProductActivity(request.mProductId, "sending purchase request");
} else if (responseCode == Consts.ResponseCode.RESULT_USER_CANCELED) {
if (Consts.DEBUG) {
Log.i(TAG, "user canceled purchase");
}
logProductActivity(request.mProductId, "dismissed purchase dialog");
} else {
if (Consts.DEBUG) {
Log.i(TAG, "purchase failed");
}
logProductActivity(request.mProductId, "request purchase returned " + responseCode);
}
}
My question is, is this the right place to place the message on successful purchase?
It's fine to put a message there, but that is not where the purchase gets completed. As you can see in the comments, it says that the purchase was successfully sent to the server. It does not mean that the purchase actually went through. This is called BEFORE your app is taken to Google Play to give the user the option to make the purchase. The user can still back out. If, however, the user presses BUY, the app restarts and the following code gets called.
#Override
public void onPurchaseStateChange(PurchaseState purchaseState, String itemId, int quantity, long purchaseTime, String developerPayload) {
if (purchaseState == PurchaseState.PURCHASED) {
// PUT YOUR CONFIRMATION MESSAGE HERE
}
}
Just to confirm that this is the right place to do all after-successful-purchase actions.