Beyond 50 MB on Google Play – ShiVa Engine

Beyond 50 MB on Google Play

According to Google’s rules, the APK file of an Android app must not be bigger than 50 MB. Sometimes, that is just not enough. In this tutorial, you will learn how to make your big applications fit for the Google Play store by creating additional packages and caching them dynamically with ShiVa!

The 50 MB limit

Many games, especially those heavy on high quality artwork, simply do not fit into 50 MB, even with all the wonders of modern texture compression. According to Google’s guide, you are allowed to have two extension files for your app though, each of which can be up to 2 gigabytes in size. To get beyond the 50MB limit, you will have to split your game. While most of the things required to do so are listed in other tutorials such as Caching and External Sources and Launch a game from another game, both of which you might want to look at, I found that splitting for Google Play had its own particular twists and turns.

Resource STKs

There are at least two ways to do the splitting in Shiva. I used the external resource file approach, read the “Launch game from another game” tutorial to learn the other. The idea of the resource STK approach is to move large media files such as images, videos, sounds and so forth into the extension files. The resource files are created by right-clicking assets at the Data explorer and choosing “Add to export”:
exporting_scene

You can choose whatever resources you want to include, but I personally found it convenient to add entire scenes. ShiVa will pull in anything that the chosen asset needs, so for example choosing a material will add all textures that the material uses. Adding a scene will add everything that is in the scene. If you add several scenes which share resources, the export screen will list the shared items many times. But not to worry, ShiVa is smart enough to add them only once.
Once you have added all of the resources that you plan to move, export the data as Android STK.
export_as_android_stk

OBB Expansion Files

The STK file that you just created can be used directly as a google expansion file. Reading Google’s expansion file guide, you will find that Google Play will choose the location of the expansion files and what they will be called. The name of the main file will be main.x.packagename.obb, where x is the version code of the APK package with which you first uploaded the expansion file, and packagename is the entire bundle identifier of your game.
export_in_authoring_tool

If you are using the ShiVa Authoring Tool 1.4 to export your game APK, all of the information that defines the name of the extension files is found at Step 2: Authoring. With the information seen at the image above, the name of the main expansion file would be main.4.com.mycompany.mygame.obb.
If you are using two files, the name of the second file is the same, only it starts with “patch” instead of “main”.
The hard part is knowing where the file will be. According to Google’s guide, the files are put to the directory $shared-storage/Android/obb/$packagename/ where packagename is again the same com.mycompany.mygame. The shared-storage directory is said to be found using the Android API command getExternalStorageDirectory(). How do you read such a value? If you own Shiva Advanced, you could create a plugin, or you could do like I did and spend a couple of days learning hooks and callbacks.
However, by far the simplest way is using one of the many plugins created by Julien Pierron, namely jpDeviceInfo. JpDeviceInfo is free, and since version 1.5 it has a command for reading this particular value (thanks a lot, Julien!). The command is called jpDeviceInfo.getExternalStorageDirectory(). To use the plugin, you download the STE, go to Import -> Archive from ShiVa’s Data Explorer and drag the plugin into the Game Editor’s “Plugins” tab.

Caching Google OBBs

Using the data from the resource file has its own gotchas as well. Just like in the Caching and External Sources tutorial, I created a state for downloading the data and a string variable by the name resourcefileurl.
In onEnter, I query the name of the directory and save it for further use.

--------------------------------------------------------------------------------
function mainai.loadextensionstate_onEnter ( )
--------------------------------------------------------------------------------
        --On PC I'm debugging by using the resource file from c:\.
        local extensiondir="/c:"
        --On Android this will return the actual file path.
        if(jpDeviceInfo.getExternalStorageDirectory ( )~=nil) then
            extensiondir=string.format ( "%s/Android/obb/com.mycompany.mygame",jpDeviceInfo.getExternalStorageDirectory ( ))
        end
        local resourcefile=(string.format ( "%s/main.4.com.mycompany.mygame.obb",extensiondir))
        this.resourcefileurl (string.format ( "file:/%s",resourcefile))
    end
--------------------------------------------------------------------------------
end
--------------------------------------------------------------------------------

In onLoop, I’m doing the actual loading, exactly like in the caching tutorial.

--------------------------------------------------------------------------------
function mainai.loadextensionstate_onLoop ( )
--------------------------------------------------------------------------------
	    local nProgress = cache.getFileStatus  ( "resmain.stk" )
    log.warning ( "STK loading onLoop progress: "..nProgress )
    if ( nProgress < 0) then
        cache.empty ( )
        cache.addFile ( "resmain.stk", this.resourcefileurl ( ) )
    end
    if (nProgress == 1) then
        this.anotherstate( )
    end
--------------------------------------------------------------------------------
end
--------------------------------------------------------------------------------

Inside onLoop however, there is the gotcha. If you were to use the cache.addFile command the "regular" way, cache.addFile ("main.4.com.mycompany.mygame.obb", this.resourcefileurl ( )), it will not work. The editor will pretend that everything is fine, but on Android the resource just won't load.
The first parameter of addFile must end in ".stk". However, the parameter does not need to have anything to do with the actual name of the file. Just pick something that ends in ".stk".
Later on, when you use the resources from the file, prefix any of your resource names with the same text, but without the ".stk" extension. So to load a scene called "myscene" from resource file in the case above, use
application.setCurrentUserScene ( "resmain/myscene" )
Now would be a good time to make a backup.
Next, remove the resources that are in the cache STK from the game editor to shrink the size of the main APK. When you rebuild the APK, notice how the APK Version Code has an effect on the name of the expansion file.
remove_scene

To add your extension files to Google Play, send in a new APK. At the summary page that comes after APK upload, there's a place for adding the extension files.

Credits

Written by Ville-Petteri Sipola with ShiVa version 1.9.2 in mind.


  • slackBanner