APK Expansion Files

Development environment.
  • Ubuntu 11.10 (Oneiric)
  • JDK 1.6.0_24-b07
  • Eclipse 3.7.3 (Indigo)
    • Android Development Toolkit 17.0.0

Preparing.
  1. Get a publisher account here for Google Play, if you don't have yet.
  2. Download two packages from the SDK Manager.('Google Play APK Expansion Library' and 'Google Play Licensing Library')
    Android SDK Manager
  3. Create two library projects from existing source.
    • <sdk>/extras/google/play_apk_expansion/downloader_library
    • <sdk>/extras/google/play_licensing/library
  4. Create a new project which you want to use APK Expansion Files and add above two library project to your new project's build path.
    Add a reference to a library project

Implementing.
  1. Downloader service.
    // Extends com.google.android.vending.expansion.downloader.impl.DownloaderService class and override three methods.
    public class ExpansionFileDownloaderService extends DownloaderService {
     // the Base64-encoded RSA public key for your publisher account
     private static final String PUBLIC_KEY = "{YOU_PUBLIC_KEY}";
     // Generate 20 random bytes, and put them here.
     private static final byte[] SALT = new byte[] {};
     @Override public String getPublicKey() {
      return PUBLIC_KEY;
     }
     @Override public byte[] getSALT() {
      return SALT;
     }
     @Override public String getAlarmReceiverClassName() {
      return ExpansionFileAlarmReceiver.class.getName();
     }
    }
    
  2. Alarm receiver.
    public class ExpansionFileAlarmReceiver extends BroadcastReceiver {
     @Override public void onReceive(Context context, Intent intent) {
      try {
       DownloaderClientMarshaller.startDownloadServiceIfRequired(
         context, intent, ExpansionFileDownloaderService.class);
      } catch (NameNotFoundException e) {
       Log.e("apk-expansion-files", "NameNotFoundException occurred. " + e.getMessage(), e);
      }
     }
    }
    
  3. Main activity.
    @Override
     public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.main);
      
      // Check whether the file have been downloaded.
      String mainFileName = Helpers.getExpansionAPKFileName(this, true, 1);
      boolean fileExists = Helpers.doesFileExist(this, mainFileName, 32921796L, false);
      if (!fileExists) {
       Intent launcher = getIntent();
       Intent fromNotification = new Intent(this, getClass());
       fromNotification.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
       fromNotification.setAction(launcher.getAction());
       if (launcher.getCategories() != null) {
        for (String cat : launcher.getCategories()) {
         fromNotification.addCategory(cat);
        }
       }
       PendingIntent pendingIntent = PendingIntent.getActivity(
         this, 0, fromNotification, PendingIntent.FLAG_UPDATE_CURRENT);
       try {
        // Start the download
        int result = DownloaderClientMarshaller.startDownloadServiceIfRequired(
          this, pendingIntent, ExpansionFileDownloaderService.class);
        if (DownloaderClientMarshaller.NO_DOWNLOAD_REQUIRED != result) {
         // implement Downloading UI.
         return;
        }
       } catch (NameNotFoundException e) {
        Log.e("apk-expansion-files", "NameNotFoundException occurred. " + e.getMessage(), e);
       }
      }
      // expansion file is available. start your application.
     }
    

Manifest declarations.
  • uses-permission
    <!-- Required to access Android Market Licensing -->
    <uses-permission android:name="com.android.vending.CHECK_LICENSE" />
    <!-- Required to download files from Android Market -->
    <uses-permission android:name="android.permission.INTERNET" />
    <!-- Required to keep CPU alive while downloading files (NOT to keep screen awake) -->
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <!-- Required to poll the state of the network connection and respond to changes -->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <!-- Required to check whether Wi-Fi is enabled -->
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
    <!-- Required to read and write the expansion files on shared storage -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    
  • application
    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name">
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <service android:name=".ExpansionFileDownloaderService" android:label="@string/app_name" />
        <receiver android:name=".ExpansionFileAlarmReceiver" android:label="@string/app_name" />
    </application>
    

Testing APK Expansion Files
  1. Upload the application APK file and Expansion Files using the Google Play Developer Console.
    Uploading APK and Expansion file.
  2. Fill in the necessary application details. Click the Save button. Do not click Publish.
  3. Install the application on your test device and launch the app. Download will start soon.