Android In app Subscription not working - android

i am developing a app in android using in app subscription. i am trying to query my purchase items using IabHelper.QueryInventoryFinishedListener. but it always coming as a failure results. IabResult returns failure. i added in app products in developer console. can any one help me on this?
here is some of my code,
bindService(new Intent("com.android.vending.billing.InAppBillingService.BIND"),
mServiceConn, Context.BIND_AUTO_CREATE);
String base64EncodedPublicKey = "my key";
mHelper = new IabHelper(this, base64EncodedPublicKey);
mHelper.enableDebugLogging(true);
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
public void onIabSetupFinished(IabResult result) {
if (!result.isSuccess()) {
System.out.println("Not Success");
Log.d("In APP Billing", "Problem setting up In-app Billing: " + result);
return;
} else {
System.out.println("Success");
Log.d(" In APP Billing", "Setting up In-app Billing Success: " + result);
}
List<String> additionalSkuList = new ArrayList<String>();
additionalSkuList.add(SKU_ID);
mHelper.queryInventoryAsync(true, additionalSkuList,
mQueryFinishedListener);
}
});
IabHelper.QueryInventoryFinishedListener mQueryFinishedListener = new IabHelper.QueryInventoryFinishedListener() {
#Override
public void onQueryInventoryFinished(IabResult result, Inventory inv) {
// TODO Auto-generated method stub
if (result.isFailure()) {
// handle error
System.out.println("mQueryFinishedListener is Failure"); // i am always getting this
return;
}
System.out.println("mQueryFinishedListener is Success");
Boolean hasPur = inv.hasPurchase(SKU_ID);
if (hasPur) {
System.out.println("Query - - subscribed ");
isSubscribed = true;
} else {
System.out.println("Query - not subscribed ");
isSubscribed = false;
}
System.out.println("Purchase panic:"+inv.getPurchase(SKU_ID));
}
};
any idea why its not working? thanks in advance.

To work with in app subscription i think you will gave to call "launchSubscriptionPurchaseFlow()" method on IabHelper instance you create.
mHelper.launchSubscriptionPurchaseFlow(Activity act, String sku, int requestCode,
OnIabPurchaseFinishedListener listener, String extraData);
OR
mHelper.launchPurchaseFlow(Activity act, String sku, String itemType, int requestCode,
OnIabPurchaseFinishedListener listener, String extraData);
Where itemType = IabHelper.ITEM_TYPE_SUBS

Related

android in app purchase - Articel already owned issue

