Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Problems testing APK expansion library

I've integrated the APK Expansion file download library from Google into my project, and it works more or less OK (except a few minor gotchas, which have been reported by others on SO already).

However, I have a hard time testing it. When I was first testing it, I uploaded my signed APK + main expansion file version 1 to Google Play, and it worked well.

However, when I upgraded my application, together with main expansion file version 2, the application could no longer download the file - the library immediately returns with NO_DOWNLOAD_REQUIRED, but the file is not there! I started debugging the LVL check passes, but the downloadable files table was empty! While I was trying to debug the details... it suddenly started to work again!

I assumed this was a sort of temporary glitch and continued my work, just to hit the same issue again, after updating my APK and expansion file again. Application passes the LVL check, but again library assumes there are no files to download.

Is it a known problem with Google's library? Or perhaps I need to wait some time until the files is available on Google's cloud?

EDIT: It just started working OK. It really seems it needs some time for the file to somehow propagate on Google's side. One bad thing about the library is that once it validates the license, it never checks the download list again, so I had to reinstall the app. Weird... Why the heck is it so complex?

like image 266
Code Painters Avatar asked Aug 13 '12 11:08

Code Painters


People also ask

What is Google Play APK expansion library?

Google Play hosts the expansion files for your app and serves them to the device at no cost to you. The expansion files are saved to the device's shared storage location (the SD card or USB-mountable partition; also known as the "external" storage) where your app can access them.

What is the maximum size of APK file in Android?

Each expansion file can be up to 2GB in size. Users must run Play Store version 5.2 or higher to install 100MB APKs.

What are expansion files?

Expansion files are simply files/folders in archived format (. obb to be precise). Basically after publishing you will receive two files: . apk file – the main app file.


1 Answers

A little thread necromancy, but since I had so much trouble getting the OBB downloading to work I wanted to put all the problems in one place. Quite how - or indeed why - Google managed to make downloading a file from t'internet quite this complicated is beyond me.

Adding the Libraries to Android Studio

The official instructions proudly brought to you by the Ministry of Misinformation (https://developer.android.com/google/play/expansion-files.html) are simply wrong.

Before importing the libraries, go to sdk\extras\google\market_apk_expansion\downloader_library and edit project.properties to remove the "android.library.0" line entirely. You may also need to update the android target version line in the same file to match your existing project's target version.

Following the installation instructions on the page linked above, "Preparing to use the Downloader Library" Step 2 should be "File > New > Import Module" and not "File > New > New Module".

After importing both modules, go to "File > Project Structure" and add dependencies:

  • Your app should have a "Module Dependency" on both the licensing and downloader libraries
  • The downloader library should have a "Module Dependency" on the licensing library

The step that says "You must update the BASE64_PUBLIC_KEY value to be the public key belonging to your publisher account." is also wrong. You need the public key for this specific app, not your account, which is in the online Developer Console under "Services & APIs" after you've selected the app.

Both the License Validation Library and the Downloader Library have dependencies on a now-removed package "org.apache.http"

Replace two instances of "decodeExtras" method (one in APKExpansionPolicy.java, one in ServerManagedPolicy.java) with:

private Map<String, String> decodeExtras(String extras) {
    Map<String, String> results = new HashMap<String, String>();

    UrlQuerySanitizer sanitizer = new UrlQuerySanitizer();
    sanitizer.setAllowUnregisteredParamaters(true);
    sanitizer.setUnregisteredParameterValueSanitizer(new UrlQuerySanitizer.IllegalCharacterValueSanitizer(
            UrlQuerySanitizer.IllegalCharacterValueSanitizer.URL_LEGAL));
    sanitizer.parseQuery(extras);

    for (UrlQuerySanitizer.ParameterValuePair item : sanitizer.getParameterList()) {
        String name = item.mParameter;
        int i = 0;
        while (results.containsKey(name)) {
            name = item.mParameter + ++i;
        }
        results.put(name, item.mValue);
    }

    return results;
}

Crash at runtime, saying "Service Intent must be explicit"

See the answer at https://stackoverflow.com/questions/24480069.

W/LicenseValidator: Error contacting licensing server

The license validation library won't work on an emulator, and this is the error it throws. If you're on a real device, it may just be a genuine timeout.

Debug versions fail a signature check (Signature verification failed), so are denied access.

The binary that is calling the license verification service must be a correctly-signed, release version. If you're running a debug copy that won't be the case, so the license checks fail.

  • Go to your online Developer Console, Settings, Account Details
  • Change the "License Test Response" to "LICENSED" (or whatever you're testing)
  • Enter your email address under "Gmail accounts with testing access".

Downloader returns "STATE_COMPLETED" but download is not done.

This is a side-effect of the previous change. You are licensed, but the APK extension files are still not provided because you're not really licensed. This step is what allows you to actually test the downloads as they happen after distribution, instead of manually placing files onto your test devices.

  • Create a promo code for the app.
  • Create a new user on your device, for a totally new GMail account.
  • Log in to your device as the new user, redeem the promo code. You are now a genuine app owner.
  • Add the new gmail account under "Gmail accounts with testing access", as in the previous section.

You can't do this with the developer's account because purchasing or redeeming will fail, which means you can never own a copy of your own product, which means that the OBB download will never work.

Now that you have a second account, with a genuine Play Store copy of the app and which is registered as a test account with a 'fake' LICENSED status, you can run a debug copy of your code, get the LICENSED status, and have the downloads work as you'd expect.

W/LVLDL: Aborting request for download whavever.obb: while writing destination file: java.io.FileNotFoundException:

Since Android v23 it's been necessary to explicitly request permissions to write to "external storage", whether it's an SD card or not, and on top of having the permission listed in your manifest. See https://developer.android.com/guide/topics/permissions/requesting.html .

The "File not found" is referring to the directory on the external storage that the downloader library wants to put the OBB file into, which it has been unable to create. An exception gets raised if it can't create the file, but it fails silently if it can't create the directory. See processResponseHeaders() in DownloadThread.java .

W/LVLDL: Aborting request for download main.whatever.obb: http error 410

Your app's version number must match one from a current APK that Google knows about otherwise your download request will be rejected with error 410.

Library will not re-check the license if it's found to be valid once.

If you're testing, chances are you need to re-do things a few times. The License Verification Library caches it's state after it's been found to be LICENSED. You can clear this without totally uninstalling your app:

DownloadsDB db = DownloadsDB.getDB(my_app_context);
db.updateMetadata(0, 0);

It also keeps the downloaded OBB in place, which can be found and cleared using:

final String dlName = Helpers.getExpansionAPKFileName(my_app_context, true, expansionVersion);
final String dlFullPath = Helpers.generateSaveFileName(my_app_context, dlName);
File dlFile = new File(dlFullPath);
if (dlFile.exists())
{
    dlFile.delete();
}

Now, if you'll excuse me, I'm off to a spiritual retreat for a month or so.

like image 73
Jim Keir Avatar answered Oct 08 '22 07:10

Jim Keir