Press "Enter" to skip to content

Google IO 2013 InApp Billing Version 3

pGoogle IO 2013 InApp Billing Version 3 BRUNO OLIVEIRA: All right, welcome everyone.

Google IO 2013 InApp Billing Version 3

My name is Bruno Oliveira. And I work with Android Developer Relations. And were going to talk about InApp Billing Version 3. So its pretty cool. InApp Billing is actually a pretty cool thing. And every time we talk to someone about InApp Billing, we sort of expect them to go like this.

And but sometimes, in the previous versions of the API, if youve worked with InApp Billing V2, they sometimes go like that. And we really dont understand why that happens. Because if theyre all in a billing spree, its in command, right? So just to go back in time a little bit, things used to be well, things were actually pretty straightforward back then.

In V2, you would just have to make a purchase, kind of like that. And then thats done, right? Easy. Well, actually, Im just oversimplifying a little bit. You actually had to have code to handle the purchase date changes, like that.

Still, its not that much code. But then you have that case where the app could be sleeping when you got that message. So you also had to have a broadcast receiver to make sure that that didnt happen, so just broadcast receiver. Still not complicated, right?

And then, of course, the broadcast receiver couldnt really run for very long because it would get killed by the system. So its probably good practice INAUDIBLE a service, like pretty simple and straightforward service, to handle that broadcast receiver. And of course, then since you cant credit for the purchases all the time because its an expensive API call, you probably need to persist at using a database of some sort. But thats OK. Everyone loves databases.

Its SQL. And well, why does it really gets so complicated? And even this is an oversimplification because you have to encrypt the database. Make sure that the users dont tamper with it.

So why does it get so complicated with InApp Billing in the previous versions? Well, lets start with a simple case. So the user thats my drawing of a user.

Again, its probably fortunate that I write code better than I draw pictures. But then the user buys something. And that gets delivered to the app. No problem there, right? So standard.

But what happens if the application is not there to receive the package, because applications on Android sometimes have other stuff to do? So sometimes apps go to sleep on Android. They take naps.

So what if the app is sleeping? Then a different component has to pick up the package. And then that component has to take care of delivering the item to the application when it finally wakes up. And thats when the problems might happen because that component right there could end up losing your package.

As you can see from this diagram in V2, the developer had to write many components that had to work together to ensure that the users purchase went to the right place. And of course, it can get a little complicated. In comparison, this is what the V3 diagram looks like.

Actually, let me use a little bit more of the slide. No, lets make it a full slide. The diagram for V3 has seven subcomponents.

Were going to spend the next several minutes discussing each component and subcomponent in detail. Actually, just kidding. This is the actual diagram. So the INAUDIBLE in V3, apart from glass boxes, is that API calls are now synchronous.

This means that your application gets a response right away. So if I want to and its also much more straightforward to think about too. So if I want to buy something like 50 gold coins, all I have to do is make a request that looks like buy 50 gold coins. Then if Google Play thinks a purchase is OK, its going to return something thats pretty intuitive, like say OK. And you get that response right away.

If you worked with V2 before, youre probably going to remember that our advice, the advice we gave every time is that listing items, which we call restoring purchases, was a very, very expensive operation. Nobody could afford to do that a whole bunch of times. So you couldnt just get away with calling it every single time the app launched. You had to somehow keep a clientside storage to know which items either owns. So thats no longer the case because in V3, Google Play implements a clientside cache and takes care of keeping that cache in sync with the server.

So whenever you make your query to the API, youre going to hit that clientside cache instead of incurring that cost of a network round trip. So you can call it as many times as you want. So listing the users items has actually become a pretty cheap operation.

And you can do that as often as you need. For example, you can do that every time the application starts, which we figure is a pretty natural place where you might want to ask yourself, what items does this user own? All right, so I probably sound like Im trying to sell you something, right?

So if youre a developer, I mean, if youre in this room, youve probably grown a healthy mistrust over the years of people who stand on a stage like me and then dont show you any actual code. So lets stop with the sales and talk about something thats entirely different. Lets talk about selling stuff. So before you can make V3 API calls, you have to check that its actually supported.

You can do that by calling the isBillingSupported API call. The good news is that InApp Billing is actually supported on a whole variety of devices, so running Froyo and above and a recent version of the Play Store. And there was actually more than 90 on the day that we launched, which was back a few months ago.

And right now, of course, theres much more than that. So you dont have to be too worried about that. Now how do you go ahead and get a list of the items that the user owns?

Well, we just call the getPurchases API call. And remember that this call is actually pretty cheap on V3. Notice also that you get the results right away right there.

So theres no funny call backs or state management, no funny business you have to implement to get the result right away. All right, so now this is very important. Its that single moment your application has been waiting for ever since the user launched it.

Its that profound moment in modern technology thats very hard to explain to older generations, where the user actually realizes that the virtual item or service that youre offering them is so valuable and they like it so much that they are actually willing to give you real money for it. Thats awesome, right? So its at that singular moment you have something thats really, really, really, really very valuable.

And Im not talking about those 0.99 that you just made. What you have on that moment is the users trust. So they give you their money. And they expect to get something in return.

And nothing is more valuable to an application than that. So what happens if at that critical moment you take the users money and then you lose a purchase? Thats going to be a very bad user experience. So again, theyve paid for something and didnt get it. The least you can expect after that is a pretty bad review.

And of course, if youre unlucky, it may be very, very much worse than that, as this very reliable data that I in no way made up clearly demonstrates. So you dont want the user to lose their purchase ever, which is why one of the central points in V3 was to make it easier to do exactly that. So it was to make it easier not to lose purchases. One of the ways we do that is by making all items managed, which means that Google Play keeps track of the ownership of those items for you. So going back to code, how do you write this reliable purchase flow?

First of all, you launch the purchase screen. And that can be done by calling getBuyIntent. So thats going to get to a readytouse intent that you can then fire, and thats going to bring you the purchase screen. And what does that look like?

So I have a game called Nostalgic Racer. And then I have 1, 000 points, 1, 000 nostalgic points, if you will, and that the user can purchase. So notice that this dialogue is pretty much its simple and to the point. And the user doesnt lose context, because its overlaid on top of the game.

This is an improvement we launched a few months ago. So and theres really only one button in that UI. And it really says, click me.

Right? And so theres no context lost, no confusion. And the result of the dialogue when the user clicks Buy is that youre going to get the results through an activity result.

So what do you do at the point? Well, at that point, you have the purchase result. So you have the response code. You have the purchase data and the purchase signature. Everything is right there.

So when I say purchase data, what I mean is just this J as an object that looks kind of like that. So you have the order ID. You have the package name that bought the product.

You have the product ID, which is also known as your SKU. You have the purchase time, the purchase date, the developer payload. Thats something very important that were going to talk about next. And you have the purchase token, which is a long, alphanumeric string that identifies that particular purchase. So thats pretty much all there is for a simple application.

So on startup, you call getPurchases to figure out what the user owns. And then when the user wants to purchase something, you call getBuyIntent. That gives you a readytouse intent that you can fire.

When you fire that intent, you get the purchase flow. And then onActivityResult, you handle that purchase. Notice that its actually pretty hard to lose a purchase that way.

