About App Licensing - dummies

By Barry Burd

With Android’s app licensing, each device checks with a server to make sure that this device has permission to run your app. Licensing is important for any paid app. Licensing is also a good precaution with a free app (to help you maintain ownership of the app’s concept). This article guides you through the steps to add a simple licensing scheme to your Android application.

Creating a new Android application

Create a new Android project the way you normally do. When setting a Minimum SDK, select API Level 19 or lower. In the new app’s build.gradle file, change the targetSdkVersion to 19 or lower. (It takes more work to do licensing when you target a newer API level.)

The licensing library

Here’s one way to add Google’s licensing library to your project:

  1. In Android Studio’s main menu, select Tools→Android→SDK Manager.

  2. In the SDK Manager’s SDK Tools tab, select Google Play Licensing Library.

  3. Click OK to download and install the Licensing Library.

  4. When the installation is completed, click Finish to dismiss the SDK Manager.

  5. In Android Studio’s main menu, select File→Project Structure.

  6. On the left side of the Project Structure dialog box, select the SDK Location item.

  7. In the main body of the Project Structure dialog box, note the entry in the Android SDK Location text field.

    This is the place on your hard drive where the Android SDK has been installed.

  8. Click OK to dismiss the Project Structure dialog box.

  9. With your development computer’s File Explorer or Finder, visit the place on your hard drive where the Android SDK is installed.

  10. Navigate downward to the extras/google/play_licensing/library/src/com directory.

    In that directory, you’ll find a subdirectory named google.

  11. Copy the google directory to your application’s app/src/main/java/com directory.

Now your application’s app/src/main/java/com directory has two subdirectories. For example, if an application is in a package named com.allyourcode.licensingdemo, the application’s app/src/main/java/com directory has subdirectories named allyourcode and google. You can see this with your computer’s File Explorer or Finder, but you can also see it in Android Studio’s Project tool window (as shown here).

Some new subdirectories.
Some new subdirectories.

Getting a license key for your app

You need a license key in order to publish this app. To get your key, do the following:

  1. Visit Google Play Store’s Developer Console.

  2. In the Developer Console, click the Add New Application button.

    An Add New Application page appears.

  3. On the Add New Application page, type a title for your new application.

  4. Still on the Add New Application page, click the Prepare Store Listing button.

    You’re taken to a Store Listing page.

  5. On the left side of the Store Listing page, select Services and APIs.

    The Store Listing page’s content changes.

  6. On the Store Listing page, look for a monstrously long sequence of characters like the one shown here.

    A monstrously long sequence of numbers.
    A monstrously long sequence of numbers.
  7. Copy that sequence of characters, and paste it to a plain text file on your development computer’s hard drive.

Modifying your app for licensing

Next, you have to add code to your app so that the app checks the licensing server before allowing the customer to use it. Here’s a bare-bones sample. (For a richer sample, see the code in the SDK’s extras/google/play_licensing/sample folder.)

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.provider.Settings;
import com.google.android.vending.licensing.AESObfuscator;
import com.google.android.vending.licensing.LicenseChecker;
import com.google.android.vending.licensing.LicenseCheckerCallback;
import com.google.android.vending.licensing.ServerManagedPolicy;
public class MainActivity extends Activity {
  private static final String BASE64_PUBLIC_KEY = "YOUR PUBLIC KEY GOES HERE";
  private static final byte[] SALT = new byte[] { //Twenty numbers (ranging from 
                                                  // -128 to +127) go here
  };
  private LicenseCheckerCallback mLicenseCheckerCallback;
  private LicenseChecker mChecker;
  private boolean keepGoing = true;
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    String deviceId = Settings.Secure.getString(getContentResolver(),
        Settings.Secure.ANDROID_ID);
    mLicenseCheckerCallback = new MyLicenseCheckerCallback();
    mChecker = new LicenseChecker(this, new ServerManagedPolicy(this,
        new AESObfuscator(SALT, getPackageName(), deviceId)),
        BASE64_PUBLIC_KEY);
    doCheck();
  }
  @Override
  public void onResume() {
    super.onResume();
    if (!keepGoing) {
      finish();
    }
  }
  private void doCheck() {
    mChecker.checkAccess(mLicenseCheckerCallback);
  }
  private class MyLicenseCheckerCallback implements LicenseCheckerCallback {
    public void allow(int policyReason) {
      if (isFinishing()) {
        // Don't update UI if Activity is finishing.
        return;
      }
    }
    public void dontAllow(int policyReason) {
      if (isFinishing()) {
        return;
      }
      keepGoing = false;
      Intent intent = 
                  new Intent(MainActivity.this, NotLicensedActivity.class);
      intent.putExtra("message", getResources().getString(R.string.app_not_licensed) + 
                      " (0x" + Integer.toHexString(policyReason) +")");
      startActivity(intent);
    }
    public void applicationError(int errorCode) {
      if (isFinishing()) {
        return;
      }
      keepGoing = false;
      Intent intent = new Intent(MainActivity.this,
          NotLicensedActivity.class);
      intent.putExtra("message",getResources().getString(R.string.application_error) + 
                      " (0x" +Integer.toHexString(errorCode) +")");
      startActivity(intent);
    }
  }
  @Override
  protected void onDestroy() {
    super.onDestroy();
    mChecker.onDestroy();  //Don't forget this line. Without it, your app might crash.
  }
}

