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();
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 using API 3 for in app feature in my app.Currently for test purpose i am using test item code
android.test.purchased
Everything works fine i am able to buy product.But if i click "Purchase" button again, it says"already purchased" and need 30 minutes to let user buy again.Then i tried to consume this product using the following code but its ends up inside QueryInventoryFinishedListener's if(result.isFailure) condition.Following is my code for consuming
public void consumeItem() {
mHelper.queryInventoryAsync(mReceivedInventoryListener);
}
IabHelper.QueryInventoryFinishedListener mReceivedInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result,
Inventory inventory) {
if (result.isFailure()) {
// Handle failure
Log.i("Ajji", "Failed in Query Inventory Finished Listener");
} 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);
Log.i("Ajji", "Item Consumed Successfully");
rowPayment.setClickable(true);
} else {
// handle error
Log.i("Ajji", "Not Consumed");
}
}
};
I call this method for consuming item, Further i am using Trivial Drivesample project of google to make calls
I got the solution thank you.I needed to edit the security.java file from Trivial drive Project .I changed "return false" line in the verifyPurchase method to "return true" (dont forget its only for debug mode) .Now I can consume test in app successfully .Following is the edit of Verify Purchase method
public static boolean verifyPurchase(String base64PublicKey,
String signedData, String signature) {
if (TextUtils.isEmpty(signedData) || TextUtils.isEmpty(base64PublicKey)
|| TextUtils.isEmpty(signature)) {
Log.e(TAG, "Purchase verification failed: missing data.");
if (BuildConfig.DEBUG) {
return true;
}
return false;
}
PublicKey key = Security.generatePublicKey(base64PublicKey);
return Security.verify(key, signedData, signature);
}
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.
I am trying to set up in-app-billing and test using a static product ID in Google Play.
Am following developer tutorial here.
When the launhPurcahseFlow method is called on the labHelper object I get the exception:
java.lang.IllegalStateException: IAB helper is not set up. Can't
perform operation: launchPurchaseFlow at
com.android.vending.billing.IabHelper.checkSetupDone(IabHelper.java:782)
Have been searching for hours and can't find a solution that works.
Any input appreciated.
My code is:
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
// compute your public key and store it in base64EncodedPublicKey
mHelper = new IabHelper(this, base64EncodedPublicKey);
// enable debug logging (for a production application, you should set this to false).
mHelper.enableDebugLogging(true);
//perform service binding to Google Bill ser and return ny errors with IabResult object and listener
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
public void onIabSetupFinished(IabResult result) {
Log.d(TAG, "Setup finished.");
if (!result.isSuccess()) {
// Oh noes, there was a problem.
alert("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);
}
});
//ILLEGALSTAEEXCEPTION THROWN HERE
mHelper.launchPurchaseFlow(this, testProduct, RC_REQUEST,
new IabHelper.OnIabPurchaseFinishedListener() {
public void onIabPurchaseFinished(IabResult result, Purchase purchase)
{
if (result.isFailure()) {
Log.d(TAG, "Error purchasing: " + result);
return;
}
else if (purchase.getSku().equals(testProduct)) {
// give user access to premium content and update the UI
//set the purchaesd booean to true
//when purcajsed add this code
editor.putBoolean("purchased", true);
editor.commit();
Toast.makeText(getApplicationContext(), "ADD FREE VERSION PURCAHSED!!!" +
" Details OrderID: "+purchase.getOrderId() +" Payload ID: "+purchase.mDeveloperPayload, Toast.LENGTH_LONG).show();
Log.d("CONNECT TO GOOGLE BILL", "ITEM PURCAHSED! : "+purchased);
}
}
}, "diveAppPurchase");
}//onCreate
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.d(TAG, "onActivityResult(" + requestCode + "," + resultCode + "," + data);
if (mHelper == null) return;
// Pass on the activity result to the helper for handling
if (!mHelper.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(TAG, "onActivityResult handled by IABUtil.");
}
}
This be useful to those like me, who are dealing with in app purchasing first time.
The set up call is asynchronous, therefore this must complete before the launchPurchaseFlow is called. So i disabled a 'Purchase' button to make the launchPurchaseFlow call, which is enabled once the set up call is done. Works fine:
Set up call
//perform service binding to Google Bill ser and return ny errors with IabResult object and listener
mHelper.startSetup(...)
if successfully then enable button and call mHelper.launchPurchaseFlow(...) method
Also, when using the test product id provided by google you may note a signature exception is thrown during the launchPurchaseFlow with a subsequent result failure although the transaction is successful , this is apparently a known bug that google are aware of
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.