[TUT] Simple InApp Billing / Payment

Tutorials with advanced 'difficulty' and more Lines of Code.

Re: [TUT] Simple InApp Billing / Payment

Postby kei » Mon Jul 04, 2011 3:33 am

Hi, Thank you very much. This is wonderful post.
I didn't want to publish my app by just copying google's billing sample without understanding what is actually going on... This article helps me a lot:)

One question.
In BillingHelper#verifyPurchase, you only check the first purchase
latestPurchase = purchases.get(0);
While google's sample checking the each item in the ArrayList.
I guess it may be the reason you mention that "Caveats: May have issues with multiple purchases and network delays",
But do you know in which case the purchase can be multiple? It seems we can only specify one item id ( and can not specify the quantity ) in the "REQUEST_PURCHASE" billing request. Or it should be safe to check the first one only (same as your sample) with the current market implementation?

Best Regards,
kei
Once Poster
Once Poster
 
Posts: 1
Joined: Mon Jul 04, 2011 3:19 am

Top

Re: [TUT] Simple InApp Billing / Payment

Postby blundell » Mon Jul 04, 2011 11:16 am

Yes it's because there can be multiple purchases, I left it like this to be simple.

I believe there can be occasion were you send two singular purchase requests and there is a delay by the server so it will just send one request back. These are edge cases but good for spotting it!
User avatar
blundell
Master Developer
Master Developer
 
Posts: 1610
Joined: Tue Nov 18, 2008 12:58 pm
Location: UK

Re: [TUT] Simple InApp Billing / Payment

Postby TrashMaster » Sun Jul 10, 2011 1:17 pm

Then I can use this code without changing anything? What has to be changed? I'm a beginner and I'm a little lost with app billing...
TrashMaster
Freshman
Freshman
 
Posts: 2
Joined: Thu Jul 07, 2011 2:45 pm

Re: [TUT] Simple InApp Billing / Payment

Postby blundell » Sun Jul 10, 2011 1:30 pm

You can use most of it without changing it, just have a quick read through it is commented were you have to change your sig
User avatar
blundell
Master Developer
Master Developer
 
Posts: 1610
Joined: Tue Nov 18, 2008 12:58 pm
Location: UK

Re: [TUT] Simple InApp Billing / Payment

Postby kishore.thorata » Mon Jul 25, 2011 12:57 pm

I am getting null pointer excretion by the below code