I have just implemented the in app billing functionality in my app.
I only have one product to unlock all premium features.
The purchase itself works, but after the purchase flow, my code obviously isn't able to recognise the success of the purchase, because there appears a complain window right after purchase saying "Articel already owned". So somehow the purchase flow is not recogniced to be successful. After i restart the app, the pro features are unlocked, because the querying of the inventory says, the pro features have been bought.
I am out of ideas, so here is my code:
// SKUs for our products: the premium upgrade (non-consumable)
String SKU_PREMIUM;
// (arbitrary) request code for the purchase flow
final int RC_REQUEST = 10001;
// The helper object
IabHelper mHelper;
// Provides purchase notification while this app is running
public IabBroadcastReceiver mBroadcastReceiver;
IabHelper.QueryInventoryFinishedListener mGotInventoryListener;
AppCompatActivity activity;
private String payload;
public InAppBillingHelper(AppCompatActivity context, final IabBroadcastReceiver.IabBroadcastListener contextBroadcastListener, String base64EncodedPublicKey,String skuPremium, boolean debug){
//String base64EncodedPublicKey = "VALENTIN_HERR_SCHAFKOPF_RECHENHELFER";
this.activity = context;
SKU_PREMIUM = skuPremium;
// Create the helper, passing it our context and the public key to verify signatures with
Log.d(TAG, "Creating IAB helper.");
mHelper = new IabHelper(context, base64EncodedPublicKey);
// enable debug logging (for a production application, you should set this to false).
mHelper.enableDebugLogging(debug);
// Start setup. This is asynchronous and the specified listener
// will be called once setup completes.
Log.d(TAG, "Starting setup.");
// Listener that's called when we finish querying the items and subscriptions we own
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("Fehler bei der Bestimmung der App-Lizenz: " + result);
// TODO analyse results and output it to the user
return;
}
Log.d(TAG, "Query inventory was successful.");
// 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"));
}
updateUi();
setWaitScreen(false);
Log.d(TAG, "Initial inventory query finished; enabling main UI.");
}
};
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;
mBroadcastReceiver = new IabBroadcastReceiver(contextBroadcastListener);
IntentFilter broadcastFilter = new IntentFilter(IabBroadcastReceiver.ACTION);
try {
activity.registerReceiver(mBroadcastReceiver, broadcastFilter);
}catch (Exception e)
{}
// IAB is fully set up. Now, let's get an inventory of stuff we own.
Log.d(TAG, "Setup successful. Querying inventory.");
try {
mHelper.queryInventoryAsync(mGotInventoryListener);
} catch (IabHelper.IabAsyncInProgressException e) {
complain("Error querying inventory. Another async operation in progress.");
}
}
});
}
public void receivedBroadcast() {
// Received a broadcast notification that the inventory of items has changed
Log.d(TAG, "Received broadcast notification. Querying inventory.");
try {
mHelper.queryInventoryAsync(mGotInventoryListener);
} catch (IabHelper.IabAsyncInProgressException e) {
complain("Error querying inventory. Another async operation in progress.");
}
}
// User clicked the "Upgrade to Premium".
public void handlePremiumPurchase() {
Log.d(TAG, "Upgrade button clicked; launching purchase flow for upgrade.");
setWaitScreen(true);
payload = "";
try {
mHelper.launchPurchaseFlow(activity, SKU_PREMIUM, RC_REQUEST,
mPurchaseFinishedListener, payload);
} catch (IabHelper.IabAsyncInProgressException e) {
complain("Error launching purchase flow. Another async operation in progress.");
setWaitScreen(false);
}catch (NullPointerException e)
{
complain("Fehler beim Kaufversuch. Stelle sicher, dass mit einem Google Konto im PlayStore angemeldet bist und eine stabile Internetverbindung besteht." +
"Versuche es nach noch einmal." +
"");
setWaitScreen(false);
}
}
public boolean isPremium() {
return mIsPremium;
}
public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
Log.d(TAG, "onActivityResult(" + requestCode + "," + resultCode + "," + data);
if (mHelper == null) return false;
// Pass on the activity result to the helper for handling
if (!mHelper.handleActivityResult(requestCode, resultCode, data)) {
// Todo handle
}
else {
Log.d(TAG, "onActivityResult handled by IABUtil.");
}
return true;
}
/** Verifies the developer payload of a purchase. */
boolean verifyDeveloperPayload(Purchase p) {
String payload = p.getDeveloperPayload();
// Todo payload string verification
return true;//payload.equals(this.payload);
}
// 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 we were disposed of in the meantime, quit.
if (mHelper == null) return;
if (result.isFailure()) {
if(result.getResponse() == IabHelper.BILLING_RESPONSE_RESULT_ITEM_ALREADY_OWNED)
{
mIsPremium = true;
updateUi();
//complain("Du besitzt bereits das Premium Paket auf einem deiner angemeldeten Google Konten.");
}
else {
complain("Fehler beim Kauf: " + result);
}
setWaitScreen(false);
return;
}
if (!verifyDeveloperPayload(purchase)) {
complain("Error purchasing. Authenticity verification failed.");
setWaitScreen(false);
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("Danke für das Premium Upgrade! Ich wünsche dir weiterhin viel Spaß bei der Nutzung!");
mIsPremium = true;
updateUi();
setWaitScreen(false);
}
}
};
Btw: The code is a modified version of the **trivial drive* example.
Thanks in advance!
Although it's not the cleanest solution, just query the inventory again if you have a "already owned error". Then update the UI only according to the inventory query result
Thanks #DerAdler . I implemented it just the way you said and it worked.

