I develop an app with in app version 2 and publish it on developers Google now some one download the app and try to purchase it. On purchasing a message showed to him that "Your card is decline" now even after this message app got "unlock" . Now this is a very difficult situation that payment is not made while app got unlock. Is this issue with in app billing method(logic) in my app or its with Google.
If its in my app then is there any method which check that the person card is a "declined card" so in this method i can restrict my app not to unlock the app.
Any app will be appreciated.
I have this code in my BillingReceviver:
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (Consts.ACTION_PURCHASE_STATE_CHANGED.equals(action)) {
String signedData = intent.getStringExtra(Consts.INAPP_SIGNED_DATA);
String signature = intent.getStringExtra(Consts.INAPP_SIGNATURE);
purchaseStateChanged(context, signedData, signature);
} else if (Consts.ACTION_NOTIFY.equals(action)) {
String notifyId = intent.getStringExtra(Consts.NOTIFICATION_ID);
if (Consts.DEBUG) {
Log.i(TAG, "notifyId: " + notifyId);
}
notify(context, notifyId);
} else if (Consts.ACTION_RESPONSE_CODE.equals(action)) {
long requestId = intent.getLongExtra(Consts.INAPP_REQUEST_ID, -1);
int responseCodeIndex = intent.getIntExtra(Consts.INAPP_RESPONSE_CODE,
ResponseCode.RESULT_ERROR.ordinal());
checkResponseCode(context, requestId, responseCodeIndex);
} else {
Log.w(TAG, "unexpected action: " + action);
}
}
After making ACTION_PURCHASE_STATE_CHANGED matches the action the my purchsedstatechanged calls in file BillingService
private void purchaseStateChanged(int startId, String signedData, String signature) {
ArrayList<Security.VerifiedPurchase> purchases;
DatabaseHandler db=new DatabaseHandler(this);
purchases = Security.verifyPurchase(signedData, signature);
if (purchases == null) {
return;
}
ArrayList<String> notifyList = new ArrayList<String>();
for (VerifiedPurchase vp : purchases) {
if (vp.notificationId != null) {
notifyList.add(vp.notificationId);
}
ResponseHandler.purchaseResponse(this, vp.purchaseState, vp.productId,
vp.orderId, vp.purchaseTime, vp.developerPayload);
db.addUser("com.example.app", "111", "1222");
Log.i("Usgdgfer",""+db.isUserPresent("com.example.app"));
}
if (!notifyList.isEmpty()) {
String[] notifyIds = notifyList.toArray(new String[notifyList.size()]);
confirmNotifications(startId, notifyIds);
}
}
Usually, the card has to be mapped to the Google Wallet account before the purchase is made. If the card is invalid, it will show an error while you map the card to your Google account.
Seems strange that the card is being validated during purchase. Even then, if the payment is not made properly , you should get an error response
BILLING_RESPONSE_RESULT_USER_CANCELED = 1;
BILLING_RESPONSE_RESULT_BILLING_UNAVAILABLE = 3;
Check if you handle these errors properly after you receive them in the IabResult. Make sure you unlock your app only when you receive a proper response.
Related
I'm using Rave for the first time, it looked so flexible and easier to integrate, but along the line. I got stuck with testing, I'm using only card and bank payments methods.
when I choose the card to and enter some test cards from the test card link https://developer.flutterwave.com/reference#test-cards-1
I get 2 errors, => "unable to retrieve transaction fees" but in my logcat I see => " only test cards ree allowed," of which were using the test cards. And am also on staging mode which I assume is correct while testing with test keys.
When I use the bank tab I get some error in JSON toasted, but display later => "parents_limit not defined". Not just that I give this errors, I still found transactions of the bank payment types recorded on my dashboard. This confuses me more since I didn't get the payment success message so I can verify and give value to the customer.
I have integrated everything as per guideline in Rave docs, which calls my make payment. from https://github.com/Flutterwave/rave-android
variable for implementation
//online payment
String[] fullname;
String email = "";
String fName = "";
String lName = "";
String narration = "Payment for Riidit App activation";
String txRef;
String country = "NG";
String currency = "NGN";
private String mUsername, userID, mEmail;
the payment method
private void makePayment(int amount) {
txRef = email + " " + UUID.randomUUID().toString();
try {
fullname = mUsername.split(" ");
fName = fullname[0];
lName = fullname[1];
} catch (NullPointerException ex) {
ex.printStackTrace();
}
/*
Create instance of RavePayManager
*/
new RavePayManager(this).setAmount(amount)
.setCountry(country)
.setCurrency(currency)
.setEmail(email)
.setfName(fName)
.setlName(lName)
.setNarration(narration)
.setPublicKey(RiiditUtilTool.getPublicKey())
.setEncryptionKey(RiiditUtilTool.getEncryptionKey())
.setTxRef(txRef)
.acceptAccountPayments(true)
.acceptCardPayments(true)
.acceptMpesaPayments(false)
.acceptGHMobileMoneyPayments(false)
.onStagingEnv(false)
.allowSaveCardFeature(true)
.withTheme(R.style.DefaultTheme)
.initialize();
}
//called from below
private void payOnline()
{
makePayment(amount);
}
public void onActivateOnlineClick(View v) {
payOnline();
}
// expecting result of payment here either fail or success
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == RaveConstants.RAVE_REQUEST_CODE && data != null) {
String message = data.getStringExtra("response");
if (resultCode == RavePayActivity.RESULT_SUCCESS) {
Toast.makeText(this, "SUCCESS " + message, Toast.LENGTH_LONG).show();
// get a PIN and SERIAL no when payment succeeds
getGetPinAndSerialForPaidUser();
} else if (resultCode == RavePayActivity.RESULT_ERROR) {
Toast.makeText(this, "ERROR " + message, Toast.LENGTH_LONG).show();
} else if (resultCode == RavePayActivity.RESULT_CANCELLED) {
Toast.makeText(this, "Payment CANCELLED " + message, Toast.LENGTH_LONG).show();
}
}
}
I want when this event is triggered, it will make the payment to using the value set in the amount and return status in the onActivityResult above where I can check and give value to the user
First of all make sure you are using the api keys which are for testing and if you are on staging mode(testing) then set this to true .onStagingEnv(true) and test after that.
I have a new android app in which I am adding in-app billing and I am tearing my hair out with frustration.
I have uploaded a signed APK and published to alpha. I created a set of in-app products and activated them all. I have created a new gmail account and defined them as a tester for the app on the app apk page.
I have factory reset my android phone and initialised it with the new gmail account. I have entered the /apps/testing link in to chrome and signed up as a tester. I then downloaded and installed my app. Inside my app I asked for the in app products that were available and was shown the set i created above. I selected one to buy and went through the following purchase process.
1. Screen shows product to be purchased and price and requests press continue which i do
2. Screen shows payment methods and I select redeem code
3. Screen shows redeem your code and I enter one of the promotion codes I set up in the developer console earlier (not mentioned above - sorry) and press redeem
4. Screen shows product again, this time with price crossed out and offers option to add item which I select (very strange being asked to add again buy hey ho)
5. Screen shows item added
6. After a fews seconds screen shows Error you already own this item.
How can this be, this user did not exist before ten minutes ago and has only used this app once as described above.
I have seen many questions in stack overflow and elsewhere similar to this and tried everything, clearing google play store cache, clearing google play store data etc. This sequence described above is my latest attempt with a completely clean user on a completely clean phone.
I could upload my app code used but that misses the point, which is how can this gmail account already own an item when this gmail account have never purchased anything before from anyone. Surely this is a bug.
All clues very welcome as to how to proceed. Code now added, note this is a hybrid android app, with the user purchase decisions code in javascript/html and the in app actions in the wrapper code below
private void processCommand(JSONObject commandJSON) throws JSONException
{
String command = commandJSON.getString("method");
if ("GetInAppProducts".equals(command))
{
Log.d(TAG, "Querying Inventory");
InAppPurchaseSkuString = null ; // clear the purchased sku. Note this is tested in mConsumeFinishedListener
mHelper.queryInventoryAsync(true, itemSkus, new IabHelper.QueryInventoryFinishedListener()
{
#Override
public void onQueryInventoryFinished(IabResult iabResult, Inventory inventory)
{
InventoryRecord = inventory ;
if (iabResult.isFailure())
{
Log.d(TAG, "Query inventory failed");
SendEndItemsToApp ();
}
else
{
Log.d(TAG, "Query inventory was successful.");
InventoryCheckCount = 0 ; // seems that we cannot just fire off a whole lot of these checks at the same time, so do them in sequence
if (itemSkus.size()>0) { CheckForOwnedItems (); } else { SendEndItemsToApp (); }
}
}
});
}
else if ("BuyInAppProduct".equals(command))
{
JSONArray params = commandJSON.getJSONArray("parameters");
InAppPurchaseSkuString = params.getString(0);
Log.d(TAG, "User decision to purchase " + InAppPurchaseSkuString);
mHelper.launchPurchaseFlow( MainActivity.this, InAppPurchaseSkuString, InAppPurchaseActivityCode, mPurchaseFinishedListener, "mypurchasetoken"); // consider putting the user email address in the last field - need to get from app
};
}//end of ProcessCommand
public void CheckForOwnedItems ()
{
Log.d(TAG, "Pre Purchase Inventory Processing Started");
String sku = itemSkus.get(InventoryCheckCount);
if (InventoryRecord.getSkuDetails(sku) != null)
{
if (InventoryRecord.hasPurchase(sku))
{
consumeItem ();
}
else
{
SendItemToApp ();
InventoryCheckCount++;
if (InventoryCheckCount < itemSkus.size()) { CheckForOwnedItems (); } else { SendEndItemsToApp (); }
};
};
}//end of CheckForOwnedItems
public void SendItemToApp ()
{
String sku = itemSkus.get(InventoryCheckCount);
String priceString = InventoryRecord.getSkuDetails(sku).getPrice().replaceAll("[^\\d.]+", ""); // RegExp removes all characters except digits and periods
String infoString = "InAppProductDetails('" + sku + "','" + "dummy" + "','" + priceString + "');"; // dummy is a placeholder for product description which is not (yet?) used in the app
Log.d(TAG, infoString);
mWebView.evaluateJavascript (infoString, new ValueCallback<String>()
{
#Override
public void onReceiveValue(String s)
{
//Log.d(TAG,"Returned from InAppProductDetails:");
}
}
);
}
public void SendEndItemsToApp ()
{
String endString = "InAppProductsEnd();"; // name is a placeholder for now
Log.d(TAG, endString);
mWebView.evaluateJavascript(endString, new ValueCallback<String>()
{
#Override
public void onReceiveValue(String s)
{
//Log.d(TAG,"Returned from InAppProductsEnd:");
}
}
);
}
public void consumeItem()
{
Log.d(TAG,"Pre Purchase Inventory Query Started");
String sku = itemSkus.get(InventoryCheckCount);
mHelper.consumeAsync(InventoryRecord.getPurchase(sku), mConsumeFinishedListener);
}
IabHelper.OnConsumeFinishedListener mConsumeFinishedListener = new IabHelper.OnConsumeFinishedListener()
{
public void onConsumeFinished (Purchase purchase, IabResult result)
{
if (result.isSuccess())
{
Log.d(TAG, "Pre Purchase Consume Item Completed");
SendItemToApp ();
InventoryCheckCount++;
if (InventoryCheckCount < itemSkus.size()) { CheckForOwnedItems (); } else { SendEndItemsToApp (); }
}
else
{
Log.d(TAG,"Pre Purchase Consume Item Failed");
}
}
};
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener()
{
public void onIabPurchaseFinished (IabResult result, Purchase purchase)
{
if (result.isFailure())
{
Log.d(TAG,"Purchase Scenario Failed");
}
else if (purchase.getSku().equals(InAppPurchaseSkuString))
{
Log.d(TAG,"Purchase Scenario Completed");
String evalString = "InAppProductPurchased('" + InAppPurchaseSkuString + "');";
Log.d(TAG, evalString);
mWebView.evaluateJavascript (evalString, new ValueCallback<String>()
{
#Override
public void onReceiveValue(String s)
{
Log.d(TAG, "Returned from InAppProductPurchased:");
}
}
);
}
}
};
I have found that this error does not occur when using paypal (i.e. real money) to make the purchase, so I believe that this "Error you already own this item" message is in some way connected to using a promotion code for the test. And (so far) my paypal account has not been charged (as I am a resgistered tester for the app).
With the following code that retrieves the user's Google account, gmail, I was wondering why I get null from devices like mine (that of course runs on my gmail), whereas it works on my mom's devices:
public class MainActivity extends AppCompatActivity {
final String TAG = "Sample2";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String test = getEmail(getApplicationContext());
Log.d(TAG, "Email is: " + test);
TextView emailTxt = (TextView)findViewById(R.id.emailTxt);
emailTxt.setText(test);
}
private String getEmail(Context context) {
AccountManager accountManager = AccountManager.get(context);
Account account = getAccount(accountManager);
if (account == null) {
return null;
} else {
return account.name;
}
}
private static Account getAccount(AccountManager accountManager) {
Account[] accounts = accountManager.getAccountsByType("com.google");
Account account;
if (accounts.length > 0) {
account = accounts[0];
} else {
account = null;
}
return account;
}
}
I also included the following permission into my Manifest file:
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
Clearly, it's because of my device... But it can't be the only device that's returning null, so I don't know if this is a good approach for a unique string token when verifying payload with in-app billing.
Oh, and here's a screenshot of what I see in my Accounts & Sync settings:
... Is there anything I'm missing here?
Based on the document Set the developer payload string. When making purchase requests, you should not use the user's email address in the payload string, since the address may change.
You should pass in a string token that helps your application to identify the user who made the purchase, so that you can later verify that this is a legitimate purchase by that user. For consumable items, you can use a randomly generated string, but for non- consumable items you should use a string that uniquely identifies the user.
https://developer.android.com/about/versions/oreo/android-8.0-changes.html
Account access and discoverability
In Android 8.0 (API level 26), apps can no longer get access to user accounts unless the authenticator owns the accounts or the user grants that access. The GET_ACCOUNTS permission is no longer sufficient. To be granted access to an account, apps should either use AccountManager.newChooseAccountIntent() or an authenticator-specific method. After getting access to accounts, an app can can call AccountManager.getAccounts() to access them.
Android 8.0 deprecates LOGIN_ACCOUNTS_CHANGED_ACTION. Apps should instead use addOnAccountsUpdatedListener() to get updates about accounts during runtime.
For information about new APIs and methods added for account access and discoverability, see Account Access and Discoverability in the New APIs section of this document
Maybe you can try this
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private static final int PICK_ACCOUNT_REQUEST = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent googlePicker = AccountManager.newChooseAccountIntent(null, null,
new String[] { "com.google"}, true, null, null, null, null);
startActivityForResult(googlePicker, PICK_ACCOUNT_REQUEST);
}
#Override
protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
if (requestCode == PICK_ACCOUNT_REQUEST && resultCode == RESULT_OK) {
String accountName = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
Log.d(TAG, "Account Name=" + accountName);
String accountType = data.getStringExtra(AccountManager.KEY_ACCOUNT_TYPE);
Log.d(TAG, "Account type=" + accountType);
AccountManager accountManager = AccountManager.get(this);
Account[] accounts = accountManager.getAccounts();
for (Account a :
accounts) {
Log.d(TAG, "type--- " + a.type + " ---- name---- " + a.name);
}
}
}
}
I am a novice Android developer who has never used in-app billing before. So I have followed the steps outlined in Google's own documentation at http://developer.android.com/google/play/billing/billing_integrate.html.
I added the IInAppBillingService.aidl file under main/aidl/com.android.vending.billing and my structure matches countless screenshots I've seen online.
I added code very similar to the sample code to a part of my app that interacts with my online marketplace. A simplified version of that code, with extraneous stuff removed, is:
imports...
import android.content.ServiceConnection;
import com.android.vending.billing.IInAppBillingService;
public class intMarket extends Activity {
IInAppBillingService mService;
public static final String SHARED_PREFS_NAME="myAppSettings";
public static String purchaseToken = "";
ServiceConnection mServiceConn = new ServiceConnection() {
#Override
public void onServiceDisconnected(ComponentName name) {
mService = null;
}
#Override
public void onServiceConnected(ComponentName name,
IBinder service) {
mService = IInAppBillingService.Stub.asInterface(service);
}
};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.intbrowser);
Intent serviceIntent = new Intent("com.android.vending.billing.InAppBillingService.BIND");
serviceIntent.setPackage("com.android.vending");
bindService(serviceIntent, mServiceConn, Context.BIND_AUTO_CREATE);
WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.setWebViewClient(new WebViewClient());
WebSettings webSettings = myWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
myWebView.addJavascriptInterface(new WebAppInterface(this), "Android");
String tUrl = getString(R.string.urlMarket);
SharedPreferences settings = getSharedPreferences(SHARED_PREFS_NAME, 0);
myWebView.loadUrl(tUrl);
}
#Override
public void onDestroy() {
super.onDestroy();
if (mService != null) {
unbindService(mServiceConn);
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 1001) {
int responseCode = data.getIntExtra("RESPONSE_CODE", 0);
String purchaseData = data.getStringExtra("INAPP_PURCHASE_DATA");
String dataSignature = data.getStringExtra("INAPP_DATA_SIGNATURE");
if (resultCode == RESULT_OK) {
try {
JSONObject jo = new JSONObject(purchaseData);
String sku = jo.getString("productId");
purchaseToken = jo.getString("purchaseToken");
}
catch (JSONException e) {
e.printStackTrace();
}
}
}
}
public class WebAppInterface {
Context mContext;
/** Instantiate the interface and set the context */
WebAppInterface(Context c) {
mContext = c;
}
/** Show a toast from the web page */
#JavascriptInterface
public void showToast(String toast) {
Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
}
#JavascriptInterface
public void purchaseItem(Integer itemID, String itemName, BigDecimal itemPrice) {
// Credit Purchase
ArrayList<String> skuList = new ArrayList<String> ();
Bundle querySkus = new Bundle();
querySkus.putStringArrayList("ITEM_ID_LIST", skuList);
String purchaseCreditsResponse = "Success";
try {
Bundle skuDetails = mService.(3, getPackageName(), "inapp", querySkus);
Log.d("WPS", skuDetails.toString());
int response = skuDetails.getInt("RESPONSE_CODE");
Log.d("WPS", Integer.toString(response));
if (response == 0) {
ArrayList<String> responseList = skuDetails.getStringArrayList("DETAILS_LIST");
String thisItemID = "0";
for (String thisResponse : responseList) {
JSONObject object = new JSONObject(thisResponse);
String itemPrice = object.getString("price");
if (itemPrice.equals(itemPrice.toString()))
thisItemID = object.getString("productId");
}
if (Integer.parseInt(thisItemID) > 0) {
Bundle buyIntentBundle = mService.getBuyIntent(3, getPackageName(), thisItemID, "inapp", "bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ");
if (buyIntentBundle.getInt("RESPONSE_CODE") == 0) {
PendingIntent pendingIntent = buyIntentBundle.getParcelable("BUY_INTENT");
//startIntentSenderForResult(pendingIntent.getIntentSender(), 1001, new Intent(), Integer.valueOf(0), Integer.valueOf(0), Integer.valueOf(0));
// purchaseToken
purchaseCreditsResponse = "Failure";
Toast.makeText(mContext, "Buying: " + itemName, Toast.LENGTH_LONG).show();
}
} else {
purchaseCreditsResponse = "Failure";
Toast.makeText(mContext, "Sorry, but there was a problem with your purchase. Please try again. If the problem persists, contact support. Error Code: 001.", Toast.LENGTH_LONG).show();
}
} else {
purchaseCreditsResponse = "Failure";
Toast.makeText(mContext, "Sorry, but there was a problem with your purchase. Please try again. If the problem persists, contact support. Error Code: 002.", Toast.LENGTH_LONG).show();
}
} catch (RemoteException e) {
purchaseCreditsResponse = "Failure";
Toast.makeText(mContext, "Sorry, but there was a problem with your purchase. Please try again. If the problem persists, contact support. Error Code: 003.", Toast.LENGTH_LONG).show();
} catch (JSONException e) {
purchaseCreditsResponse = "Failure";
Toast.makeText(mContext, "Sorry, but there was a problem with your purchase. Please try again. If the problem persists, contact support. Error Code: 004.", Toast.LENGTH_LONG).show();
}// catch (IntentSender.SendIntentException e) {
// purchaseCreditsResponse = "Failure";
// Toast.makeText(mContext, "Sorry, but there was a problem with your purchase. Please try again. If the problem persists, contact support. Error Code: 005.", Toast.LENGTH_LONG).show();
//}
// Purchase Report
// Report purchase and get response into purchaseResponse
// Todo
// Credit Consumption
// Todo
}
}
}
I then compiled a version of this and uploaded the APK to Google Play as an alpha test case and published it. I have been making updates and using ADB to install the new compiled APKs to my phone, but I continually get the following from this code in LogCat:
03-23 15:07:55.325 2958-3009/? D/WPS﹕ Bundle[mParcelledData.dataSize=48]
03-23 15:07:55.325 2958-3009/? D/WPS﹕ 5
Which, of course, indicates: BILLING_RESPONSE_RESULT_DEVELOPER_ERROR
I read in another SO post that you cannot test billing on a device whose main account is the same as the developer's account. So I spent several hours yesterday tracking down another phone and getting it setup using a completely separate account (and the only account on the device). I uploaded a new build to Google Play as an alpha test and published it. I waited for this other phone to get the new version and tried testing billing again. The phone reported this error message that I had built in:
Sorry, but there was a problem with your purchase. Please try again. If the problem persists, contact support. Error Code: 002.
Which indicates the same error I was running into before. This implies that there is a problem with my code, which would not surprise me.
I have not done anything with the big giant license code that appears in the Google Play developer panel because the above referenced documentation says nothing about it being required. But is it? If not, what about my code is causing this problem?
Verify that com.android.vending.BILLING is added to your manifest permissions.
Also verify that your app is signed with your production key and the version on Google Play should be the same as the version you are testing with.
Also have a look at this lightweight, straight forward library you can use on Github below:
https://github.com/anjlab/android-inapp-billing-v3
People comment that this is a bug in Google's billing API (maybe Google considers it a feature?).
Seems like you have to consume the purchaseToken, just as the guy here does:
String purchaseToken = o.optString("token", o.optString("purchaseToken"));
// Consume purchaseToken, handling any errors
mService.consumePurchase(3, getPackageName(), purchaseToken);
In my attempts to understand the In-app Billing flow, I ran the market_billing sample, as is, plus a few Log.v() in key points, like in BillingService.handleCommand():
public void handleCommand(Intent intent, int startId) {
String action = intent.getAction();
if (Consts.DEBUG) {
Log.i(TAG, "handleCommand() action: " + action);
}
if (Consts.ACTION_CONFIRM_NOTIFICATION.equals(action)) {
String[] notifyIds = intent.getStringArrayExtra(Consts.NOTIFICATION_ID);
confirmNotifications(startId, notifyIds);
} else if (Consts.ACTION_GET_PURCHASE_INFORMATION.equals(action)) {
String notifyId = intent.getStringExtra(Consts.NOTIFICATION_ID);
getPurchaseInformation(startId, new String[] { notifyId });
} else if (Consts.ACTION_PURCHASE_STATE_CHANGED.equals(action)) {
String signedData = intent.getStringExtra(Consts.INAPP_SIGNED_DATA);
String signature = intent.getStringExtra(Consts.INAPP_SIGNATURE);
purchaseStateChanged(startId, signedData, signature);
} else if (Consts.ACTION_RESPONSE_CODE.equals(action)) {
long requestId = intent.getLongExtra(Consts.INAPP_REQUEST_ID, -1);
int responseCodeIndex = intent.getIntExtra(Consts.INAPP_RESPONSE_CODE,
ResponseCode.RESULT_ERROR.ordinal());
ResponseCode responseCode = ResponseCode.valueOf(responseCodeIndex);
checkResponseCode(requestId, responseCode);
}
}
My problem (?) is that I can see in the logs all actions being performed, but ACTION_CONFIRM_NOTIFICATION never shows up for some reason, despite the transaction being successful.
Any idea why this is?
What am I missing?
ACTION_CONFIRM_NOTIFICATION is never used in BillingReceiver and I have no idea why they declare it in handleCommand as CONFIRM_NOTIFICATION should not be done here in the first place
The BillingReceiver is waiting for the IN_APP_NOTIFY message sent from the market. Then it would start the confirmation through the service. Does your receiver receive the IN_APP_NOTIFY message?
I have a similar issue too. My application does never get back the notification from the Market application. So there's actually nothing to confirm for your app.
It seems like it is a known issue for a long time already as you can see here: http://code.google.com/p/marketbilling/issues/detail?id=14