You would actually have to make an effort to lose a purchase this way, because even if the unthinkable happens and, say, your application has a bug, what happens, if your application crashes right after the purchase and never gets the onActivityResult, thats not a problem because then the next time the user is going to start the app, youre going to call getPurchases. And youre going to realize that the items there. So the user has not lost the purchase. All right, so phones are funny things, actually. So they have a tendency to fall into all sorts of liquids, like from sea to margaritas.

So they have a tendency. They have an attraction to liquids that science doesnt explain. What also happens is that phones tend to fall. But as you know, contrary to popular belief, falling doesnt really do anything to a phone. The problem is when the phone collides with something massive, like say a planet.

So the planet tends to win in that case. But dont worry. Thats OK, because the beauty of managed InApp purchases is that theyre like diamonds.

Theyre forever. So even if the user deletes the app or even if they switch to a different device, its OK because the purchase is still going to be there. And they havent lost it. So this is good for things that the user should only purchase once, like for instance, a premium upgrade even if the user switches phones, you dont want them to lose that an adfree upgrade, special items that the user can never lose, or even level packs, content, and so on and so forth.

So for all that, its this purchase once and use everywhere is a pretty good approach. But sometimes, of course, you dont want a purchase to be forever. You want to implement things like consumable items, like health potions and whatnot, gold coins that are put into the players wallet and then they go away, things that expires like season passes. And then you have to, of course, to purchases that are not permanent.

And this is what unmanaged item was used for in V2. But of course, there are no unmanaged items in V3. So how do you do that? Well, this is why we have the consumption APIs on V3. So to understand how this works, so somewhere in Google Play so theres a building where Google Play works.

And in the basement of that building, every single user at Google has a box. And inside that box, with my name on it, are all my virtual items. I know. Ive been there.

Ive seen that box. When I buy a cool item, what happens is that somebody goes in there and puts the cool item inside the box that has my name on it. And from that point on, I know I own the cool item. When I subsequently ask, what items does Bruno own, through an API call, it returns well, Bruno owns a cool item. Then what happens when I tell the API to consume cool item?

What happens is that the item goes up in flames, just like that. And then, if I ask what items does Bruno own, I dont own anything at all. So consumption is the opposite of a purchase. When you consume, the item goes away.

As far as code goes, this is how you consume an item. We would just call the consumePurchase on the API. And then you give it the purchase token associated with that item. Remember that the purchase token is the same one that you got when you got the getPurchases call. And then thats the purchase token field on that JSON.

And then, well, then you call that. And the items going to be consumed. Now, there is one decision that youre going to have to make, which is when to consume something. So its up to you how to decide how to use the consumption API.

The contract is that when you consume something, it goes away. So were going to talk about two of the most used methods when youre using the consumption API. First of all, maybe you want to consume the item when its actually used because thats, by far, the most intuitive way to consume an item, right?

Then you dont need to manage the items yourself. Now the second approach, which is pretty popular, is to consume it immediately upon purchase. In that case, your app takes care of managing the users inventory.

So you might call that inventory a wallet, a purse, a bag, account, or any other name. But you will manage the users inventory in that case. So to explain method one quickly so lets give an example. So again, thats me. Its a stick figure character of me, anyway, somewhat slimmer.

And those are the items that I own in Google Play. So right now, its an empty box, right? Now, as we all know, the world out there is a pretty dangerous place, especially for stick figure characters like myself.

So I decided before I go out into the world, Im going to buy a health potion. So I buy a health potion. And when I do that, it appears in my inventory. Also like everybody else, I walk around with a head point bar on top of my head that tells me what my life points are. So now I have a potion that I bought.

And its on my box in Google Play. And I own that potion. Now I go out, and I venture into the wild lands of bugs. And then I battle bugs, and I write code. Pretty soon I realize that Im starting to get low on life points.

And then I decide to consume the potion. Thats when your application would call the consumption API to make that potion disappear and then restore my life point bar back to what it was before. So this is consumption upon usage. Now, thats a perfectly good method, except that it has one fundamental limitation.

And that has to do with how Google Play thinks about numbers. So Google Play, at least as far as InApp purchases are concerned, only really knows two numbers. And they are 0 and 1. So if the world out there is really, really dangerous, and I think Im going to need more than one healing potion out there to battle bugs, then Im going to want to buy two potions. But what happens if I try to buy a potion when I already have one? So Google Play is going to look at me, and its going to see that I have a potion right there.

And its going to say, that makes no sense. You already have a potion. Why are you trying to buy a second one? So clearly, this approach doesnt work if you want to have more than one item of each kind, which is why method two might come in handy, which is consuming upon purchase.

In this case, your application is actually responsible for managing the users inventory. So notice my excellent INAUDIBLE of a plastic bag right there, which is my clientside inventory or serviceside. Either way, its managed by my application.

So I buy a potion. And now the potion exists in my Google Play inventory. Then what I do is, regardless of when the user is going to consume this, I consume the potion right away through the API.

And I credit that to my ingame inventory. And then if the user buys a second one, thats no problem because Google Play doesnt know about a potion anymore. So I can buy a second potion and consume it right away and credit it to my bag.

So now I have two potions in my inventory. If youre using method two, its very important not only to consume upon purchase, but also upon startup. And then on startup, you check if there any outstanding items that you should be consumed. This is going to be necessary, for example, if your application crashed before it consumed the item.

So suppose the user made the purchase. The purchase went through. But then your application crashed. Then when your application recovers and starts again, youre going to make sure that on startup you check if theres any item in the users inventory that should have been consumed, but was not. So in our example, what Im going to do on startup is call getPurchases.

And if I realize that I own a potion that should have been consumed, Im going to consume it right away and then put it into the players inventory. You dont even have to notify the player that youre actually doing that. You can do that in the background.

So summarizing what we have so far on startup, you would call getPurchases. Then if I notice that there is a potion there that should have been consumed before, I consume it. When the user wants to make a purchase, I call getBuyIntent and then launch that intent to get the purchase flow. And thats the window that prompts the user to buy something. Then when I get the onActivityResult call back, what I do is I check if the purchase was successful.

And then I consume the purchase if the purchase was successful. And then when I get the consume call back, I see if the consume was successful. If the consume was successful, then I finally add the potion to the inventory.

Its very important to wait for the last part before you actually credit the item to the users inventory because what may happen is that remember that the Google Play inventory is the same for every device. So its per user and not per device. So if I own a potion on one device, then I own a potion on all devices. So when you are going to consume that potion, you should make sure that you only created the potion once.

So if you try to consume the same potion from several devices, only one of those consumptions is going to succeed. So thats guaranteed. So this means you should only credit the potion once its been successfully consumed.

All right? So InApp Billing V3 also brings a longanticipated feature that developers have been really asking for a long time, which is the ability to query for a products details from code, like for instance, title, description, and price. So if you take a look at the API, youre going to find this method call, which is called getSkuDetails.

Its actually pretty straightforward. You just specify the list of SKUs that you want to get information about. And when you make that call, the API returns the information in a bundle. And that bundle kind of looks like this. So it has your products ID, which is the SKU, the type, whether its in a product or a subscription, the price, the title, description, so on and so forth.