Code: Select all
      public void onClick(View v)
        { 
        startService(new Intent(mContext, BillingService.class));
        BillingHelper.setCompletedHandler(mTransactionHandler);
if(BillingHelper.isBillingSupported()){
            BillingHelper.requestPurchase(mContext,"android.test.purchased");
something();
}

ondestroy()
Code: Select all
@Override
   protected void onDestroy() {
      super.onDestroy();
      if(mContext!=null){
      BillingHelper.stopService();}

My aim is to call in app service only on a button click, how to do that.
Regards,
KISHORE.
User avatar
kishore.thorata
Freshman
Freshman
 
Posts: 8
Joined: Wed Jun 02, 2010 7:21 am

Re: [TUT] Simple InApp Billing / Payment

Postby blundell » Mon Jul 25, 2011 1:27 pm

You cannot start the service and then request a purchase instantly.

When you start the service, there is a delay while it loads up. You need to either implement a callback when this has finished loading then do your purchase, or just start the service on activity launch, and enable the button when the service has loaded.
User avatar
blundell
Master Developer
Master Developer
 
Posts: 1610
Joined: Tue Nov 18, 2008 12:58 pm
Location: UK

Top

Re: [TUT] Simple InApp Billing / Payment

Postby kishore.thorata » Tue Aug 02, 2011 8:23 am

Thanks for the tut I have solved the above described NPE but, having trouble with getting null for mService and mContext in getPurchaseInformation() . How to solve it..
Regards,
KISHORE.
User avatar
kishore.thorata
Freshman
Freshman
 
Posts: 8
Joined: Wed Jun 02, 2010 7:21 am

Re: [TUT] Simple InApp Billing / Payment

Postby blundell » Tue Aug 02, 2011 8:34 am

If your context and service are null this means you are killing the activity, if this is your intention try using getApplicationContext() , however check the context is not used for any explicit casts.
User avatar
blundell
Master Developer
Master Developer
 
Posts: 1610
Joined: Tue Nov 18, 2008 12:58 pm
Location: UK

Re: [TUT] Simple InApp Billing / Payment

Postby zog » Fri Aug 05, 2011 9:04 am

Hi blundell!

I have implemented IAB in my games following the offical docs and have observed the following issue:
If you open the app, bring up the IAB dialog and close the app, the BillingService keeps running.

I haven't tried your implementation, but maybe you could verify if this is the case too, cause otherwise I'd go through your code step by step and check what you did different =)

Every app I've seen in the Market suffers from it (~5 different).
Googling didn't bring much up except maybe http://comments.gmane.org/gmane.comp.ha ... vel/156716

Now it appears to be ok except for recently, my device crashed with
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. W/ActivityManager(   96): Timeout executing service: ServiceRecord{46667fe8 com.android.vending/.billing.MarketBillingService}
  2. W/dalvikvm(   96): threadid=8: thread exiting with uncaught exception (group=0x400259f8)
  3. E/AndroidRuntime(   96): *** FATAL EXCEPTION IN SYSTEM PROCESS: ActivityManager
  4. E/AndroidRuntime(   96): java.lang.IllegalArgumentException: Comparison method violates its general contract!
  5. E/AndroidRuntime(   96):        at java.util.TimSort.mergeLo(TimSort.java:743)
  6. E/AndroidRuntime(   96):        at java.util.TimSort.mergeAt(TimSort.java:479)
  7. E/AndroidRuntime(   96):        at java.util.TimSort.mergeCollapse(TimSort.java:404)
  8.  
Parsed in 0.031 seconds, using GeSHi 1.0.8.4

...which I think has the following reason: the system wanted to stop the service and for some reason crashed the whole system. I'm not able to repro this error ... it just happens occasionally.


Thanks!
Christian
zog
Freshman
Freshman
 
Posts: 3
Joined: Fri Aug 05, 2011 8:54 am

Re: [TUT] Simple InApp Billing / Payment

Postby blundell » Fri Aug 05, 2011 9:31 am

Hi Christian,

The billing service continuing running is all about if you start your service as 'sticky' or just bind to it through an activity.
That crash looks ouch! But I don't think there's anything you can do about it it's within the service itself.

I'll let you see if my implementation keeps the service running ;-) that's how you learn
User avatar
blundell
Master Developer
Master Developer
 
Posts: 1610
Joined: Tue Nov 18, 2008 12:58 pm
Location: UK

Re: [TUT] Simple InApp Billing / Payment

Postby zog » Fri Aug 05, 2011 9:59 am

Thanks, that would be great!
Glancing over your code, I already see some differences in e.g. BillingService.
We use e.g.
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1.     @Override
  2.     public void onStart(Intent intent, int startId) {
  3.         if (intent != null)
  4.                 handleCommand(intent, startId);
  5.     }
Parsed in 0.031 seconds, using GeSHi 1.0.8.4


which appears to be deprecated by now... google says to use onStartCommand(Intent, int, int) instead, but I didn't see that in your code too.
zog
Freshman
Freshman
 
Posts: 3
Joined: Fri Aug 05, 2011 8:54 am

Re: [TUT] Simple InApp Billing / Payment

Postby blundell » Fri Aug 05, 2011 11:15 am

I think I have commented that you can use onStartCommand, onStart is needed to support older devices, this is standard for all services, not just the billing service. I removed the onStartCommand for tutorial simplicity, it won't have any impact on your issues.
User avatar
blundell
Master Developer
Master Developer
 
Posts: 1610
Joined: Tue Nov 18, 2008 12:58 pm
Location: UK

Re: [TUT] Simple InApp Billing / Payment

Postby zog » Sun Aug 07, 2011 4:05 pm

Hi!

Just to keep things up to date: I examined your code and noticed that you destroy things a bit different as I did.
I now use
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. activity.stopService(new Intent(activity, BillingService.class));
  2. activity = null;
Parsed in 0.034 seconds, using GeSHi 1.0.8.4

And it appears to work =)


Greets,
Christian
zog
Freshman
Freshman
 
Posts: 3
Joined: Fri Aug 05, 2011 8:54 am

Re: [TUT] Simple InApp Billing / Payment

Postby shaddowdemon » Sun Aug 07, 2011 11:36 pm

First, I want to say that this has helped me a lot! I'm new to Android development, so I found the official guide to be a bit overwhelming.

I implemented your code and have gotten it to more or less work. I'm getting a strange error though and I haven't been able to figure it out. When calling restoreTransactionInformation, it processes fine, calls confirmTransaction, which causes the market to send a RESPONSE_CODE broadcast (which is RESPONSE_OK), and then the market process crashes with the following error:

