In App BIlling trouble with Pending Intents and sw

2020-02-26 12:53发布

问题:

Ok so I have been trying to fix this for days, and I'm not coming here looking for someone to do my work for me as I have been troubleshooting and fixed every single error message in the LogCat. I am developing an Android game using Andengine (this might be part of the problem so being familiar with it could help). I'm not doing anything too fancy, my game activities are all single scene and don't have any Physics or anything like that, just a bunch of sprites and textures. I also used Andengine for all of the other activities in my game because I find it to be a very easy way to set up graphically appealing screens. One such screen is my in-app store, where users can buy levelpacks and new sprites. The billing part of this all works great, the purchases go through to the Market and there's nothing too complicated there...

When the user clicks buy, the market screen pops up and loads the product they have selected (these are real products, not the android tests although the game is not published). The Market screen pops up over the current activity, regardless of whether I use the "Android 2.0" implementation where it is part of the game's stack or I use the "Android 1.6" implementation and it is part of its own stack. I would prefer to use the Android 2.0 implementation but if I can only get the 1.6 to work I will take that. So anyway, the problem arises when the user either cancels the purchase using the back button or completes the purchase with a credit card, both result in the market screen disappearing and the app starting a new activity that is just a black screen (which eventually times out and causes a force close). The purchase goes through OK but the user does not get the product because the game force quits before we get to the code to change the user's items in the game. Now for some code, I used this tutorial (http://www.anddev.org/advanced-tutorials-f21/simple-inapp-billing-payment-t52060.html) without changing much of anything. The BillingHelper class is most important, as it holds the requestPurchase() method and the startBuyPageActivity() methods. I call request purchase from my StoreFront activity like this:

            BillingHelper.requestPurchase(StoreFront.this, itemID); 

and in the onCreate of the StoreFront I have this stuff (as told to do by the tut):

        startService(new Intent(mContext, BillingService.class));
    BillingHelper.setCompletedHandler(mTransactionHandler);

...

//some handler that billing needs
public Handler mTransactionHandler = new Handler(){
    public void handleMessage(android.os.Message msg) {
        Log.i(TAG, "Transaction complete");
        Log.i(TAG, "Transaction status: "+BillingHelper.latestPurchase.purchaseState);
        Log.i(TAG, "Item purchased is: "+BillingHelper.latestPurchase.productId);

        if(BillingHelper.latestPurchase.isPurchased()){
            //TODO do something here if we've completed our latest purchase,
            //this should be with the status bar notifications and
            //saved preferences
        }
    };

};

So I don't think the problem lies there. Here are the relevant parts of BillingHelper

protected static void requestPurchase(Context activityContext, String itemId){
    if (amIDead()) {
        return;
    }
    Log.i(TAG, "requestPurchase()");
    Bundle request = makeRequestBundle("REQUEST_PURCHASE");
    request.putString("ITEM_ID", itemId);
    try {
        Bundle response = mService.sendBillingRequest(request);

        //The RESPONSE_CODE key provides you with the status of the request
        Integer responseCodeIndex   = (Integer) response.get("RESPONSE_CODE");
        //The PURCHASE_INTENT key provides you with a PendingIntent, which you can use to launch the checkout UI
        PendingIntent pendingIntent = (PendingIntent) response.get("PURCHASE_INTENT");
        //The REQUEST_ID key provides you with a unique request identifier for the request
        Long requestIndentifier     = (Long) response.get("REQUEST_ID");
        Log.i(TAG, "current request is:" + requestIndentifier);
        C.ResponseCode responseCode = C.ResponseCode.valueOf(responseCodeIndex);
        Log.i(TAG, "REQUEST_PURCHASE Sync Response code: "+responseCode.toString());

        startBuyPageActivity(pendingIntent, new Intent(), activityContext);
    } catch (RemoteException e) {
        Log.e(TAG, "Failed, internet error maybe", e);
        Log.e(TAG, "Billing supported: "+isBillingSupported());
    }
}

Which I have tried calling from StoreFront with a variety of arguments as "ActivityContext" such as StoreFront.this, getApplicationContext(), a static context store elsewhere, a static Activity stored elsewhere, getBaseContext() anything I could possible think of...

Here is the other relevant activity

private static void startBuyPageActivity(PendingIntent pendingIntent, Intent intent, Context context){
    //android 1.6 method
    try {
        pendingIntent.send(context, 0, intent);         
    } catch (CanceledException e){
        Log.e(TAG, "startBuyPageActivity CanceledException");
    }
}

Nothing fancy, I just want the user to be returned to any of my various activities (preferably StoreFront) when they either buy the item or press back during the process. HELP PLEASE!

Edit: I want any possible solution to allow in-app billing to return to my app after the purchase is complete, even the messiest solution.

EDIT

A logcat and method calls of what the issue:

  "BillingService Starting", 
  BillingHelper.setCompletedHandler(), 
  StoreFront.onStart() called, 
  StoreFront.onResume() called, 
  "BillingService Service starting with onCreate", 
  "BillingService Market Billing Service Successfully Bound", 
  "BillingService Market Billing Service Connected", 
  BillingHelper.instantiateHelper(), 
  then this is where I actually click the buy button in the store (all of that runs just when opening StoreFront):
  BillingHelper.setCompletedHandler(), 
  BillingHelper.isBillingSupported(), 
  BillingHelper.amIDead(), 
  BillingHelper.makeRequestBundle(), 
  "BillingService isBillingSupported response was: RESULT OK", 
  BillingHelper.requestPurchase(), 
  BillingHelper.amIDead(), 
  "BillingService requestPurchase()", 
  BillingHelper.makeRequestBundle(), 
  "BillingService current request is ......", 
  "BillingService REQUEST PURCHASE Sync Response code: RESULT OK", 
  BillingHelper.startBuyPageActivity(), 
  "BillingService Recieved action: com.android.vending.billing.RESPONSE CODE", 
  "BillingService checkResponseCode got requestID..."
  "BillingService checkResponseCode go responseCode RESULT ERROR" 
  (this is because I can't purchase on this device), 
  and then I get an Error message saying: "E 32427 Surface surface (identity=5925) is invalid, err=-19 (No such device)" and from there nothing works anymore. 

Also I have tested this on a different phone (another developer I am working with, who can actually buy things in it but still gets the black screen error) and he never got the Handler messages you mentioned in your comment either

Edit: if I had to guess where the error is, I'd say it's this

06-16 11:20:23.635: DEBUG/dalvikvm(3807): GC_EXPLICIT freed 53K, 45% free 3710K/6663K, external 1K/513K, paused 102ms
06-16 11:20:23.885: ERROR/Surface(3807): surface (identity=158) is invalid, err=-19 (No such device)
06-16 11:20:23.905: ERROR/Surface(3807): surface (identity=158) is invalid, err=-19 (No such device)
06-16 11:20:23.905: ERROR/Surface(3807): surface (identity=158) is invalid, err=-19 (No such device)
06-16 11:20:23.905: ERROR/Adreno200-EGL(3807): egliSwapWindowSurface: unable to dequeue native buffer

Note that the interrupted exception is expected by the Andengine library so that is a red herring.

Also (I hope this is allowed on here) I will offer paypal reward for a solution. If this is against the Terms of SO then just delete this line, please don't close this question.

回答1:

I may know what's wrong and I have a test for you to do. The buy screen runs a finish call after the user cancels the purchase or completes the purchase. For me for some reason the finish call was drifting down into the currently running activity and (CLOSING??? it).

Here's the relevant line from the log:

06-16 11:20:22.774: WARN/ActivityManager(132): Duplicate finish request for HistoryRecord{40ace828 com.android.vending/.billing.InAppBuyPageActivity}

I think I fixed this in my code problem is that I can't remember exactly what I did (maybe didn't call finish in my purchase complete handler...)

I don't know anything about Andgen, but what would happen if a finish call got called on the main Andgen activity? I'd imagine it would stop execution and you might get a black screen and an app crash.

So to test this, create a separate activity for you buy page. Doesn't need to be complicated - maybe have it just buy one canned product after it starts up. Run your code and see if it still gives you the black screen of doom. My bet: it may exit out of the activity back to your game but I think it'll work.

Hope this helps and Good Luck!