41

I have developed Application and work successfully.

I have used Application Licensing feature into my application. And now I'm going to upload an application on google play.

Please let me know the steps, How to use Application licensing and how to create APK Expansion file?

RobinHood
  • 10,464
  • 4
  • 44
  • 92
user1414154
  • 411
  • 1
  • 5
  • 10
  • New tools available now, just update your SDK. http://developer.android.com/tools/help/jobb.html – Idea Estiawan Nov 18 '12 at 12:38
  • There is a nice documentation provided on developer's site. [`APK Expansion Files`](http://developer.android.com/guide/google/play/expansion-files.html). Did you check that? Its nicely documented with steps. – Lalit Poptani Jul 30 '12 at 05:33
  • Please let me know the steps to implement Application Licensing. I have look at the developer site. Still i require some more help on it. – user1414154 Jul 30 '12 at 06:36
  • Well, what you have tried? what problem you are facing that matters. – Lalit Poptani Jul 30 '12 at 06:37
  • @hotveryspicy Can you please provide steps for APK expansion? – Dharmendra Jul 30 '12 at 07:23
  • Basically, i am using eclipse using ADT so i have developed one library project for market licensing. and add library project into my application project. implement source code of application licensing into my project where initial point of the project. I created one APK and uploaded on google play and publish it. but could not seen on google play store. – user1414154 Jul 30 '12 at 07:27
  • @hotveryspicy: I'm looking for the same. can you provide steps for APK expansion? **Edit**: ignore it, I found it in your answer. – Adil Soomro Jul 30 '12 at 07:51
  • @LalitPoptani we are facing many bugs in sample code, those who are trying the sample code they may get this bugs http://stackoverflow.com/questions/11723814/xapk-file-validation-failed-in-sample-code-of-android-apk-expansion-files – LOG_TAG Aug 01 '12 at 04:11
  • @Subra better check the steps provided by hotveryspicy below. – Lalit Poptani Aug 01 '12 at 06:19
  • @LalitPoptani i am getting this error com.google.android.vending.licensing.LicenseChecker.generatePublicKeycom.google.android.vending.licensing.LicenseChecker.generatePublicKey When testing, i havent uploaded the app i am just running the app and checking can you please let me know whats the mistake that i am doing? – Goofy Feb 25 '13 at 20:00
  • I'm not sure how this constitutes an answer. It should be a comment. – iwasrobbed Jun 19 '13 at 15:44
  • @ Lalit Poptani. That link tells you what to do not how to do. Just another garbage tutorial from Google. –  Dec 03 '14 at 07:00
  • The documentation Google provided was not helpful nor clear. Glad this question was kept and answers were provided. – daspianist Jul 01 '19 at 13:38

5 Answers5

95

Expansion files remove the restriction of uploading more than 100MB apk size. You should attach these files when uploading the apk. Each app can provide up to 4GB (2GB - main, 2GB - patch) of additional data for each APK.

There are naming convention you have to follow while creating Expansion files

[main|patch].<expansion-version>.<package-name>.obb

note:

  1. main- are those files without this your application will not going to run
  2. patch- are those files which are additional, without this your application can run
  3. expansion-version- version that you are giving to your apk, so that Expansion files of different version will not conflict
  4. package-name-This is your unique package name

.obb we are not appending, it will implicitly appended by Google while uploading

suppose you have all the content in your current directory so just select all the content and make it a zip named main.2.com.xyz.abc.zip and attach it with while uploading apk

enter image description here

This all uploading part, now downloading part

First of all you need to download Google extra package by clicking on SDK-Manager

enter image description here

Now create new project from existing source and import market_licensing, play_apk_expansion from the path sdk-path/extras/google

Remember: Free app does not require Licensing but Expansion concept required, you just need not to bother by giving reference of market_licensing to your project it will implicitly manage.

play_apk_expansion contains three projects downloader_library, zip_file, downloader_sample.

downloader_library itself having the reference of Market_licensing.

Now you just need to concentrate on downloader_sample first change the package name(for testing) to your packagename(packagename same as uploaded apk)