Code: Select all
08-07 18:14:31.566: WARN/dalvikvm(8030): threadid=10: thread exiting with uncaught exception (group=0x4001d7f0)
08-07 18:14:31.574: ERROR/AndroidRuntime(8030): FATAL EXCEPTION: Thread-12
08-07 18:14:31.574: ERROR/AndroidRuntime(8030): java.lang.IllegalArgumentException: Type mismatch type:null tag:1
08-07 18:14:31.574: ERROR/AndroidRuntime(8030):     at com.google.common.io.protocol.ProtoBuf.assertTypeMatch(ProtoBuf.java:896)
08-07 18:14:31.574: ERROR/AndroidRuntime(8030):     at com.google.common.io.protocol.ProtoBuf.insertObject(ProtoBuf.java:1021)
08-07 18:14:31.574: ERROR/AndroidRuntime(8030):     at com.google.common.io.protocol.ProtoBuf.insertString(ProtoBuf.java:827)
08-07 18:14:31.574: ERROR/AndroidRuntime(8030):     at com.google.common.io.protocol.ProtoBuf.addString(ProtoBuf.java:173)
08-07 18:14:31.574: ERROR/AndroidRuntime(8030):     at com.android.vending.model.AckNotificationsRequest.addNotificationId(AckNotificationsRequest.java:40)
08-07 18:14:31.574: ERROR/AndroidRuntime(8030):     at com.android.vending.util.AlarmService$AsynchAckNotifications.doRequest(AlarmService.java:274)
08-07 18:14:31.574: ERROR/AndroidRuntime(8030):     at com.android.vending.billing.MarketBillingService$AsynchInAppAckNotifications.doRequest(MarketBillingService.java:640)
08-07 18:14:31.574: ERROR/AndroidRuntime(8030):     at com.android.vending.AsynchRequestRunner$RequestRunnable.run(AsynchRequestRunner.java:37)
08-07 18:14:31.574: ERROR/AndroidRuntime(8030):     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1068)
08-07 18:14:31.574: ERROR/AndroidRuntime(8030):     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:561)
08-07 18:14:31.574: ERROR/AndroidRuntime(8030):     at java.lang.Thread.run(Thread.java:1096)
08-07 18:14:31.574: ERROR/AndroidRuntime(8030):     at com.android.vending.AsynchRequestRunner$VendingThreadFactory$VendingFactoryThread.run(AsynchRequestRunner.java:118)


I don't know what the error means or what could cause it... I do know that if the CONFIRM_NOTIFICATIONS request isn't sent though, the error doesn't happen. Oh and I'm running Android 2.2.
shaddowdemon
Freshman
Freshman
 
Posts: 2
Joined: Sun Aug 07, 2011 9:25 pm

Re: [TUT] Simple InApp Billing / Payment

Postby shaddowdemon » Mon Aug 08, 2011 10:45 pm

Ah, I think I found the problem. It appears that the information sent to the receiver with a RESTORE_TRANSACTIONS request does not need to have a confirm message sent, so a notification ID is not contained in the data retrieved from the PURCHASE_STATE_CHANGED bundle. As it is now, the code will send a null notification ID to the market when restoreTransactionInformation() is called, causing a type error and crashing it.

Enclosing the confirmTransaction() body in an if statement will prevent it from sending null notification id COMFIRM_NOTIFICATIONS requests, but still allow it to confirm purchases. For example,

Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. protected static void confirmTransaction(String[] notifyIds) {
  2.         if (amIDead()) {
  3.                 return;
  4.         }
  5.         if (notifyIds[0] != null) {
  6.                 Log.i(TAG, "confirmTransaction()");
  7.                 Bundle request = makeRequestBundle("CONFIRM_NOTIFICATIONS");
  8.                 request.putStringArray("NOTIFY_IDS", notifyIds);
  9.                 Log.i(TAG, "Notify ID: " + notifyIds[0]);
  10.                 try {
  11.                         Bundle response = mService.sendBillingRequest(request);
  12.  
  13.                         //The REQUEST_ID key provides you with a unique request identifier for the request
  14.                         Long requestIndentifier         = (Long) response.get("REQUEST_ID");
  15.                         Log.i(TAG, "current request is:" + requestIndentifier);
  16.                                
  17.                         //The RESPONSE_CODE key provides you with the status of the request
  18.                         Integer responseCodeIndex       = (Integer) response.get("RESPONSE_CODE");
  19.                         Consts.ResponseCode responseCode = Consts.ResponseCode.valueOf(responseCodeIndex);
  20.                        
  21.                         Log.i(TAG, "CONFIRM_NOTIFICATIONS Sync Response code: "+responseCode.toString());
  22.                 } catch (RemoteException e) {
  23.                         Log.e(TAG, "Failed, internet error maybe", e);
  24.                         Log.e(TAG, "Billing supported: " + isBillingSupported());
  25.                 }
  26.         }
  27. }
Parsed in 0.040 seconds, using GeSHi 1.0.8.4


source: http://developer.android.com/guide/mark ... ion-notify

Relevant Quote: "The RESTORE_TRANSACTIONS request type also triggers a PURCHASE_STATE_CHANGED broadcast intent, which contains the same type of transaction information that is sent during a purchase request, although you do not need to respond to this intent with a CONFIRM_NOTIFICATIONS message."
shaddowdemon
Freshman
Freshman
 
Posts: 2
Joined: Sun Aug 07, 2011 9:25 pm

Top
PreviousNext

Return to Advanced Tutorials

Who is online

Users browsing this forum: Google Feedfetcher and 9 guests