One thing thats pretty nice about this is that the price is actually returned in a way thats formatted according to the users locale. So its going to look right to the user when you display it on the screen. However, one thing to be careful about is that price is only formatted for display and not for parsing.

So dont try to use that as a number. Dont try to add two together. This is just a number thats formatted for display only. And you can show it to the user.

Now lets talk about subscriptions. So in V3, thats actually pretty simple too. If you have used V2, youll remember that there was a whole bunch of messages and call backs and broadcast receivers that you had to write to implement and to know the status of a particular subscription at any given time.

And there were asynchronous call backs that you had to implement. But in V3, its much easier. They are actually just like items. Theyre much simpler. To check if substitutions are supported, you can call isBillingSupported API call.

So its the same as before, except you pass subs instead of inapp. And then thats going to return whether or not subscription are supported on that device. So its important to make that check. Now launching the purchase flow for a subscription is not really very different from launching the purchase flow for a regular item. So we just use getBuyIntent.

But except that instead of saying inapp, you say subs. And then you go past the item type, and then get an intent. You can launch the intent.

And that brings the purchase window, just like did before. One thing to be careful about is that subscriptions cant be consumed. So you cannot use the consumption API on a subscription.

If the effect that youre trying to accomplish is to cancel a subscription, then this is another way to do. Youre going to have to do that through the serverside, as were going to see next. All right, so remember how I said that in V2 its actually pretty difficult to know whats the state of a subscription? So in V3, its actually pretty easy because you just call getPurchases. When you call getPurchases with the item type set to subs, its going to return all the subscriptions that are actually active right now.

What I mean by actually active is that while subscriptions are either in the active state or in the trial state the trial state that the user can have before buying the subscription those are going to appear in your getPurchases results. Now once a subscription expires, youre not going to get any notification of that. But then the next time you call getPurchases which, remember, became a pretty cheap call, so every time your application starts, you can call getPurchases. So the very next time you call getPurchases, whats going to happen is that the expired subscription is no longer going to be there.

So it does not appear on getPurchases. So your whole logic can be, if I see the subscription in getPurchases, then I provide the content. If I dont see the subscription in getPurchases, then I dont provide the content. Its much easier logic than trying to manage whats a subscription state at any given point. So how about canceled subscriptions?

Well, we do the right thing for canceled subscriptions as well, which is canceled subscriptions are actually going to appear in getPurchases until the end of the billing period that the user has paid for. So after that expires, they cease to appear. So you may see canceled subscriptions in getPurchases.

And that may happen because the user has paid for the billing period, but they have canceled it. So on the next billing period, that subscriptions going to expire. So as far as the developers concerned, all they have to do is check if its in getPurchases.

If it is, you deliver the content. If its not, you dont deliver. Now remember that Google Play actually now has a local cache on the client, which means that when a subscription expires, it might actually take some time for it to disappear from getPurchases.

Usually that doesnt really take more than 24 hours, of course. So that cache is refreshed every 24 hours at most. So you might actually see a subscription there that has already expired. But then, hopefully, thats only going to last 24 hours or so. Thats usually not a big deal.

All right? So when youre making any API calls, its very important to be careful about the UI thread. So the UI threads something thats very delicate. Why?

Because if you block the UI thread, your application is going to stop responding, of course. And in the Android world, I mean, actually in any mobile application, thats not just something thats frowned upon. The system actually punishes your app for that.

And the punishment, of course, this is very, very friendly dialogue box. So if you dont want the users to see this dialogue box, because users just absolutely love that dialogue box, then you shouldnt ever block the UI thread by calling INAUDIBLE that take a long time to return. Particularly in the InApp Billing API, the safe ones to call are isBillingSupported and getBuyIntent. Those two you can call safely from the UI thread because theyre returned right away.

Now the other three that we talked about are not safe to call from the UI thread because they might actually take a while to execute. So if youre calling getPurchases, consumePurchase, getSkuDetails, remember that they might actually take a while to execute. So you definitely do not want to call them from the UI thread in order not to risk a application not responding error. So always call them from a separate thread, async task, whatever else.

But whatever you do, dont block the UI thread while waiting for that response. If you download the sample thats called Trivial Drive, it implements that for you because it has asynchronous wrappers so that you can actually call them from the UI thread and get a call back when they are done. Now many developers dont know this.

But theres actually a serverside API that allows you to check for subscriptions. The way it works is this API allows you to take a particular subscription and then query whether or not its valid, when its going to expire, and whether or not its going to renew itself automatically. It also allows you to cancel an existing subscription from the server side. So how do you go ahead and specify a particular subscription? Well, remember the purchase data on the client side when you call getPurchases?

So one of the fields in that is called purchaseToken. So that identifies that particular subscription for that particular user. So thats the string that you need to use on the server side to call that API.

So this is what I know of what a sample API call looks like. Its basically REST. And Im calling the state of that particular subscription. So I pass it to you.

Your package name goes there. Your subscription ID, so this is the SKU of the subscription goes there. And then thats the token that you get from the clientside.

The response looks something like this. And it gives you when the subscription started, when its going to expire, and then whether or not its going to renew automatically. If you want to know more about this API, theres that URL right there. So theres the full specification of that API.

It also allows you to cancel a subscription from the server side, which might be useful for your application. Now, next, lets talk about a very important topic, which is security. Now security is important because, believe it or not, there are some shady characters out there in the interwebs who might want to take your stuff without paying.

I know, its shocking. And they are out there on the web, on the loose. So its very important to implement some measure of security in applications.

So I dont really know what the technical term is. But Im going to say theyre pirates, mostly because we spent a really long time drawing this character, and I wanted to use it in a presentation. So actually, I think theyre called crackers.

But lets go with pirates. So anyway, anytime you see a purchase result in your application, you should always ask yourself if you should trust the purchase or not. Of course, a pirates is going to be pirates spend all day being a pirate.

And their job is to convince you that a particular purchase is correct. And of course, your job is to detect that lie and see that that purchase is a fake. So how do you go ahead and do that? Well, depending on your particular type of app and market, piracy might be a small problem, might be a big problem.

Thats going to depend on your type of app. But you should always think in terms of risk model that takes into account several variables, such as the target audience, the items value, the likelihood that somebody would make a fake purchase, the technical difficulty in making a purchase. And based on that, make a decision on how much security to implement. Of course, in the best case scenario, we implement all possible security.

But then you might have to balance that against engineering time and so on and so forth. So its important to be conscious of that. Of course, nobody can stop piracy all together. I would be lying to you if I said that I had a method to stop piracy. But of course, you should always make life hard for piracy because thats fun.

So heres some of the defenses that you can employ to make a pirates life hard. First of all is use our developer payload, and then use signature verification, and also serverside validation. Were going to give a quick overview of each one of those. So whats this developer payload thing?

Well, developer payload is really just a fancy term for a tag. So its just a tag that gets attached to a particular purchase. Its an arbitrary string.

Anytime you launch the purchase flow, you can specify what the string is. Its just a string that gets attached to the purchase. And then every single time you credit for that purchase and you get that purchase, that strings going to be there. Now, of course, you can write anything into it. But of course, one of the most useful applications of this is to identify the owner of a particular purchase.

Why do you want to identify the owner of a particular purchase? Because then it makes it very hard for somebody to take the purchase data and then replay it into s different device. So again, thats me, the stick figure, of course. Like everyone else I mean, its a scientific fact.