Very Important

In SampleDownloaderActivity navigate to...

private static final XAPKFile[] xAPKS = {
            new XAPKFile(
                    true, // true signifies a main file
                    2, // the version of the APK that the file was uploaded
                       // against
                    xxxxxxxxxxxL // the length of the zipfile in bytes right click on you expansion file and get the size in bytes, size must be same as zip size
            ),

    };

Now This activity will download the Expansion file and will store it in sdcard/Android/obb/[main|patch].<expansion-version>.<package-name>.obb ignore obb, just unzip this file anywhere you want (sdcard/Android/data recommended because it removes when your application get uninstalled).

There are latest device which download Expansion files directly from Play store and it get stored in sdcard/Android/obb/ so you have to be very careful to check all the cases

  1. Obb already downloaded
  2. Available memory
  3. downloaded but not unzipped
  4. Memory to select(see Memory Cases)

Memory Cases:

if you take any new device or for ex. micromax funbook, then it's having three memory

  • /data/data/ (phone internal memory) getFilesDirectory()
  • /mnt/sdcard/ (phone's internal sdcard) Environment.getExternalStorageDirectory()
  • /mnt/extsd/ (External sdcard) /mnt/extsd

Hope this will help you and will meet your requirements.

And one more thing use this below ZipHelper to unzipped the content.

ZipHelper.java

public class ZipHelper
{
    boolean zipError=false;

    public boolean isZipError() {
        return zipError;
    }

    public void setZipError(boolean zipError) {
        this.zipError = zipError;
    }

    public void unzip(String archive, File outputDir)
    {
        try {
            Log.d("control","ZipHelper.unzip() - File: " + archive);
            ZipFile zipfile = new ZipFile(archive);
            for (Enumeration e = zipfile.entries(); e.hasMoreElements(); ) {
                ZipEntry entry = (ZipEntry) e.nextElement();
                unzipEntry(zipfile, entry, outputDir);
                
            }
        }
        catch (Exception e) {
            Log.d("control","ZipHelper.unzip() - Error extracting file " + archive+": "+ e);
            setZipError(true);
        }
    }

    private void unzipEntry(ZipFile zipfile, ZipEntry entry, File outputDir) throws IOException
    {
        if (entry.isDirectory()) {
            createDirectory(new File(outputDir, entry.getName()));
            return;
        }

        File outputFile = new File(outputDir, entry.getName());
        if (!outputFile.getParentFile().exists()){
            createDirectory(outputFile.getParentFile());
        }

        Log.d("control","ZipHelper.unzipEntry() - Extracting: " + entry);
        BufferedInputStream inputStream = new BufferedInputStream(zipfile.getInputStream(entry));
        BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(outputFile));

        try {
            IOUtils.copy(inputStream, outputStream);
        }
        catch (Exception e) {
            Log.d("control","ZipHelper.unzipEntry() - Error: " + e);
            setZipError(true);
        }
        finally {
            outputStream.close();
            inputStream.close();
        }
    }

    private void createDirectory(File dir)
    {
        Log.d("control","ZipHelper.createDir() - Creating directory: "+dir.getName());
        if (!dir.exists()){
            if(!dir.mkdirs()) throw new RuntimeException("Can't create directory "+dir);
        }
        else Log.d("control","ZipHelper.createDir() - Exists directory: "+dir.getName());
    }
}
Jeff Ward
  • 11,655
  • 3
  • 36
  • 48