Android Studio In-App purchases configuration

I am setting up in-app purchases for my application and am stuck at a particular point. The code I have used so far is as follows:
IabHelper mHelper;
protected void onCreate(Bundle savedInstanceState) {
mHelper = new IabHelper(this, base64EncodedPublicKey); //base64EncodedPublicKey is a string declared earlier and not reposted here.
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
public void onIabSetupFinished(IabResult result) {
if (!result.isSuccess()) {
Log.d(TAG, "Failed: " + result);
Toast.makeText(MainActivity.this, "IAB setup Failed", Toast.LENGTH_SHORT).show();
} else {
Log.d(TAG, "Worked");
Toast.makeText(MainActivity.this, "IAB setup Successful", Toast.LENGTH_SHORT).show();
final List additionalSkuList = new ArrayList();
additionalSkuList.add("remove_ad");
mHelper.queryInventoryAsync(true, additionalSkuList, mQueryFinishedListener);
}
}
});
At this point, everything seems to be going well. The "Worked" section of code triggers and is processed successfully. The code sends a request at this point to mHelper.queryInventoryAsync, which is configured as follows, outside of onCreate():
IabHelper.QueryInventoryFinishedListener mQueryFinishedListener = new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result, Inventory inventory)
{
if (result.isFailure()) {
Toast.makeText(MainActivity.this, "Query Listener Error", Toast.LENGTH_SHORT).show();
return;
}
String removalPrice =
inventory.getSkuDetails("remove_ad").getPrice();
Toast.makeText(MainActivity.this, removalPrice, Toast.LENGTH_SHORT).show();
// update the UI
}
};
At this point, Toast triggers to say "Query Listener Error", indicating that if (result.isFailure()) has triggered. This is where I am stuck. It is not giving me any clues as to why this might be happening.
From the Developer Console, these are the details of my In-App product:
Name/ID: Remove Ad (remove_ad)
Type: Managed product
Last Update: Jul 15, 2015
Status: Active
What have I done incorrectly? The only thing I am not too sure about is how I have declared and used my arrayList, and where I have submitted a string value to .getPrice();
mHelper.launchPurchaseFlow(Activity.this, SKU, 11,
mPurchaseFinishedListener, "mypurchasetoken");
Call this method and implement listner like below in that you will get result
public IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
public void onIabPurchaseFinished(IabResult result,
Purchase purchase)
{
if (result.isFailure()) {
}
return;
}
};
Refer the below link:
http://www.techotopia.com/index.php/An_Android_Studio_Google_Play_In-app_Billing_Tutorial

SKU bought with IAP doesn't show up on as purchased on a second device owned by the same user

