This last weekend, I decided to add in-app billing to an app that's already shipping for Android, and I ran into a couple of hiccups that I think are worth documenting here to save others some time/pain. Overall, I think the Android folks learnt from some of the pitfalls that early developers hit with in-app payments on iOS and worked to fix those. The documentation is a lot clearer and precise compared to where iOS was a year ago. Android Market also has a nifty static test/response facility which makes it easy to test code without worrying about external influences. iOS was desperately lacking something of this sort (not sure if it's better now) - I even wrote a dummy implementation of the iOS in-app payment API and the different response conditions to let me test my code in an emulator, which was really helpful. I'm glad Android got this right (still no testing in an emulator though, which is a bummer because of the inability to test with different Android OS versions).
At a high level, the in-app billing protocol on Android is extremely chatty (see the diagrams on this page). It seems particularly so when compared to PayPal's rival offering. PayPal's in-app billing module handles payment using
onActivityResultmethods which can be used for communicating between child/parent activities. This is very similar to how Facebook's Android SDK handles single sign on. That model is extremely simple to understand and implement for developers - you could probably have it coded up and tested faster than you can finish reading this blog post. I think part of this chattiness is to ensure a higher level of security and also to handle managed purchases, which are both likely harder to do using PayPal's approach. I assume they had good reason to make it as chatty as it is now, but my gut says that Google loses out on a lot of developers because of this apparent complexity. Having said that, the sample application Google provides does a really good job of illustrating the various communications that need to occur, so studying that code makes the chattiness easier to understand (for some reason, code registers more easily in my brain than verbose documentation - good code and good documentation together are very rare, and Android seems to have gotten this right - kudos!)
One of the biggest red flags with using Android's in-app billing, however, is the development teams non-responsiveness to critical bugs. This issue, marked critical and accepted, talks about transactions failing 4-6% of the time, and has been active for over two months without an owner being assigned. An equally disturbing issue with unacceptably long latency when handling authorization has been open for almost two months without any comment from Google or even an owner being assigned. In fact, browsing the issues list certainly doesn't inspire confidence in the platform. It would be a big mistake by Google to not take these issues seriously. In my case, I'm certainly debating the merit of jumping into this as an early adopter.
Some other notes about implementing in-app billing on Android:
- It sounds obvious in hindsight, but you need to make sure that your application is signed with the release key before testing in-app billing, even the static response stuff. Developer's aren't used to doing this while debugging, so it's worth calling out in the documentation.
- If you want valid signatures for the JSON responses as suggested by the table here, the "debuggable" attribute in the app manifest should be set to false, even if you're using a release-key-signed APK and static responses. I was a little annoyed by this un-documented restriction because it basically meant that I had to resort to using logging as the only real means of debugging my code. If there is indeed some way to debug this using a debugger (and yet receive valid signatures), it’s definitely not obvious to me. Again, not a terribly big deal once you realize that this attribute actually seems to affect signatures, but that isn't documented anywhere.
- If you're using a server to validate signatures (as you should), be aware that the public key you obtain from the Android Market profile page is a base-64 encoded string. You will almost certainly need to convert it to PEM/DER format or use the x509 certificate for it to be usable with most server openssl implementations. For instance, this command can be used to convert the base-64 encoded key into a key usable by PHP:
openssl enc -base64 -d -in publickey.base64 -A | openssl rsa -inform DER -pubin > publickey.pemAlso, if you're using the PHP function
openssl_verify, remember that
$signatureneeds to be the binary signature, not the base-64 encoded signature string that the Android Market app sends (I found out the long way).
- Unavailability of subscriptions/auto-billing is a big gap in the offering currently, but I assume support for it is coming soon, since iOS already supports it.
- I hit an issue when testing payments using carrier billing, where accepting the carrier ToS basically causes the transaction to get lost somewhere between the carrier and Android Market. I logged this bug to track the issue.
Well, I hope that the web-search spiders do their job and this post helps others out there looking at implementing in-app billing on Android. And making Google get a move on those bugs.