Mohammed Azharuddin Shaikh
  • 39,642
  • 13
  • 90
  • 114
  • i follow the steps up to added code from SampleDownloadActivity to my activity. – user1414154 Jul 30 '12 at 09:28
  • after running the code there bugs like 1>crc 2>download bar may effect your code.. http://stackoverflow.com/questions/11723814/xapk-file-validation-failed-in-sample-code-of-android-apk-expansion-files please comment if got the same problem, if I found the solution let u know.. – LOG_TAG Aug 01 '12 at 04:08
  • crc bug solution by hotveryspicy: http://stackoverflow.com/questions/10330283/crc-error-with-expansion-files – LOG_TAG Aug 01 '12 at 04:10
  • right click on you expansion file and get the size in bytes, size must be same as zip size but which size we have to put? there two types of file size 1>Size on Disk 2>Size which one we should use? – LOG_TAG Aug 01 '12 at 06:33
  • 1
    @Subra ignore size on disk, take another one. – Mohammed Azharuddin Shaikh Aug 01 '12 at 06:36
  • thanks! do you think XAPK File validation failed come for crc bug or files size ? http://stackoverflow.com/questions/11723814/xapk-file-validation-failed-in-sample-code-of-android-apk-expansion-files – LOG_TAG Aug 01 '12 at 06:40
  • Which is the right way for unzipping or unpacking the expansion APK Expansion Files obb files? (sdcard/Android/data recommended because it removes when your application get uninstalled). I can use this http://goo.gl/OJfLk for unzipping? – LOG_TAG Aug 02 '12 at 05:28
  • 1
    @hotveryspicy thanks it's working fine! #coolverysweet problem is I have to delete downloaded obb file after unzipping to save the space!! – LOG_TAG Aug 07 '12 at 07:43
  • @Goofy please share where you stuck ex:LVL, download verification, unzipping/accessing the data – LOG_TAG Feb 26 '13 at 09:06
  • i am using the sample proj provided in the sdk, now i have am testing the obb file exists or not before uploading the apk file in market, now i have added the obb file in Android/obb/com.abc.ss/main.2.com.abc.ss.obb but when i run the sample app it says downlaoding failed resource not found, but why is it downloading as i have not yet uploaded in console and also the obb file is already present – Goofy Feb 26 '13 at 09:27
  • @Goofy maybe you have to check the size of the file you mentioned in the sampledownloader activity! – LOG_TAG Feb 26 '13 at 10:31
  • @Subra can you join here http://chat.stackoverflow.com/rooms/25141/discussion-between-goofy-and-subra – Goofy Feb 27 '13 at 06:14
  • @hotveryspicy i have a problem while unzip the .obb file. i am getting this error Not a zip file. – jeevamuthu May 08 '13 at 11:31
  • I spent some time looking for the sdk-path/extras/google path when creating new project from existing source. My sdk was located in my users/[username]/AppData/Local/Android/android-sdk/extras/google. Just hover your mouse above the package in the SDK Manager and it will show the path there. – am_ Jul 03 '13 at 08:55
  • i have found that we should have to make 0% compression zip file. so we dont need to extract that obb file. see this http://stackoverflow.com/a/18953778/942224 – Sanket Kachhela Sep 23 '13 at 07:29
  • @SanketKachhela Yes, but this is when you are dealing with media files i.e Audio/Video. This will not apply for regular files – Mohammed Azharuddin Shaikh Sep 24 '13 at 04:06
  • @hotveryspicy i have tried with images too. and it's working nice. – Sanket Kachhela Sep 24 '13 at 07:20
  • [This blog](http://ankitthakkar90.blogspot.in/2013/01/apk-expansion-files-in-android-with.html) seems to be helpful too. Also this [sample](https://gist.github.com/moust/7990925) – Lalit Poptani Jul 25 '14 at 09:28
  • Thank you for the Explanation. 1) Any Other Alternate is there or not 2) we are able or not to access obb files directly without upload the apk in play store. – Raj Jan 24 '18 at 05:01
  • @AzharShaikh You've write this line in try of unZipEntry method `IOUtils.copy(inputStream, outputStream);` Please guide me what is **IOUtils** Android Studio is showing error on it. – Nauman Shafique Jul 08 '18 at 18:38
  • can i use notification sound from expansion file? – Pranav May 08 '19 at 12:50
  • Another Important key point, In the documents google says: "Google Play downloads your expansion files to a device, it saves them to the system's shared storage location." What would happen if the device does not have external storage? is it going to crash? @MohammedAzharuddinShaikh – xSuperMu Jul 05 '20 at 08:33