I get this complaint every so often that a user buys my premium features with IAP and that it works fine on the device they bought but their other device won't get the features, I ask them to reboot the other device and that usually fixes it. So the other day I tried to see if I could do something about this so I purchased on one of my devices (test account) and then I went to the other, killed my app to make sure it was starting from zero, and then stepped the code. The query of purchases was actually returning no purchases. It did not tell me about purchases until I tried to buy premium from that device. Trying to buy premium from that device didn't create a dialog or anything, it just returned as if nothing had happened but after that the device had that purchase on its inventory.
Here are the methods I have, I am using the IABHelper from Google's example and I think I updated it just a month ago.
public void createIABHelper(final Context ac) {
mHelper = new IabHelper(ac, myid);
try {
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
public void onIabSetupFinished(IabResult result) {
if (!result.isSuccess()) {
// Oh noes, there was a problem.
Log.d(TAG, "Problem setting up In-app Billing: " + result);
} else {
iabSetup = true;
//queryIAB(ac);
queryIABPurchases(ac);
}
}
});
} catch (Throwable e) {
final String desc = "Error starting IABHelper";
Log.w(TAG, desc, e);
}
}
public void queryIAB(final Context ctx) {
List<String> additionalSkuList = new ArrayList<String>();
additionalSkuList.add(Constants.PREMIUM_UPGRADE);
IabHelper.QueryInventoryFinishedListener
mQueryFinishedListener = new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
if (result.isFailure()) {
// handle error
return;
} else {
Purchase p = inventory.getPurchase(Constants.PREMIUM_UPGRADE);
if (p != null) {
setHasPremiumPref(p.getPurchaseState() == 0);
} else {
setHasPremiumPref(false);
}
}
// inventory.hasDetails(PREMIUM_UPGRADE);
// update the UI
}
};
mHelper.queryInventoryAsync(true, additionalSkuList,
mQueryFinishedListener);
}
#Override
public void purchaseIAB(final Activity ac) {
if (iabSetup) {
try {
final String finalPayload = ....;
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener
= 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(Constants.PREMIUM_UPGRADE)) {
Log.w(TAG, "Purchased " + purchase.getPurchaseState());
if (purchase.getDeveloperPayload().equals(finalPayload) && purchase.getPurchaseState() == 0) {
setHasPremiumPref(true);
} else {
Log.w(TAG, "Something went wrong verifying purchase.");
setHasPremiumPref(false);
}
}
}
};
mHelper.launchPurchaseFlow(ac, Constants.PREMIUM_UPGRADE, 10001,
mPurchaseFinishedListener, finalPayload);
} catch (Throwable ex) {
final String msg = "Error starting in-app purchase";
Log.w(TAG, msg, ex);
}
} else {
Log.w(TAG, "IAB not setup.");
}
}
public void queryIABPurchases(Context ctx) {
if (iabSetup) {
IabHelper.QueryInventoryFinishedListener mGotInventoryListener
= new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result,
Inventory inventory) {
if (result.isFailure()) {
// handle error here
} else {
// does the user have the premium upgrade?
Purchase p = inventory.getPurchase(Constants.PREMIUM_UPGRADE);
if (p != null) {
setHasPremiumPref(p.getPurchaseState() == 0);
} else {
setHasPremiumPref(false);
}
// update UI accordingly
}
}
};
List<String> additionalSkuList = new ArrayList<String>();
additionalSkuList.add(Constants.PREMIUM_UPGRADE);
mHelper.queryInventoryAsync(false, additionalSkuList, mGotInventoryListener);
} else {
Log.w(TAG, "IAB not setup.");
}
}
Anyways, basically I use queryIABPurchases but p is always null on that second device. Is this an issue with test accounts or maybe something to do with time, do I maybe need to wait a few hours before testing on the second device?
Thanks.

In-App purchase crashing after payment