To make this sample code work, you have to add some extra ingredients:

  • In the main activity, replace the words YOUR PUBLIC KEY GOES HERE with your own license key from Steps 6 and 7 in this article’s “Getting a license key for your app” section.

  • Make up your own 20-number SALT value — a fancy term for a set of randomly produced values — and add it to the main activity’s code.

  • Create app_not_licensed and application_error string resources.

  • Add <uses-permission android:name=”com.android.vending.CHECK_LICENSE” /> to the project’s AndroidManifest.xml file.

  • Add any of your own app’s code to the sample code. (In other words, make your app do what it’s supposed to do — play a game, display information, solve a problem, or whatever.)

  • Create a NotLicensedActivity class.

    A sample NotLicensedActivity is copied here.

    public class NotLicensedActivity extends Activity {
      public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.not_licensed);
        String message = getIntent().getExtras().getString("message");
        ((TextView) findViewById(R.id.message_text)).setText(message);
        ((TextView) findViewById(R.id.message_text2)).setText(message);
      }
      public void quitApp(View view) {
        finish();
      }
    }
  • Add text views named message_text and message_text2 to your NotLicensedActivity’s layout file.

In the main activity, the essence of the license check comes in two parts (a) the call to doCheck(), which communicates with the Google Play server, and (b) the MyLicenseCheckerCallback inner class (the class that responds to the Play server’s results). The LicenseCheckerCallback has to have at least three methods — an allow() method for “Go ahead and use the app”, a dontAllow() method for “you’re not licensed to use this app”, and an applicationError() method for “Oh, oh!”

In the sample code nothing special is done in the allow() method. In the dontAllow() and applicationError() methods another activity is started that is named NotLicensedActivity. You can make this NotLicensedActivity do anything you want. Whatever happens in the NotLicensedActivity, a keepGoing field is set to false, telling the main activity to call finish() (in the onResume method) when returning from the NotLicensedActivity.

You can use this trick or do something different. In Android, activities aren’t modal. That is, if one activity partially covers another activity, then the user can interact with either activity by touching the appropriate part of the screen. So if NotLicensedActivity doesn’t completely cover up the main activity, the user can circumvent the NotLicensedActivity by touching another part of the screen. To keep this from happening, make the NotLicensedActivity cover the entire screen, resisting the temptation to make the NotLicensedActivity look like a small dialog box.

Testing Your App’s Licensing

Does your app licensing work? Can licensed users run your app? And what about unlicensed users? Can they run your app, too? You can find out after you’ve uploaded your app and before you actually publish your app. Here’s how:

  1. Visit https://play.google.com/apps/publish/.

  2. In the very leftmost part of the Developer Console page, select Settings.

    Your account’s Settings page appears.

  3. On the left side of the Settings page, select Account Details.

  4. Scroll down the Account Details page until you find a License Testing section.

    In that License Testing section, you’ll find a text field labeled Gmail Accounts with Testing Access. You’ll also find a drop-down list labeled License Test Response.

    Your License Test Response options
    Your License Test Response options
  5. In the Gmail Accounts with Testing Access field, type the email address for one or more Gmail accounts.

    If you type more than one email address, use a comma to separate one address from another. People whose Android devices are registered to these email addresses will be able to find your app on the Google Play Store. (Others will not see your app.)

  6. In the Licensed Test Response list, select NOT_LICENSED.

    Users who install your app (users with the Gmail addresses that you listed in Step 5) will get this NOT_LICENSED response when they try to run the app.

  7. Tell the users on your Gmail Accounts list to try downloading and installing your app.

    If your app’s code is correct (for example, if the onCreate method in this article’s main activity is doing its job), user’s won’t be able to continue running your app. That’s exactly what you want

  8. When you’re satisfied with the results of the testing in Steps 6 and 7, revisit the Developer Console and change the Licensed Test Response to LICENSED.

  9. Tell the users on your Gmail Accounts list to try running your app again.

    If your app’s code is correct (for example, if the onCreate method in this article’s main activity is doing its job), user’s will be able to continue running your app.

  10. Try other options in the Licensed Test Response list — options such as LICENSED_OLD_KEY, ERROR_SERVER_FAILURE, and so on.

    Remember, there’s no such thing as too much testing.