13

First , assume you are migrate using a helloworld.jpg from /assets/helloworld.jpg to your expansion

  1. create an zip file but with the following file pattern , ending the file extension .obb:
 `[main|patch].{expansion-version}.{package-name}.obb`

E.g if your pkg name is "com.earth.helloworld" and version = 1

then your output extension file name should be: patch.1.com.earth.helloworld.obb
which is a zip file containing helloworld.jpg
after the zip file is created, note the file size: enter image description here 2. then create this folder on your sdcard if not exists:
/mnt/sdcard/Android/obb/{your package name}/
i.e /mnt/sdcard/Android/obb/com.earth.helloworld/

  1. then upload your obb file to your sdcard e.g /mnt/sdcard/Android/obb/com.earth.helloworld/patch.1.com.earth.helloworld.obb

  2. Then create a method to get the extension file

    public ZipResourceFile getExpansionFile() {
    
    String fileName = Helpers.getExpansionAPKFileName(this, false, 1);
    
            int filesize = 445461159;
    if (Helpers.doesFileExist(this, fileName, , false)) {
    
        try {
            return APKExpansionSupport.getAPKExpansionZipFile(
                    getBaseContext(), 1, 1);
    
        } catch (IOException e) {
            // TODO Auto-generated catch block
    
            e.printStackTrace();
        }
    }
    return null;       }
    
  3. Finally use this two lines to get the helloworld.jpg
    InputStream istr = getExpansionFile().getInputStream(strName);

    Bitmap bitmap = BitmapFactory.decodeStream(istr);
    
RAY
  • 1,941
  • 2
  • 16
  • 15
  • Can you provide Helpers class as well? – anhnt Aug 09 '15 at 10:16
  • Thank you for the Explanation. 1) Any Other Alternate is there or not 2) we are able or not to access obb files directly without upload the apk in play store. – Raj Jan 24 '18 at 05:15
11

Some helfull information for people that end up here in this post since there are some things that changed in the way apk expansions work and also if you are using Android Studio to make the libraries work.

NOTE 1

You can't use draft anymore as the link to get the expansion file won't be active yet. You have to upload a version to Alpha or Beta first with expansion file. (adding an expansion file is only possible from the second apk you upload and up) So make sure you see the apk expansion file listed when you click the details in the developer publish section under APK.

NOTE 2

If you are using android studio and want to make use of the downloader library don't just copy the package name and java files into your own app src directory. Import the downloader library in eclipse and choose export => gradle build files. Afterwards you can import the library as a module in android studio.

NOTE 3

Not sure of this but I also think it's neccesary to download the app atleast once through the play store and have access to it with the account on your test device. So if you are working with alpha create a google+ test group and add yourself or other test devices to it.

BTW

With these libraries it's pretty easy to implement the apk expansion download just make sure:

  1. your activity (the one where you want to implement the downloading of the expansion pack when the downloading has not been done automatically) implements IDownloaderClient.

  2. you set up the service & receiver and set them up in your manifest.

  3. The BASE64_PUBLIC_KEY in the service class is correct. Upload the first apk => look in Services and API's in the developer console under your app => License code for this app.

This code is used to see if the expansion file can be found on the device:

boolean expansionFilesDelivered() {
    for (XAPKFile xf : xAPKS) {
        String fileName = Helpers.getExpansionAPKFileName(this, xf.mIsMain, xf.mFileVersion);
        Log.i(TAG, "Expansion filename " +fileName);
        if (!Helpers.doesFileExist(this, fileName, xf.mFileSize, false))
            return false;
    }
    return true;
}

It uses the class XAPKS wich represents an expansion file, be it either a main or patch file, having a certain filesize(bytes) and associated with a apk version (the one it was first added in).

private static class XAPKFile {
        public final boolean mIsMain; // true
        public final int mFileVersion; //example 4
        public final long mFileSize; //example 126515695L
        // example => main expansion that was first introduced in apk version 4 and is 126515695 bytes in size