I've wrote an in app purchase test app to learn how to implement it in an application i've made.
I adapted the code from the TrivialDrive sample provided by google.
But it doesn't work, after my friend makes the payment the app crashes.
The code looks like this
public class MainActivity extends Activity {
String TAG = "AppPurchaseTest";
IabHelper mHelper;
boolean mIsPremium = false;
static final String SKU_PREMIUM = "premium";
static final int RC_REQUEST = 10001;
// 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);
}
//this is not working
// 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(), "Fail :(", 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(), "Successo: adesso sei premium", duration).show();
Button test = (Button) findViewById(R.id.test);
test.setVisibility(View.INVISIBLE);
// updateUi();
// setWaitScreen(false);
}
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String base64EncodedPublicKey = null;
// compute your public key and store it in base64EncodedPublicKey
mHelper = new IabHelper(this, base64EncodedPublicKey);
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
public void onIabSetupFinished(IabResult result) {
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!
}
});
}
#Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
if (mHelper != null) {
Log.d(TAG, "mHelper doesn't = null ");
mHelper.dispose();
mHelper = null;
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.d(TAG, "onActivityResult(" + requestCode + "," + resultCode + "," + data);
// 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.");
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}
Can you spot something wrong? Something i forgot?
Also this tutorial https://developer.android.com/google/play/billing/billing_integrate.html
looks much simpler, but i don't understand how to implement it, is there a sample or something from which i can see how it's implemented? I just need a simple upgrade to premium purchase
It's very hard to make it work since i can't test it personally and everytime i test it i lose money :(
Took a long time to figure out on my project but you have to understand that your mPurchaseFinishedListener is called on a non rendering thread and before your application onResume() is called (just check the IabHelper code.
So if you try to do any rendering there it CAN crash because the rendering context is not restored yet.
In your case it is likely that:
Toast.makeText(getBaseContext(), "Successo: adesso sei premium", duration).show();
will crash, the same goes for
Button test = (Button) findViewById(R.id.test);
if you check the trivia example the textButton visibility is set to true, but the button itself is a class property that is assigned in the onCreate() method.
Let me know if this helps..
Per TrivialDrive You also need (this will fix it):
// We're being destroyed. It's important to dispose of the helper here!
#Override
public void onDestroy() {
super.onDestroy();
// very important:
if (mBroadcastReceiver != null) {
unregisterReceiver(mBroadcastReceiver);
}
// very important:
Log.d(TAG, "Destroying helper.");
if (mHelper != null) {
mHelper.disposeWhenFinished();
mHelper = null;
}
}

Android - testing billing purchase with real item id gives error: Item Not Found

I have a situation where I tested on a test device with the item id: android.test.purchased
And things worked. Then once I changed that string with the real item id, I started getting Item Not Found error when I pressed the buy button.
Also the buy item is a subscription and not a 1-time purchase. Does that make a difference?
I was not sure which part of the code may be at fault, or what may be missing so here is the class for this:
public class SubscribeIntroActivity extends BaseActivity
{
IabHelper mHelper;
// Does the user have the premium upgrade?
boolean isSubscriber = false;
// (arbitrary) request code for the purchase flow
static final int RC_REQUEST = 105;
// Subscribe SKU
static final String SUBSCRIBE_SKU = "11";
// Subscribe SKU
static final String TAG = "BILLING";
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.subscribe_intro);
String base64EncodedPublicKey = "my_real_key";
// Create the helper, passing it our context and the public key to verify signatures with
mHelper = new IabHelper(this, base64EncodedPublicKey);
mHelper.enableDebugLogging(true);
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
public void onIabSetupFinished(IabResult result)
{
if (!result.isSuccess())
{
// Oh noes, there was a problem.
//complain("Problem setting up in-app billing: " + result);
return;
}
// Hooray, IAB is fully set up. Now, let's get an inventory of stuff we own.
mHelper.queryInventoryAsync(mGotInventoryListener);
}
});
// Listener that's called when we finish querying the items we own
IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
if (result.isFailure())
{
//complain("Failed to query inventory: " + result);
return;
}
Log.d(TAG, "Query inventory was successful.");
// Do we have the premium upgrade?
isSubscriber = inventory.hasPurchase(SUBSCRIBE_SKU);
Log.d(TAG, "User is " + (isSubscriber ? "SUBSCRIBER" : "NOT SUBSCRIBER"));
// Check for gas delivery -- if we own gas, we should fill up the tank immediately
if (inventory.hasPurchase( SUBSCRIBE_SKU ))
{
Log.d(TAG, "HAS SUBSCRIPTION");
return;
}
//updateUi();
// TODO: TELL USER HE IS SUBSCIBED AND TAKE THEM TO THE QUESTION
//setWaitScreen(false);
Log.d(TAG, "Initial inventory query finished; enabling main UI.");
}
};
Button subscribe = (Button)findViewById(R.id.subscribe);
subscribe.setOnClickListener(new Button.OnClickListener()
{
public void onClick(View v)
{
// FIRST CHECK IF THE USER IS ALREADY A SUBSCRIBER.
mHelper.launchPurchaseFlow(SubscribeIntroActivity.this, SUBSCRIBE_SKU, RC_REQUEST, mPurchaseFinishedListener);
// Send me an email that a comment was submitted on a question.
//sendEmail("My Questions -> Add Question", "Someone clicked on add-question from my questions. User id: " + user_id );
//Intent myIntent = new Intent(MotivationActivity.this, WePromoteActivity.class);
//MotivationActivity.this.startActivity(myIntent);
}
});
// mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
// public void onIabSetupFinished(IabResult result)
// {
// if (!result.isSuccess())
// {
// // Oh noes, there was a problem.
//
// Log.d("INAPP BILLING", "Problem setting up In-app Billing: " + result);
// }
//
// // Hooray, IAB is fully set up!
//
//
// // First arg is whether product details should be retrieved
// // The List argument consists of one or more product IDs (also called SKUs) for the products that you want to query.
// // the QueryInventoryFinishedListener argument specifies a listener is
// // notified when the query operation has completed
// // and handles the query response.
//// mHelper.queryInventoryAsync(false, new ArrayList ( ).add("1"),
//// mQueryFinishedListener);
//
// //mHelper.queryInventoryAsync(mGotInventoryListener);
//
//
//// mHelper.launchPurchaseFlow(SubscribeIntroActivity.this, "11" , 105, mPurchaseFinishedListener, "" );
// }
// });
}
IabHelper.QueryInventoryFinishedListener
mQueryFinishedListener = new IabHelper.QueryInventoryFinishedListener()
{
public void onQueryInventoryFinished(IabResult result, Inventory inventory)
{
if (result.isFailure()) {
// handle error
return;
}
String applePrice =
inventory.getSkuDetails("1").getPrice();
String bananaPrice =
inventory.getSkuDetails(SUBSCRIBE_SKU).getPrice();
}
// update the UI
};
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener
= new IabHelper.OnIabPurchaseFinishedListener() {
public void onIabPurchaseFinished(IabResult result, Purchase purchase)
{
if (result.isFailure())
{
Log.d("ERROR", "Error purchasing: " + result);
return;
}
else if (purchase.getSku().equals("1"))
{
// consume the gas and update the UI
}
else if (purchase.getSku().equals(SUBSCRIBE_SKU))
{
// give user access to premium content and update the UI
Log.d(TAG, "PURCHASED: " + result);
}
}
};
IabHelper.QueryInventoryFinishedListener mGotInventoryListener
= new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result,
Inventory inventory) {
if (result.isFailure()) {
// handle error here
}
else
{
// does the user have the premium upgrade?
isSubscriber = inventory.hasPurchase(SUBSCRIBE_SKU);
// update UI accordingly
}
}
};
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.d(TAG, "onActivityResult(" + requestCode + "," + resultCode + "," + data);
// 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.");
}
}
#Override
public void onDestroy()
{
super.onDestroy();
if (mHelper != null) mHelper.dispose();
mHelper = null;
}
}
Since this is a subscription I believe you must replace this line:
mHelper.launchPurchaseFlow(SubscribeIntroActivity.this, SUBSCRIBE_SKU, RC_REQUEST, mPurchaseFinishedListener);
with this one:
mHelper.launchSubscriptionPurchaseFlow(SubscribeIntroActivity.this, SUBSCRIBE_SKU, RC_REQUEST, mPurchaseFinishedListener);
At least this is what I use in my code and I have successfully tested it.
I don't think the new in-app billing version 3 currently supports subscriptions. I could be wrong, but I haven't seen any mention of subscriptions in the sample code or documentation, so that could be why you're receiving the the "Item not found" error.
In general, to test purchasing a real item, you need to upload a version of your app to the developer console (but you don't need to publish it), and you have to be using the same (signed) version to test with. It also takes Google Play some time to process/propagate newly added items...so sometimes you unfortunately just need to wait. Check out developer.android.com/training/in-app-billing/test-iab-app.html if you haven't already.
One more thing to know. Purchases doesn't appear immediately. You can test them after 2-3 hours from moment, when you publish it.
Sorry for my English =)
There's a limit of 20 items per request.
Even if you split them in groups of 20 items, it still does
skuList.addAll(inv.getAllOwnedSkus(itemType));
which guarantees an error if number_of_owned_items + number_of_queried_items is greater than 20, in particular, if number_of_owned_items is 21.
Now I understand why someone suggested rewriting the code from scratch from the very beginning.

Categories

Resources