Its been scientifically proven that everyone, everyone has an evil twin somewhere. Now this is Onurb, my evil twin. He is not nearly as honest as I am. So last week, he picked up my device and did a database dump of the items that I had and then replayed them on his device, hoping to get some of my items for free.

So of course, if your application is using developer payload, this is whats going to happen. So Onurb, my evil twin, is going to run your app. And then youre going to check what items does Onurb own.

And youre going to see this purchase. Do you see anything suspicious at all about this purchase? Well, of course.

The developer payload says it belongs to Bruno. But its Onurb thats running the app. Of course, on a real application, you would not use first names because some people have evil twins that have the same first name.

So you would not use names, but some unique ID, like for instance, the Google ID or something like that. Also its actually pretty hard to fake that signature, because every purchase comes signed from the server. So its not actually trivial just to change that purchase. So speaking about signature verification, well, what is this thing about signature verification?

Well, every application has a public key and a private key. The private key never leaves Google. So the private key is only known to Google. And you know the public key for your application.

What this means is that whenever somebody signs something with your private key and that, of course, by definition, has to be Google because we are the only ones that have the private key, then you can use the public key for your app to verify that signature to know that we signed it. So Google Play signs every single purchase that goes through Google Play gets signed with your applications private key, which means that, when you get a purchase on your application, you should use your applications public key to check that the signature matches. If it does not, its a fake. Its not actually difficult to implement signature verification.

But if you dont want to implement that, thats actually available in our sample. So Trivial Drive has a helper class that does all that signature verification for you. So you dont even have to implement that. Now, all right, even though clientside signature verification is pretty cool, right?

But dont think that clientside security alone is going to be enough for your app. That would be a mistake because regardless of how difficult you make things, the reality is that phones can be hacked. So you should definitely secure the server side as well.

So when we say serverside verification, what we mean is that on the server side, you should check the signature again just to make sure that the client does not compromise. And then one cool thing you can do on the server, which you cant do on the client, is that you can check the order number because the server is seeing every single purchase that comes from every single person. So every purchase comes with an order number.

And they should be unique. So if you ever see a second purchase with the same number as a purchase that youve already provisioned before, then you know that that second purchase is a fake. So you should always check the order number and dedup it. Also, if youre doing this, make sure to secure the handshake because Ive seen pretty sad stories of developers that spent countless man hours devising this perfect serverside security system. And then their handshake was like a boolean call.

It was like a REST call that returned to boolean, saying true, you are validated or not. And then, of course, that can be easily circumvented with a man in the middle attack. So make sure that the handshake is secure if youre going through the trouble of implementing a serverside security like that. Also make sure that the handshake between the server and the client is secure and not triggered to break. Now to give a summary of the security methods that we talked about.

Of course, you are free not to do anything. If you dont do anything, then youre pretty much vulnerable to any attack. Maybe for your application thats not going to matter. But then you should probably just add at least clientside security because if you at least add clientside signature verification, thats actually very easy to do because its implemented for you. Its available in the sample.

Its just a matter of copying and pasting that. So if you add clientside signature verification, youre going to be protected against man in the middle attacks. So youre going to be protected against everyones evil twin who tries to replay a purchase on a different device.

Now if you want to go the extra mile and then add a unique developer payload, of course, you are also protected against the more elaborate forms of purchase replay. And next, if you want to be really secure, you should, of course, implement serverside signature verification. The serverside signature verifications going to protect you even in the case that the clients phone is hacked, and then the framework has been compromised. So definitely think about implementing serverside security. Well, so overall, its important to approach the problem of piracy in a very rational way.

And that means dont panic and implement methods that are known to be effective. So at least as far as the InApp Billing platforms concerned, these are the three that we talked about. And definitely they are the ones that you should have in mind because theyre very easy to implement so developer payload that identifies the user of course, then signature verification, and also doing serverside validation.

And the last topic for today, its something that developers have been asking us for a long time. So Im actually glad that this launched. So and this is the InApp Billing sandbox. So whats the sandbox thing? Well, if you remember how things used to be, when you wanted to test to make sure that your InApp Billing implementation was working right, you essentially had two choices when testing InApp purchase.

You could just use the test SKUs, the purchased and canceled SKUs, which are, of course, fake product codes. And they always return a given purchase result. So you could, of course, use that. And those are, of course, mock products with a mock purchase flow. They dont actually go through the server.

And then they get a mock result. Of course, if you were not satisfied with that and, of course, if you wanted to do something thats closer to production, you could use that. You could use a test account.

And of course, if you list somebody as a test account, the only privilege they used to have is that they could make purchases from an application that was not yet published. But you had to use real money, had to use a real credit card, has to use a real purchase flow. And then you would actually get charged for that. Of course, you could revert the charge by refunding it. But then maybe the banks not going to be happy and so on and so forth.

But its just very complicated. So with InApp Billing sandbox, you can now test purchases with the real products, using the actual real purchase flow, with a real credit card. So everything is as real as possible, except that that last step, when your credit card is about to be charged, that doesnt happen. So thats the only part thats mock.

But thats the only part that doesnt happen is you dont get charged. But otherwise, the whole flow is actually real. So how do you go ahead and set this up? To enable that, you simply add some test account to the list of test accounts in the publishers site.

So this is the Android publisher site. You go to Account Details. Then you add a list of test accounts over there, so some Gmail accounts that you want to test the app with. So apart from those accounts apart from being able to purchase from your unpublished app, whats going to happen when you try to publish with any of those accounts is that youre going to see a screen just like this.

So do you notice any difference from the screen that we saw before? Its exactly the same one, except theres a warning saying, this is a test purchase and you wont actually be charged. But everything else is going to work exactly in the same way as a real purchase would.

So this means that you can test your InApp purchase in an environment that is pretty much identical to the real life production system. But you wont actually be charged. Of course, if you want to see the InApp Billing Version 3 code in practice, we have a sample called Trivial Drive. So its an exciting driving game that I wrote.

So you get burn fuel and then buy more fuel. Its kind of like the experience of having a car in real life. And its available through the SDK manager.

And its also available through the Google code site. I recommend that you get the code directly from Google code site because its more uptodate there. And pretty soon, were going to launch an update to that app thats going to include selfdriving cars. So summarizing, we talked about the most challenging points of InApp Billing V2. We talked about how InApp Billing V3 was designed to address those points and make things much easier for developers.

We talked about subscriptions. We talked about new API features, such as consumption. We talked about the new product details API feature. Then we talked about the server API and gave some pointers on security best practices. And we also presented IAB sandbox, which makes it much easier to test your apps in a real environment.

So the reason we are improving the API constantly and adding these new features is we are always striving to improve the developer experience because we know that if we give you a good experience as a developer, you can focus on what makes your apps great. So you can make a better experience for your users, which is everybodys final goal. So I hope that the tips that I gave you are useful in that respect.

And I thank you very much for coming to this session. If you have any feedback, there is the rate this session poster over there. On previous IOs, I know that we had real life tomatoes you could throw on stage. But that was pretty messy.

So if you want to give your feedback, just scan that QR code over there or use the Google IO app to give your feedback. So thank you very much. APPLAUSE Google IO 2013 InApp Billing Version 3 BRUNO OLIVEIRA: All right, welcome everyone.

