Phil Hassey - game dev blog
Phil Hassey as Snidely Whiplash
"You can't buy awesomeness.
You're born that way."

Android Day 10: Implementing License Server

So .. License Server came out about a week ago. When I heard about that I was all, “eh, more DRM, why bother, the users won’t see any benefit, so it’s not worth my time.” Turns out I got that wrong! There are actually several concrete benefits to the user by using the License Server (which I found within a day of releasing Galcon due to the quantity of emails from users explaining my failure to care about them!) If you use the “Copy Protection” feature of the Android Marketplace publisher, you do two things to the user:

– The app will take up twice as much room.
– The app cannot be stored on the user’s SD card.

I covered some of this in a previous blog, but the users memory is very limited, so over utilizing it is a “bad thing”!

The documentation for the Licensing Server is really really long looking, but there isn’t that much you have to do, actually. You’ll probably want to read it, but if you want the synopsis of what you actually end up having to do, here it is:

Step 1: Install the LVL SDK.

You just power up the SDK installer software and find the “Market Licensing package” and install that.

Step 2: Copying the LVL SDK into your project.

Just copy path/to/android/market_licensing/library/src/* into your local src/ folder. The SDK isn’t part of the Android platform, so you have to include it in your own codebase.

Step 3: Get your app to check the license using a Policy.

You can do some complicated things, but the documentation says, “… don’t do that. Just use the included ServerManagedPolicy or StrictPolicy.” I’m going to use the ServerManagedPolicy because that doesn’t require the user to ALWAYS be on-line to use your App. The StrictPolicy only works when the user is on-line and checks the license every time.

At this point, you’ll want to just go find path/to/android/market_licensing/sample and check out the source there. It includes an example that will pop up a dialog to send the users off to buy your app if they don’t have it licensed properly. This seems to be pretty much what I want, so I’ll just copy-n-paste from that.

Tips:

– To grab your public key go to http://market.android.com/publish/ and click on “Edit Profile” and your key is at the bottom of the page.

– You’ll (maybe) want to grab the example res/values/strings.xml and paste the Licensing related strings into your own strings.xml

– applicationError(ApplicationErrorCode errorCode) should call dontAllow()

– add finish() after the app goes to the market Intent. This way, they can’t go back to the app and get pestered about buying it again. They will have to restart the app and the license will check out fine.

Step 4: Testing it out

You can test out your app by again going to http://market.android.com/publish/ and clicking on “Edit Profile” .. at the bottom you can add market user emails that are being tested and you can change what license response you want to force out to the user.

Tip: be careful not to hit the licensing server too often, or you’ll start getting 503 errors which indicate overuse of resources. These take a while to reset.

Step 5: Adding a demo mode

You may want to add a demo mode to your game if licensing fails. Or somehow stop the game entirely, because the AlertDialog seems to be full of “holes”. That dialog will disappear and reveal your game under a number of scenarios. So don’t count on it blocking the user.

I just recall showDialog(0); in onTouchEvent if the game is in demo mode to keep bringing up the dialog again. I suppose a less annoying way to do it would be to respawn the dialog every minute or something. But maybe I’ll do that later!

Step 6: Applying ProGuard code obfuscation

This step is highly recommended by the Android developer guide. It would be nice if this were built into the Android toolchain, but it isn’t. Here’s a blog post that tells you how to do this.

However, I found that the binary that got build crashed. I’m not sure what is going on, but I’m guessing the NDK and ProGuard just aren’t getting along somehow. I’m going to leave out ProGuard for the time being. (I gave this a few hours effort. Again, this is where having support as part of the Android developer’s kit would be great!)

Update: this blog post explains what you need to do. Beyond that, you also need to handle your native methods and callbacks properly.

Step 7: Enabling Install on SD Card!!

This step is basically the whole point of this entire blog post. This gets the app out of the main memory on the device and onto the SD card for the user’s improved happiness.

To do this, add android:installLocation=”preferExternal” to the manifest tag in AndroidManifest.xml

Also change target=android-8 in default.properties.

And that’s that!
-Phil

5 Responses to “Android Day 10: Implementing License Server”

  1. Little Big Tomatoes » Blog Archive » Porting Galcon to Android Says:

    […] Android Day 10: Implementing License Server […]

  2. Alex Roberts Says:

    Regarding LVL and ProGuard, I encountered the same problem, and recently blogged a solution that appears to work.

    Basically ProGuard screws up Java Enumeration, and must be told not to, since LVL relies on it. So just add the following to your ProGuard config:

    -keep class com.android.vending.licensing.ILicensingService

    -keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
    }

    Hopefully that fixes it, but if there is indeed more to it, please let me know!

  3. Manuel Says:

    I’ve already wondered why the game got just 4MB with last update. But some changelog in-game or via the market would be great to get the catch why there’s an update again.

  4. philhassey Says:

    Yeah, it doesn’t seem the market has a way to give a changelog, which is a bit weird.

  5. Manuel Says:

    It has some way. Many apps schon a smaller, grey text at the end of the description with the current version, size of the app and the latest changes. e.g. Titanium Backup, here’s a screenshot: http://imghost.glorp.de/i/1568a1a1e0fe.png