Hi i'm trying to add in app purchases to my app i have set up my in app purchases on the developer console which are set to active i have then queried them which yesterday was working perfectly i retrieved all the details but today its coming back as null. the only thing that has changed is that i had to uninstall the app and re-run it. I have checked my skus both in the app and on the developer console which match exactly when i run IabHelper start setup i get a result of ok. And then i call IabHelper.QueryInventoryFinishedListener and that results back as being ok but when i try access anything from the inventory it comes back as null. does anyone know why? or if i'm doing some wrong in my code?
in my on Create();
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.v("Menu", "Problem setting up In-app Billing: " + result);
}
// Hooray, IAB is fully set up!
Log.v("Menu", "INAPP BILLING SETUP COMPLETE: " + result);
ArrayList<String> skuList = new ArrayList<String> ();
skuList.add("myapp.consumable.inapppurchase_id_1");
skuList.add("myapp.consumable.inapppurchase_id_2");
skuList.add("myapp.consumable.inapppurchase_id_3");
skuList.add("myapp.permanant.inapppurchase_id_6");
skuArray = new JSONArray(skuList);
mHelper.queryInventoryAsync(true, skuList, mQueryFinishedListener);
}
});
Then i heres my code for the QueryListener
IabHelper.QueryInventoryFinishedListener mQueryFinishedListener = new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result, Inventory inventory)
{
if (result.isFailure()) {
Log.v("Menu", "RESULT FALIURE");
return;
}
Log.v("Menu", "this +" + skuArray);
Log.v("Menu", "Inventory +" + inventory);
for(int i = 0; i < skuArray.length(); i++){
try {
String SKU = skuArray.getString(i);
if(inventory.getSkuDetails(SKU) != null){
Log.v("Menu", "SKU = " + SKU);
Log.v("Menu", "SKU" + SKU + "= " + inventory.getSkuDetails(SKU));
updateProductData("price",inventory.getSkuDetails(SKU).getPrice(),i);
updateProductData("id",inventory.getSkuDetails(SKU).getSku(),i);
}else{
Log.v("Menu", "SKU RETURNED NULL" + SKU);
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
};
Ok i spoke to Google about this issue. And they say they have made changes which requires the apk to be published before adding in app purchases they recommend uploading the apk to alpha testing channel and published (not in draft mode).
Ill give it a try and feed back if it works
After I published my alpha apk to google play the billing started to work again.
Related
I've been working on IAB V3, and have been having trouble, when trying to get the sku details off the store. After cheking for result failure of the inventory query, I try to get the details with inv.getSkuDetails(MODULE).getPrice(); This always returns null, and when debugging I can see that the inventory object is empty.
However These requests always return null.
I am aware that google requires you to upload an apk to the alpha release channel (and release it) and have the InAppPurchase active (I also gave the store a few days to take over the changes). To test I used the same APK as uploaded to the alpha channel.
The IabHelper obviously managed to connect to the right app, as a test purchase was possible, and could be queried from the store.
Code:
`mHelper = new IabHelper(MainActivity.this, getString(getString(R.string.key1));
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener(){
#Override
public void onIabSetupFinished(IabResult result) {
if (!result.isSuccess()) {
Log.d(TAG, "Problem Setting up Billing" + result);
return;
}
IabHelper.QueryInventoryFinishedListener mQueryFinishedListener = new IabHelper.QueryInventoryFinishedListener() {
#Override
public void onQueryInventoryFinished(IabResult result, Inventory inv) {
if (result.isFailure()) {
Toast.makeText(getApplicationContext(), R.string.connectionFailed, Toast.LENGTH_SHORT).show();
Log.d(TAG, result.getMessage() + result.getResponse() + inv.toString());
return;
}
String modulePrice = inv.getSkuDetails(MODULE).getPrice();
String moduleTitle = inv.getSkuDetails(MODULE).getTitle();
String moduleDescription=inv.getSkuDetails(MODULE).getDescription();
}
}
ArrayList<String> skuList=new ArrayList<String>();
skuList.add(MODULE);
try {
mHelper.queryInventoryAsync(true, skuList, mQueryFinishedListener);
} catch (IabHelper.IabAsyncInProgressException e) {
e.printStackTrace();
}
}
});`
Ignore the wrong indentation and missing brackets, as i cut out some code.
I greatly appreciate any ideas as to what could be causing this problem.
Thanks
I am currently developing an app with in App billing. all works fine. and I already published the app in Beta channel and tested it with test users with real items, and it works.
However while debugging, I am using the android.test.purchased item, my play store crashes when I press the buy button.
and I get the following error(s):
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.android.vending, PID: 25463
java.lang.NullPointerException: Attempt to read from field 'com.google.android.finsky.protos.Acquisition$AutoDismissTemplate com.google.android.finsky.protos.Acquisition$PostAcquisitionPrompt.autoDismissTemplate' on a null object reference
at com.google.android.finsky.billing.SuccessStep.getLayoutResId(SuccessStep.java:75)
at com.google.android.finsky.billing.lightpurchase.PurchaseFragment.onStateChange(PurchaseFragment.java:31066)
at com.google.android.finsky.fragments.SidecarFragment.notifyListener(SidecarFragment.java:255)
at com.google.android.finsky.fragments.SidecarFragment.setState(SidecarFragment.java:250)
at com.google.android.finsky.billing.lightpurchase.CheckoutPurchaseSidecar.confirmAuthChoiceSelected(CheckoutPurchaseSidecar.java:631)
at com.google.android.finsky.billing.lightpurchase.PurchaseFragment.onStateChange(PurchaseFragment.java:32156)
at com.google.android.finsky.fragments.SidecarFragment.notifyListener(SidecarFragment.java:255)
at com.google.android.finsky.fragments.SidecarFragment.setState(SidecarFragment.java:250)
at com.google.android.finsky.billing.lightpurchase.CheckoutPurchaseSidecar.access$1900$2f730cd3(CheckoutPurchaseSidecar.java:72)
at com.google.android.finsky.billing.lightpurchase.CheckoutPurchaseSidecar$1.run(CheckoutPurchaseSidecar.java:1009)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
11-23 02:22:43.202 590-739/? W/ActivityManager: Force finishing activity com.android.vending/com.google.android.finsky.billing.lightpurchase.IabV3Activity
Purchase finished: IabResult: Null data in IAB result (response: -1002:Bad response received), purchase: null
Error purchasing: IabResult: Null data in IAB result (response: -1002:Bad response received)
sometimes the purchase continues after that, and other times, my app crashes.
I tested this on several devices (Nexus 7 with Android 6.0, Note 5 with Android 5.1.1, Galaxy S3 with Android 4.3, LG G3 with Android 4.4), all have the same behavior.
What makes me mad is that real in app items work flawlessly. which makes me think this means my code is fine. but having this happening with the test items, make me worried that it might be repeated with real items with real users when published.
I appreciate your assistance to let me know if I am doing something wrong leading to play store crashing, or this can happen?
please note that I am fairly new to Android development.
Thanks.
Here is my code for in App billing:
///... part of onCreate:
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 {
// Hooray, 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); }
}
});
/////////////////
public void startPurchase(String ITEM_SKU) { // Start the purchase process here
String purchaseToken = "inapp:" + getPackageName() + ":"+ ITEM_SKU;
Log.d(TAG, "Purchase started for : " + ITEM_SKU);
mHelper.launchPurchaseFlow(this, ITEM_SKU, 10002,
mPurchaseFinishedListener, purchaseToken);
}
// 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 (result.isFailure()) {
Log.d(TAG,"Error purchasing: " + result);
if (result.getResponse()==7){
if(myInventory.hasPurchase(ITEM_SKU))
{
Log.d(TAG,"Ooops, Item already purchased, consume it");
mHelper.consumeAsync(myInventory.getPurchase(ITEM_SKU),mConsumeFinishedListener2);
}
}
return;
}
Log.d(TAG, "Purchase successful.");
if (purchase.getSku().equals(ITEM_SKU)) {
mHelper.consumeAsync(purchase, mConsumeFinishedListener);
}
}
};
IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
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.");
myInventory = inventory;
//Process inventory
}
};
IabHelper.OnConsumeFinishedListener mConsumeFinishedListener =
new IabHelper.OnConsumeFinishedListener() {
public void onConsumeFinished(Purchase purchase,
IabResult result) {
if (result.isSuccess()) {
Log.d(TAG,"consume successful for " + purchase.getSku() + " & " + result.getMessage());
updateCoinsAndScore(coinsToAdd, 0);
Toast.makeText(getApplication(), "تم إضافة عدد " + coinsToAdd + " عملات إلى رصيدك", Toast.LENGTH_LONG).show();
//reset values
coinsToAdd=0;
ITEM_SKU="";
} else {
Log.d(TAG, "Consume failed " + result.getMessage()); }
}
};
IabHelper.OnConsumeFinishedListener mConsumeFinishedListener2 =
new IabHelper.OnConsumeFinishedListener() {
public void onConsumeFinished(Purchase purchase,
IabResult result) {
if (result.isSuccess()) {
Log.d(TAG,"consumed, starting purchase again");
Log.d(TAG,"consume successful for " + purchase.getSku() + " & " + result.getMessage());
startPurchase(ITEM_SKU);
} else {
Log.d(TAG,"Consume failed " + result.getMessage()); }
}
};
The problem was in Google Play v6.0.0, it is now fixed in v6.0.5 (confirmed both on a Samsung and a Nexus device).
If you didn't get the Google Play update automatically, you can download it manually from ApkMirror.com etc.
I am trying to implement the In-App Purchase using the wrapper of Trivial Gas tutorial. After completion of successful purchase The app crashed, since then the app is getting crashed at the beginning.
java.lang.IllegalArgumentException: java.security.spec.InvalidKeySpecException: java.lang.RuntimeException: error:0D07209B:asn1 encoding routines:ASN1_get_object:too long
at com.nightowl.memory.Security.generatePublicKey(Security.java:85)
at com.nightowl.memory.Security.verifyPurchase(Security.java:65)
at com.nightowl.memory.IabHelper.queryPurchases(IabHelper.java:875)
at com.nightowl.memory.IabHelper.queryInventory(IabHelper.java:550)
at com.nightowl.memory.IabHelper.queryInventory(IabHelper.java:528)
at com.nightowl.memory.IabHelper$2.run(IabHelper.java:623)
at java.lang.Thread.run(Thread.java:841)
Caused by: java.security.spec.InvalidKeySpecException: java.lang.RuntimeException: error:0D07209B:asn1 encoding routines:ASN1_get_object:too long
at com.android.org.conscrypt.OpenSSLKey.getPublicKey(OpenSSLKey.java:101)
at com.android.org.conscrypt.OpenSSLRSAKeyFactory.engineGeneratePublic(OpenSSLRSAKeyFactory.java:47)
at java.security.KeyFactory.generatePublic(KeyFactory.java:171)
at com.nightowl.memory.Security.generatePublicKey(Security.java:80)
... 6 more
Caused by: java.lang.RuntimeException: error:0D07209B:asn1 encoding routines:ASN1_get_object:too long
at com.android.org.conscrypt.NativeCrypto.d2i_PUBKEY(Native Method)
at com.android.org.conscrypt.OpenSSLKey.getPublicKey(OpenSSLKey.java:99)
... 9 more
I have used the following code to call it:
String base64EncodedPublicKey;
base64EncodedPublicKey= String.valueOf(R.string.myPubKey);
additionalSkuList = new ArrayList<String>();
for(int i=0;i<3;i++)
{
for(int j=0;j<4;j++)
{
if(i==0&&j>1)
break;
additionalSkuList.add(id[i][j]);
}
}
mHelper = new IabHelper(this, base64EncodedPublicKey);
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
public void onIabSetupFinished(IabResult result) {
Log.d("main", "m here");
if (!result.isSuccess()) {
// Oh noes, there was a problem.
Log.d("main", "Problem setting up In-app Billing: " + result);
}
// Hooray, IAB is fully set up!
isIAB = true;
mHelper.queryInventoryAsync(true, additionalSkuList, mQueryFinishedListener);
Log.d("main", "" + isIAB + " " + isLoad);
}
});
IabHelper.QueryInventoryFinishedListener
mQueryFinishedListener = new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result, Inventory inventory)
{
Log.d("main", "m here too");
if (result.isFailure()) {
// handle error
return;
}
for(int i=0;i<3;i++)
{
for(int j=0;j<4;j++)
{
if(i==0&&j>1)
break;
price[i][j]=inventory.getSkuDetails(id[i][j]).getPrice();
}
}
isLoad=true;
data.setPrice(price);
data.setDataLoad(true);
// update the UI
}
};
public void onPurchaseCall()
{
int loc[] = data.getItem();
mHelper.launchPurchaseFlow(this, id[loc[0]][loc[1]], 100*loc[0]+loc[1],mPurchaseFinishedListener, id[loc[0]][loc[1]]);
}
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener
= new IabHelper.OnIabPurchaseFinishedListener() {
public void onIabPurchaseFinished(IabResult result, Purchase purchase)
{
if (result.isFailure()) {
Log.d("main", "Error purchasing: " + result);
return;
}
else if (purchase.getSku().equals(id[0][0])) {
data.setNoads(1);
mAdView.setVisibility(View.INVISIBLE);
data.setNotificationState(1);
data.setNoOfnotifications(2);
data.setNotificationMsg(0, "Purchase Complete");
data.setNotificationMsg(1, PurchaseMsg[0]);
// consume the gas and update the UI
}
}
};
Can anyone help me to solve it? What I guessed from the log is that something problem with the Public Key I provide. But the first time it worked (It was working till I initiated a successful purchase). And I was also getting the price list of all my in-app products.
I tried to test the purchase with a testing account. On successful completion of the purchase this error came and since then the app is not running for that account.
Don't use String.valueOf(R.string.myPubKey), it will give you a wrong value. Instead use getResources().getString(R.string.myPubKey_data)) to get your public key string.
Although the question is old, but i write answer for anyone will have this problem.
The problem is from public key length. It's not valid and is longer than it should be. Make sure you entered it correctly.
New to Android dev and I have this very annoying, and familiar problem.
Short version: how can I test my app on multiple physical devices w/o buying them? Specifically, I'm trying to test on 4.1 and 4.2 running devices. I can't use an emulator because this involves in-app billing.
Long version:
Today, I got a crash report from a user (android version = 4.2, on device = A1-811 (mango)).
The issue is: IAB helper is not set up. Can't perform operation: queryInventory . I tested the app on 4.3, 5.0, 5.1 and it's fine.
I KNOW that the actual crash happened because I wasn't quitting when I was checking for (!result.isSuccess()) in mhelper.startSetup().
My question is, how do I solve the underlying issue of IabHelper not being set up?! I don't have access to Android 4.2 device...
MY CODE:
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener () {
public void onIabPurchaseFinished (IabResult result, Purchase purchase) {
if (mHelper == null)
return;
if (result.isFailure ()) {
Log.d (PURCHASE_TAG, "Google's response is a failure.");
} else {
Log.d (PURCHASE_TAG, "Response is successful. purchase.getSKU = " + purchase.getSku ());
premium = true;
}
}
};
IabHelper.QueryInventoryFinishedListener mQueryFinishedListener = new IabHelper.QueryInventoryFinishedListener () {
public void onQueryInventoryFinished (IabResult result, Inventory inventory) {
Log.d (PURCHASE_TAG, "Processing Google's response.");
// Check if user has existing purchase.
if (result.isFailure ()) {
Log.d (PURCHASE_TAG, "Google's response is a failure. Response = ");
} else {
Log.d (PURCHASE_TAG, "Google's response is success! getPurchase() = " + inventory.getPurchase (THE_SKU));
if (inventory.getPurchase (THE_SKU) == null) {
premium = false;
} else {
premium = inventory.getPurchase (THE_SKU).getSku ().equals (THE_SKU);
}
}
// Show price if user is not premium, thank you note if the user is premium
if (premium == true) {
Log.d (PURCHASE_TAG, "3 premium = " + premium);
priceView.setText ("Thank you for the purchase!");
} else {
if (inventory != null) {
String pro_price = inventory.getSkuDetails (THE_SKU).getPrice ();
priceView.setText ("" + pro_price);
}
}
}
};
private void startPurchaseQuery () {
String base64EncodedPublicKey = "the key is generated ...";
mHelper = new IabHelper (this, base64EncodedPublicKey);
Log.d (PURCHASE_TAG, "Purchase query started.");
mHelper.startSetup (new IabHelper.OnIabSetupFinishedListener () {
public void onIabSetupFinished (IabResult result) {
Log.d (PURCHASE_TAG, "IabHelper Setup successful. Querying inventory.");
if (!result.isSuccess ()) {
Log.d (PURCHASE_TAG, "Error with IabHelper setup.");
return;
}
if (mHelper == null) return;
// IAB is fully set up. Now, let's get an inventory of stuff we own.
// Build the SKU list
List<String> additionalSkuList;
additionalSkuList = new ArrayList<String> ();
additionalSkuList.add (THE_SKU);
// Make the query
mHelper.queryInventoryAsync (true, additionalSkuList, mQueryFinishedListener);
Log.d (PURCHASE_TAG, "Query finished. Premium status = " + premium);
}
});
}
#Override
protected void onActivityResult (int requestCode, int resultCode, Intent data) {
Log.d (PURCHASE_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 (PURCHASE_TAG, "onActivityResult handled by IABUtil.");
}
}
#Override
public void onDestroy () {
super.onDestroy ();
if (mHelper != null) mHelper.dispose ();
mHelper = null;
}
Answer from comments above
It's better to catch the error and patch own code first. Trying to reproduce exact issue why was IAB not set up may not be possible, because of all kinds of modifications user can do on his device (could be bug with specific version of distro user is running, which is almost impossible to find out, or similar). As you suggested, using Analytics to find out how many users have this issue is good approach.
To answer original question, you can create Alpha or Beta versions in Developer Console and invite users with specific versions of Android you'd like to target into testing group. This was you could test issues and crashes directly from Dev. Console even when not directly being owner of the device.
I am trying to add Googles In-App Billing to my Android 4+ app. I have set up everything as described in "Preparing Your In-app Billing Application". Now I have uploaded the app to the Alpha testing channel in the Developer console.
Additionally I have set up a test account (described here) to be able purchase the items without triggering a real payment.
After installing the alpha version from the Play Store on my test device (using the test account of course) there a two problems:
No product information is fetched from the Play Store. Thus I cannot show any price information, etc.
When I start a purchase there is absolutly no hint, that this will be a free test purchase. Everything looks exactly like a real purchase.
This is the code I use:
String publicKey = MyApp.getPublicKey(); // de-code and get the public key
final IabHelper googlePlayHelper = new IabHelper(context, publicKey);
Log.d("TAG", "IabHelber Init");
googlePlayHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
public void onIabSetupFinished(IabResult result) {
if (!result.isSuccess()) {
Log.d("TAG", "IabHelber Init - Non Success: " + result);
} else {
Log.d("TAG", "IabHelber Init - SUCCESS");
try {
googlePlayHelper.queryInventoryAsync(true, new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
if (result.isFailure()) {
Log.d("TAG", "query Inventory - Non Success: " + result);
} else {
Log.d("TAG", "query Inventory - SUCCESS");
if (inventory.hasDetails(2my.product.id")) {
Log.d("TAG", "NO DETAILS");
} else {
Log.d("TAG", "Has Details");
}
}
}
}
} catch (Exception e) {
Log.d("TAG", "EXCEPTION: " + e.getMessage());
}
}
}
});
The Log shows the following:
D/TAG (25995): IabHelber Init
D/TAG (25995): IabHelber Init - SUCCESS
D/TAG (25995): query Inventory - SUCCESS
D/TAG (25995): NO DETAILS
What could be the reason that now details are fetched?
The docs that that there should be an hint when performing a test purchase. Why am I runnig a "real" purchase instead?
I have not been able to find out why purchases by test users are not handled as test purchases. But the problem with the missing product details is solved:
I used the following call to query the inventory:
googlePlayHelper.queryInventoryAsync(true, new IabHelper.QueryInventoryFinishedListener() { ... });
This is totally valid code and the first parameters (true in this example) states, that the query should fetch the product details. But it seems, that this parameter does not have any effect until a further parameter is given: One has to explicitly specify the IDs of the product one would like to fetch:
List<String> productIDs = new ArrayList<String>();
productIDs.add(IAP_ID_1);
productIDs.add(IAP_ID_2);
productIDs.add(IAP_ID_3);
googlePlayHelper.queryInventoryAsync(true, productIDs, new IabHelper.QueryInventoryFinishedListener() { ... });