Google IO 2013 InApp Billing Version 3

My name is Bruno Oliveira. And I work with Android Developer Relations. And were going to talk about InApp Billing Version 3. So its pretty cool. InApp Billing is actually a pretty cool thing. And every time we talk to someone about InApp Billing, we sort of expect them to go like this.

And but sometimes, in the previous versions of the API, if youve worked with InApp Billing V2, they sometimes go like that. And we really dont understand why that happens. Because if theyre all in a billing spree, its in command, right? So just to go back in time a little bit, things used to be well, things were actually pretty straightforward back then.

In V2, you would just have to make a purchase, kind of like that. And then thats done, right? Easy. Well, actually, Im just oversimplifying a little bit.

You actually had to have code to handle the purchase date changes, like that. Still, its not that much code. But then you have that case where the app could be sleeping when you got that message. So you also had to have a broadcast receiver to make sure that that didnt happen, so just broadcast receiver. Still not complicated, right?

And then, of course, the broadcast receiver couldnt really run for very long because it would get killed by the system. So its probably good practice INAUDIBLE a service, like pretty simple and straightforward service, to handle that broadcast receiver. And of course, then since you cant credit for the purchases all the time because its an expensive API call, you probably need to persist at using a database of some sort. But thats OK. Everyone loves databases.

Its SQL. And well, why does it really gets so complicated? And even this is an oversimplification because you have to encrypt the database. Make sure that the users dont tamper with it.

So why does it get so complicated with InApp Billing in the previous versions? Well, lets start with a simple case. So the user thats my drawing of a user. Again, its probably fortunate that I write code better than I draw pictures. But then the user buys something.

And that gets delivered to the app. No problem there, right? So standard. But what happens if the application is not there to receive the package, because applications on Android sometimes have other stuff to do? So sometimes apps go to sleep on Android.

They take naps. So what if the app is sleeping? Then a different component has to pick up the package.

And then that component has to take care of delivering the item to the application when it finally wakes up. And thats when the problems might happen because that component right there could end up losing your package. As you can see from this diagram in V2, the developer had to write many components that had to work together to ensure that the users purchase went to the right place. And of course, it can get a little complicated. In comparison, this is what the V3 diagram looks like.

Actually, let me use a little bit more of the slide. No, lets make it a full slide. The diagram for V3 has seven subcomponents. Were going to spend the next several minutes discussing each component and subcomponent in detail.

Actually, just kidding. This is the actual diagram. So the INAUDIBLE in V3, apart from glass boxes, is that API calls are now synchronous.

This means that your application gets a response right away. So if I want to and its also much more straightforward to think about too. So if I want to buy something like 50 gold coins, all I have to do is make a request that looks like buy 50 gold coins.

Then if Google Play thinks a purchase is OK, its going to return something thats pretty intuitive, like say OK. And you get that response right away. If you worked with V2 before, youre probably going to remember that our advice, the advice we gave every time is that listing items, which we call restoring purchases, was a very, very expensive operation.

Nobody could afford to do that a whole bunch of times. So you couldnt just get away with calling it every single time the app launched. You had to somehow keep a clientside storage to know which items either owns. So thats no longer the case because in V3, Google Play implements a clientside cache and takes care of keeping that cache in sync with the server. So whenever you make your query to the API, youre going to hit that clientside cache instead of incurring that cost of a network round trip.

So you can call it as many times as you want. So listing the users items has actually become a pretty cheap operation. And you can do that as often as you need.

For example, you can do that every time the application starts, which we figure is a pretty natural place where you might want to ask yourself, what items does this user own? All right, so I probably sound like Im trying to sell you something, right? So if youre a developer, I mean, if youre in this room, youve probably grown a healthy mistrust over the years of people who stand on a stage like me and then dont show you any actual code. So lets stop with the sales and talk about something thats entirely different.

Lets talk about selling stuff. So before you can make V3 API calls, you have to check that its actually supported. You can do that by calling the isBillingSupported API call. The good news is that InApp Billing is actually supported on a whole variety of devices, so running Froyo and above and a recent version of the Play Store. And there was actually more than 90 on the day that we launched, which was back a few months ago.

And right now, of course, theres much more than that. So you dont have to be too worried about that. Now how do you go ahead and get a list of the items that the user owns?

Well, we just call the getPurchases API call. And remember that this call is actually pretty cheap on V3. Notice also that you get the results right away right there. So theres no funny call backs or state management, no funny business you have to implement to get the result right away. All right, so now this is very important.

Its that single moment your application has been waiting for ever since the user launched it. Its that profound moment in modern technology thats very hard to explain to older generations, where the user actually realizes that the virtual item or service that youre offering them is so valuable and they like it so much that they are actually willing to give you real money for it. Thats awesome, right? So its at that singular moment you have something thats really, really, really, really very valuable.

And Im not talking about those 0.99 that you just made. What you have on that moment is the users trust. So they give you their money. And they expect to get something in return. And nothing is more valuable to an application than that.

So what happens if at that critical moment you take the users money and then you lose a purchase? Thats going to be a very bad user experience. So again, theyve paid for something and didnt get it. The least you can expect after that is a pretty bad review.

And of course, if youre unlucky, it may be very, very much worse than that, as this very reliable data that I in no way made up clearly demonstrates. So you dont want the user to lose their purchase ever, which is why one of the central points in V3 was to make it easier to do exactly that. So it was to make it easier not to lose purchases. One of the ways we do that is by making all items managed, which means that Google Play keeps track of the ownership of those items for you.

So going back to code, how do you write this reliable purchase flow? First of all, you launch the purchase screen. And that can be done by calling getBuyIntent. So thats going to get to a readytouse intent that you can then fire, and thats going to bring you the purchase screen.

And what does that look like? So I have a game called Nostalgic Racer. And then I have 1, 000 points, 1, 000 nostalgic points, if you will, and that the user can purchase. So notice that this dialogue is pretty much its simple and to the point. And the user doesnt lose context, because its overlaid on top of the game.

This is an improvement we launched a few months ago. So and theres really only one button in that UI. And it really says, click me.

Right? And so theres no context lost, no confusion. And the result of the dialogue when the user clicks Buy is that youre going to get the results through an activity result. So what do you do at the point?

Well, at that point, you have the purchase result. So you have the response code. You have the purchase data and the purchase signature.

Everything is right there. So when I say purchase data, what I mean is just this J as an object that looks kind of like that. So you have the order ID. You have the package name that bought the product. You have the product ID, which is also known as your SKU.

You have the purchase time, the purchase date, the developer payload. Thats something very important that were going to talk about next. And you have the purchase token, which is a long, alphanumeric string that identifies that particular purchase. So thats pretty much all there is for a simple application. So on startup, you call getPurchases to figure out what the user owns.

And then when the user wants to purchase something, you call getBuyIntent. That gives you a readytouse intent that you can fire. When you fire that intent, you get the purchase flow. And then onActivityResult, you handle that purchase. Notice that its actually pretty hard to lose a purchase that way.