        XAPKFile(boolean isMain, int fileVersion, long fileSize) {
            mIsMain = isMain;
            mFileVersion = fileVersion;
            mFileSize = fileSize;
        }
    }

Its also quite easy to read movie files and other stuff directly from the expansion file using the zip tools that google has provided (com.android.vending.zipfile).

First get the expansionfile using the methods provided in the library, the paremeters are integers that represent your main expansion apk version (the apk version where the expansion pack you need was first added) and the patch apk version.

ZipResourceFile expansionFile = APKExpansionSupport.getAPKExpansionZipFile(context, APKX_MAIN_APK, APKX_PATCH_APK);

Video

For playing video directly from this zipresourcefile:

AssetFileDescriptor a = expansionFile.getAssetFileDescriptor(pathToFileInsideZip);

Now from this assetFileDescriptor you can get a FileDescriptor and use this in your mediaplayer, the correct syntax to get your mediaplayer to play the video also needs the second and third parameter.. Be it the startoffset and length you can get from the AssetFileDescriptor.

player.setDataSource(a.getFileDescriptor(), a.getStartOffset(), a.getLength());

Other

For all the other stuff (like images) you can just get an inputstream of the zipresourcefile:

expansionFile.getInputStream(pathToFileInsideZip);`

ALSO make sure you don't compress the videos in the zip for this to work! for example not to compress .mp4 files:

zip -n .mp4 -r zipfile.zip . -x ".*" -x "*/.*"
Jordy
  • 1,624
  • 1
  • 19
  • 30
  • Thank you for the Explanation. 1) Any Other Alternate is there or not 2) we are able or not to access obb files directly without upload the apk in play store. – Raj Jan 24 '18 at 05:16
3

Just want to add some things that I learned in the process of implementing this:

1) As of now, you do not need to implement the downloader library and all the XAPKFile stuff, all you need to do is copy/paste all the permissions that are listed on https://developer.android.com/google/play/expansion-files.html into your manifest file. Maybe you used to, but Google Play Store handles the downloading and installing for you. The only reason you would need to handle actual downloading in your source code is if the user manually went into Android/obb and deleted your expansion files.

2) When uploading your .zip file, you don't have to name it to the main.version.package.obb convention. Simply upload your .zip file with its original name, and it will be renamed for you regardless.

3) To access the zip file, go to File > New > Import Module, and import the zip_file library that is in the same directory as the downloader and licensing libraries. Make sure to add to your dependencies in the build.gradle file for your app: compile project(':zip_file'). This makes it so you can import those libraries in your project.

I hope that is helpful. I basically spent hours trying to implement the (complicated) downloading library code that is listed on the site, and in the end I deleted all of it and just kept the permissions in the manifest, and it works fine.

  • Thank you for the Explanation. 1) Any Other Alternate is there or not 2) we are able or not to access obb files directly without upload the apk in play store. – Raj Jan 24 '18 at 05:16
-8

In Eclipse your project,click right mouse key,follow the steps: Android Tools->Export Signed Application Package -> ....

enjoy-writing
  • 520
  • 3
  • 4
  • Please let me know the steps to implement Application Licensing. I have look at the developer site. Still i require some more help on it. – user1414154 Jul 30 '12 at 06:36
  • @user1414154 google's apk extension files guide is very good,or go trough above details.In single line i can tell u just import all libs Marketlicensing,downloader_library,zip_file and sample code from C:..\androidsdk\extras\google\play_apk_expansion\downloader_sample from sdk C:...\android-sdk\extras\google folder and go to properties add the libraries to sample code, before uploading into gplay change the package name and add base64 code, apk expansion file byte size to SampleDownloaderService.java and sove the crc bug if you want! after running you may get some bugs http://goo.gl/2JhWg – LOG_TAG Aug 01 '12 at 04:20
  • the user asked for apk expansion files, not exporting the project to an apk. – Jeongbebs Apr 24 '14 at 02:49
  • thats not about the signed apk user ask about Apk expansion file. – Buggy IdioT Jan 08 '15 at 12:14