You would actually have to make an effort to lose a purchase this way, because even if the unthinkable happens and, say, your application has a bug, what happens, if your application crashes right after the purchase and never gets the onActivityResult, thats not a problem because then the next time the user is going to start the app, youre going to call getPurchases. And youre going to realize that the items there. So the user has not lost the purchase. All right, so phones are funny things, actually.

So they have a tendency to fall into all sorts of liquids, like from sea to margaritas. So they have a tendency. They have an attraction to liquids that science doesnt explain. What also happens is that phones tend to fall. But as you know, contrary to popular belief, falling doesnt really do anything to a phone.

The problem is when the phone collides with something massive, like say a planet. So the planet tends to win in that case. But dont worry. Thats OK, because the beauty of managed InApp purchases is that theyre like diamonds.

Theyre forever. So even if the user deletes the app or even if they switch to a different device, its OK because the purchase is still going to be there. And they havent lost it. So this is good for things that the user should only purchase once, like for instance, a premium upgrade even if the user switches phones, you dont want them to lose that an adfree upgrade, special items that the user can never lose, or even level packs, content, and so on and so forth.

So for all that, its this purchase once and use everywhere is a pretty good approach. But sometimes, of course, you dont want a purchase to be forever. You want to implement things like consumable items, like health potions and whatnot, gold coins that are put into the players wallet and then they go away, things that expires like season passes. And then you have to, of course, to purchases that are not permanent.

And this is what unmanaged item was used for in V2. But of course, there are no unmanaged items in V3. So how do you do that? Well, this is why we have the consumption APIs on V3.

So to understand how this works, so somewhere in Google Play so theres a building where Google Play works. And in the basement of that building, every single user at Google has a box. And inside that box, with my name on it, are all my virtual items. I know.

Ive been there. Ive seen that box. When I buy a cool item, what happens is that somebody goes in there and puts the cool item inside the box that has my name on it. And from that point on, I know I own the cool item. When I subsequently ask, what items does Bruno own, through an API call, it returns well, Bruno owns a cool item.

Then what happens when I tell the API to consume cool item? What happens is that the item goes up in flames, just like that. And then, if I ask what items does Bruno own, I dont own anything at all. So consumption is the opposite of a purchase.

When you consume, the item goes away. As far as code goes, this is how you consume an item. We would just call the consumePurchase on the API. And then you give it the purchase token associated with that item.

Remember that the purchase token is the same one that you got when you got the getPurchases call. And then thats the purchase token field on that JSON. And then, well, then you call that. And the items going to be consumed.

Now, there is one decision that youre going to have to make, which is when to consume something. So its up to you how to decide how to use the consumption API. The contract is that when you consume something, it goes away.

So were going to talk about two of the most used methods when youre using the consumption API. First of all, maybe you want to consume the item when its actually used because thats, by far, the most intuitive way to consume an item, right? Then you dont need to manage the items yourself. Now the second approach, which is pretty popular, is to consume it immediately upon purchase.

In that case, your app takes care of managing the users inventory. So you might call that inventory a wallet, a purse, a bag, account, or any other name. But you will manage the users inventory in that case.

So to explain method one quickly so lets give an example. So again, thats me. Its a stick figure character of me, anyway, somewhat slimmer. And those are the items that I own in Google Play. So right now, its an empty box, right?

Now, as we all know, the world out there is a pretty dangerous place, especially for stick figure characters like myself. So I decided before I go out into the world, Im going to buy a health potion. So I buy a health potion. And when I do that, it appears in my inventory.

Also like everybody else, I walk around with a head point bar on top of my head that tells me what my life points are. So now I have a potion that I bought. And its on my box in Google Play. And I own that potion. Now I go out, and I venture into the wild lands of bugs.

And then I battle bugs, and I write code. Pretty soon I realize that Im starting to get low on life points. And then I decide to consume the potion. Thats when your application would call the consumption API to make that potion disappear and then restore my life point bar back to what it was before.

So this is consumption upon usage. Now, thats a perfectly good method, except that it has one fundamental limitation. And that has to do with how Google Play thinks about numbers.

So Google Play, at least as far as InApp purchases are concerned, only really knows two numbers. And they are 0 and 1. So if the world out there is really, really dangerous, and I think Im going to need more than one healing potion out there to battle bugs, then Im going to want to buy two potions. But what happens if I try to buy a potion when I already have one?

So Google Play is going to look at me, and its going to see that I have a potion right there. And its going to say, that makes no sense. You already have a potion. Why are you trying to buy a second one? So clearly, this approach doesnt work if you want to have more than one item of each kind, which is why method two might come in handy, which is consuming upon purchase.

In this case, your application is actually responsible for managing the users inventory. So notice my excellent INAUDIBLE of a plastic bag right there, which is my clientside inventory or serviceside. Either way, its managed by my application. So I buy a potion. And now the potion exists in my Google Play inventory.

Then what I do is, regardless of when the user is going to consume this, I consume the potion right away through the API. And I credit that to my ingame inventory. And then if the user buys a second one, thats no problem because Google Play doesnt know about a potion anymore.

So I can buy a second potion and consume it right away and credit it to my bag. So now I have two potions in my inventory. If youre using method two, its very important not only to consume upon purchase, but also upon startup.

And then on startup, you check if there any outstanding items that you should be consumed. This is going to be necessary, for example, if your application crashed before it consumed the item. So suppose the user made the purchase. The purchase went through. But then your application crashed.

Then when your application recovers and starts again, youre going to make sure that on startup you check if theres any item in the users inventory that should have been consumed, but was not. So in our example, what Im going to do on startup is call getPurchases. And if I realize that I own a potion that should have been consumed, Im going to consume it right away and then put it into the players inventory. You dont even have to notify the player that youre actually doing that.

You can do that in the background. So summarizing what we have so far on startup, you would call getPurchases. Then if I notice that there is a potion there that should have been consumed before, I consume it. When the user wants to make a purchase, I call getBuyIntent and then launch that intent to get the purchase flow. And thats the window that prompts the user to buy something.

Then when I get the onActivityResult call back, what I do is I check if the purchase was successful. And then I consume the purchase if the purchase was successful. And then when I get the consume call back, I see if the consume was successful.

If the consume was successful, then I finally add the potion to the inventory. Its very important to wait for the last part before you actually credit the item to the users inventory because what may happen is that remember that the Google Play inventory is the same for every device. So its per user and not per device.

So if I own a potion on one device, then I own a potion on all devices. So when you are going to consume that potion, you should make sure that you only created the potion once. So if you try to consume the same potion from several devices, only one of those consumptions is going to succeed. So thats guaranteed. So this means you should only credit the potion once its been successfully consumed.

All right? So InApp Billing V3 also brings a longanticipated feature that developers have been really asking for a long time, which is the ability to query for a products details from code, like for instance, title, description, and price. So if you take a look at the API, youre going to find this method call, which is called getSkuDetails. Its actually pretty straightforward. You just specify the list of SKUs that you want to get information about.

And when you make that call, the API returns the information in a bundle. And that bundle kind of looks like this. So it has your products ID, which is the SKU, the type, whether its in a product or a subscription, the price, the title, description, so on and so forth.

One thing thats pretty nice about this is that the price is actually returned in a way thats formatted according to the users locale. So its going to look right to the user when you display it on the screen. However, one thing to be careful about is that price is only formatted for display and not for parsing. So dont try to use that as a number. Dont try to add two together.

This is just a number thats formatted for display only. And you can show it to the user. Now lets talk about subscriptions.

So in V3, thats actually pretty simple too. If you have used V2, youll remember that there was a whole bunch of messages and call backs and broadcast receivers that you had to write to implement and to know the status of a particular subscription at any given time. And there were asynchronous call backs that you had to implement.

But in V3, its much easier. They are actually just like items. Theyre much simpler.

To check if substitutions are supported, you can call isBillingSupported API call. So its the same as before, except you pass subs instead of inapp. And then thats going to return whether or not subscription are supported on that device. So its important to make that check.

Now launching the purchase flow for a subscription is not really very different from launching the purchase flow for a regular item. So we just use getBuyIntent. But except that instead of saying inapp, you say subs.

And then you go past the item type, and then get an intent. You can launch the intent. And that brings the purchase window, just like did before. One thing to be careful about is that subscriptions cant be consumed.

So you cannot use the consumption API on a subscription. If the effect that youre trying to accomplish is to cancel a subscription, then this is another way to do. Youre going to have to do that through the serverside, as were going to see next.

All right, so remember how I said that in V2 its actually pretty difficult to know whats the state of a subscription? So in V3, its actually pretty easy because you just call getPurchases. When you call getPurchases with the item type set to subs, its going to return all the subscriptions that are actually active right now.

What I mean by actually active is that while subscriptions are either in the active state or in the trial state the trial state that the user can have before buying the subscription those are going to appear in your getPurchases results. Now once a subscription expires, youre not going to get any notification of that. But then the next time you call getPurchases which, remember, became a pretty cheap call, so every time your application starts, you can call getPurchases. So the very next time you call getPurchases, whats going to happen is that the expired subscription is no longer going to be there. So it does not appear on getPurchases.

So your whole logic can be, if I see the subscription in getPurchases, then I provide the content. If I dont see the subscription in getPurchases, then I dont provide the content. Its much easier logic than trying to manage whats a subscription state at any given point.

So how about canceled subscriptions? Well, we do the right thing for canceled subscriptions as well, which is canceled subscriptions are actually going to appear in getPurchases until the end of the billing period that the user has paid for. So after that expires, they cease to appear.

So you may see canceled subscriptions in getPurchases. And that may happen because the user has paid for the billing period, but they have canceled it. So on the next billing period, that subscriptions going to expire. So as far as the developers concerned, all they have to do is check if its in getPurchases.

If it is, you deliver the content. If its not, you dont deliver. Now remember that Google Play actually now has a local cache on the client, which means that when a subscription expires, it might actually take some time for it to disappear from getPurchases.

Usually that doesnt really take more than 24 hours, of course. So that cache is refreshed every 24 hours at most. So you might actually see a subscription there that has already expired. But then, hopefully, thats only going to last 24 hours or so.

Thats usually not a big deal. All right? So when youre making any API calls, its very important to be careful about the UI thread. So the UI threads something thats very delicate. Why?

Because if you block the UI thread, your application is going to stop responding, of course. And in the Android world, I mean, actually in any mobile application, thats not just something thats frowned upon. The system actually punishes your app for that. And the punishment, of course, this is very, very friendly dialogue box.

So if you dont want the users to see this dialogue box, because users just absolutely love that dialogue box, then you shouldnt ever block the UI thread by calling INAUDIBLE that take a long time to return. Particularly in the InApp Billing API, the safe ones to call are isBillingSupported and getBuyIntent. Those two you can call safely from the UI thread because theyre returned right away.

Now the other three that we talked about are not safe to call from the UI thread because they might actually take a while to execute. So if youre calling getPurchases, consumePurchase, getSkuDetails, remember that they might actually take a while to execute. So you definitely do not want to call them from the UI thread in order not to risk a application not responding error. So always call them from a separate thread, async task, whatever else. But whatever you do, dont block the UI thread while waiting for that response.

If you download the sample thats called Trivial Drive, it implements that for you because it has asynchronous wrappers so that you can actually call them from the UI thread and get a call back when they are done. Now many developers dont know this. But theres actually a serverside API that allows you to check for subscriptions. The way it works is this API allows you to take a particular subscription and then query whether or not its valid, when its going to expire, and whether or not its going to renew itself automatically.

It also allows you to cancel an existing subscription from the server side. So how do you go ahead and specify a particular subscription? Well, remember the purchase data on the client side when you call getPurchases?

So one of the fields in that is called purchaseToken. So that identifies that particular subscription for that particular user. So thats the string that you need to use on the server side to call that API.

So this is what I know of what a sample API call looks like. Its basically REST. And Im calling the state of that particular subscription. So I pass it to you. Your package name goes there.

Your subscription ID, so this is the SKU of the subscription goes there. And then thats the token that you get from the clientside. The response looks something like this. And it gives you when the subscription started, when its going to expire, and then whether or not its going to renew automatically. If you want to know more about this API, theres that URL right there.

So theres the full specification of that API. It also allows you to cancel a subscription from the server side, which might be useful for your application. Now, next, lets talk about a very important topic, which is security. Now security is important because, believe it or not, there are some shady characters out there in the interwebs who might want to take your stuff without paying. I know, its shocking.

And they are out there on the web, on the loose. So its very important to implement some measure of security in applications. So I dont really know what the technical term is. But Im going to say theyre pirates, mostly because we spent a really long time drawing this character, and I wanted to use it in a presentation.

So actually, I think theyre called crackers. But lets go with pirates. So anyway, anytime you see a purchase result in your application, you should always ask yourself if you should trust the purchase or not. Of course, a pirates is going to be pirates spend all day being a pirate.

And their job is to convince you that a particular purchase is correct. And of course, your job is to detect that lie and see that that purchase is a fake. So how do you go ahead and do that?

Well, depending on your particular type of app and market, piracy might be a small problem, might be a big problem. Thats going to depend on your type of app. But you should always think in terms of risk model that takes into account several variables, such as the target audience, the items value, the likelihood that somebody would make a fake purchase, the technical difficulty in making a purchase.

And based on that, make a decision on how much security to implement. Of course, in the best case scenario, we implement all possible security. But then you might have to balance that against engineering time and so on and so forth. So its important to be conscious of that. Of course, nobody can stop piracy all together.

I would be lying to you if I said that I had a method to stop piracy. But of course, you should always make life hard for piracy because thats fun. So heres some of the defenses that you can employ to make a pirates life hard. First of all is use our developer payload, and then use signature verification, and also serverside validation.

Were going to give a quick overview of each one of those. So whats this developer payload thing? Well, developer payload is really just a fancy term for a tag. So its just a tag that gets attached to a particular purchase.

Its an arbitrary string. Anytime you launch the purchase flow, you can specify what the string is. Its just a string that gets attached to the purchase.

And then every single time you credit for that purchase and you get that purchase, that strings going to be there. Now, of course, you can write anything into it. But of course, one of the most useful applications of this is to identify the owner of a particular purchase. Why do you want to identify the owner of a particular purchase?

Because then it makes it very hard for somebody to take the purchase data and then replay it into s different device. So again, thats me, the stick figure, of course. Like everyone else I mean, its a scientific fact. Its been scientifically proven that everyone, everyone has an evil twin somewhere.

Now this is Onurb, my evil twin. He is not nearly as honest as I am. So last week, he picked up my device and did a database dump of the items that I had and then replayed them on his device, hoping to get some of my items for free.

So of course, if your application is using developer payload, this is whats going to happen. So Onurb, my evil twin, is going to run your app. And then youre going to check what items does Onurb own.

And youre going to see this purchase. Do you see anything suspicious at all about this purchase? Well, of course.

The developer payload says it belongs to Bruno. But its Onurb thats running the app. Of course, on a real application, you would not use first names because some people have evil twins that have the same first name. So you would not use names, but some unique ID, like for instance, the Google ID or something like that. Also its actually pretty hard to fake that signature, because every purchase comes signed from the server.

So its not actually trivial just to change that purchase. So speaking about signature verification, well, what is this thing about signature verification? Well, every application has a public key and a private key. The private key never leaves Google. So the private key is only known to Google.

And you know the public key for your application. What this means is that whenever somebody signs something with your private key and that, of course, by definition, has to be Google because we are the only ones that have the private key, then you can use the public key for your app to verify that signature to know that we signed it. So Google Play signs every single purchase that goes through Google Play gets signed with your applications private key, which means that, when you get a purchase on your application, you should use your applications public key to check that the signature matches. If it does not, its a fake.

Its not actually difficult to implement signature verification. But if you dont want to implement that, thats actually available in our sample. So Trivial Drive has a helper class that does all that signature verification for you.

So you dont even have to implement that. Now, all right, even though clientside signature verification is pretty cool, right? But dont think that clientside security alone is going to be enough for your app. That would be a mistake because regardless of how difficult you make things, the reality is that phones can be hacked. So you should definitely secure the server side as well.

So when we say serverside verification, what we mean is that on the server side, you should check the signature again just to make sure that the client does not compromise. And then one cool thing you can do on the server, which you cant do on the client, is that you can check the order number because the server is seeing every single purchase that comes from every single person. So every purchase comes with an order number. And they should be unique. So if you ever see a second purchase with the same number as a purchase that youve already provisioned before, then you know that that second purchase is a fake.

So you should always check the order number and dedup it. Also, if youre doing this, make sure to secure the handshake because Ive seen pretty sad stories of developers that spent countless man hours devising this perfect serverside security system. And then their handshake was like a boolean call. It was like a REST call that returned to boolean, saying true, you are validated or not. And then, of course, that can be easily circumvented with a man in the middle attack.

So make sure that the handshake is secure if youre going through the trouble of implementing a serverside security like that. Also make sure that the handshake between the server and the client is secure and not triggered to break. Now to give a summary of the security methods that we talked about.

Of course, you are free not to do anything. If you dont do anything, then youre pretty much vulnerable to any attack. Maybe for your application thats not going to matter. But then you should probably just add at least clientside security because if you at least add clientside signature verification, thats actually very easy to do because its implemented for you.

Its available in the sample. Its just a matter of copying and pasting that. So if you add clientside signature verification, youre going to be protected against man in the middle attacks.

So youre going to be protected against everyones evil twin who tries to replay a purchase on a different device. Now if you want to go the extra mile and then add a unique developer payload, of course, you are also protected against the more elaborate forms of purchase replay. And next, if you want to be really secure, you should, of course, implement serverside signature verification. The serverside signature verifications going to protect you even in the case that the clients phone is hacked, and then the framework has been compromised. So definitely think about implementing serverside security.

Well, so overall, its important to approach the problem of piracy in a very rational way. And that means dont panic and implement methods that are known to be effective. So at least as far as the InApp Billing platforms concerned, these are the three that we talked about. And definitely they are the ones that you should have in mind because theyre very easy to implement so developer payload that identifies the user of course, then signature verification, and also doing serverside validation. And the last topic for today, its something that developers have been asking us for a long time.

So Im actually glad that this launched. So and this is the InApp Billing sandbox. So whats the sandbox thing?

Well, if you remember how things used to be, when you wanted to test to make sure that your InApp Billing implementation was working right, you essentially had two choices when testing InApp purchase. You could just use the test SKUs, the purchased and canceled SKUs, which are, of course, fake product codes. And they always return a given purchase result. So you could, of course, use that.

And those are, of course, mock products with a mock purchase flow. They dont actually go through the server. And then they get a mock result.

Of course, if you were not satisfied with that and, of course, if you wanted to do something thats closer to production, you could use that. You could use a test account. And of course, if you list somebody as a test account, the only privilege they used to have is that they could make purchases from an application that was not yet published.

But you had to use real money, had to use a real credit card, has to use a real purchase flow. And then you would actually get charged for that. Of course, you could revert the charge by refunding it. But then maybe the banks not going to be happy and so on and so forth.

But its just very complicated. So with InApp Billing sandbox, you can now test purchases with the real products, using the actual real purchase flow, with a real credit card. So everything is as real as possible, except that that last step, when your credit card is about to be charged, that doesnt happen.

So thats the only part thats mock. But thats the only part that doesnt happen is you dont get charged. But otherwise, the whole flow is actually real.

So how do you go ahead and set this up? To enable that, you simply add some test account to the list of test accounts in the publishers site. So this is the Android publisher site.

You go to Account Details. Then you add a list of test accounts over there, so some Gmail accounts that you want to test the app with. So apart from those accounts apart from being able to purchase from your unpublished app, whats going to happen when you try to publish with any of those accounts is that youre going to see a screen just like this.

So do you notice any difference from the screen that we saw before? Its exactly the same one, except theres a warning saying, this is a test purchase and you wont actually be charged. But everything else is going to work exactly in the same way as a real purchase would. So this means that you can test your InApp purchase in an environment that is pretty much identical to the real life production system.

But you wont actually be charged. Of course, if you want to see the InApp Billing Version 3 code in practice, we have a sample called Trivial Drive. So its an exciting driving game that I wrote.

So you get burn fuel and then buy more fuel. Its kind of like the experience of having a car in real life. And its available through the SDK manager. And its also available through the Google code site. I recommend that you get the code directly from Google code site because its more uptodate there.

And pretty soon, were going to launch an update to that app thats going to include selfdriving cars. So summarizing, we talked about the most challenging points of InApp Billing V2. We talked about how InApp Billing V3 was designed to address those points and make things much easier for developers.

We talked about subscriptions. We talked about new API features, such as consumption. We talked about the new product details API feature. Then we talked about the server API and gave some pointers on security best practices. And we also presented IAB sandbox, which makes it much easier to test your apps in a real environment.

So the reason we are improving the API constantly and adding these new features is we are always striving to improve the developer experience because we know that if we give you a good experience as a developer, you can focus on what makes your apps great. So you can make a better experience for your users, which is everybodys final goal. So I hope that the tips that I gave you are useful in that respect. And I thank you very much for coming to this session. If you have any feedback, there is the rate this session poster over there.

On previous IOs, I know that we had real life tomatoes you could throw on stage. But that was pretty messy. So if you want to give your feedback, just scan that QR code over there or use the Google IO app to give your feedback.

So thank you very much. APPLAUSEp

Be First to Comment

Leave a Reply

Your email address will not be published. Required fields are marked *