You’re a Bank shipped on Android on Thursday night (the iOS version is still under review). On Friday morning I was getting reports that the game wasn’t working on certain phones: people were seeing just a black screen, and no game.
I instantly went into a panic. How could this be? I had tested the game in several devices, and it was working perfectly well, without a hitch. Besides, I was using Moai, which is a stable engine with several games shipped and working without issue.
The first thing I did was to locate a phone were I could work on the issue. My initial report was that the problem was occurring in a Galaxy Nexus, so I borrowed one to test. I was immediately able to reproduce it. To my surprise, uninstalling the game and reinstalling the APK seemed to fix the problem. It had something to do with actually shipping the game on Google Play. Great.
As a curiosity, I discovered right after publishing the game that you can’t buy from yourself on Google Play. I had to actually use a different account to buy the game, and was then able to observe the problem both on my phone (a Nexus S) and my tablet (a Galaxy Tab 10.1). Then I started putting some serious time into debugging it.
The submission process for Google Play is very straightforward. You upload a new APK with an updated version, hit Publish and you’re done. It takes about 2 hours for the update to go through the process that ends with it showing up in the market. So that was my turnaround time for trying things.
I added a bunch of logs to figure out what the problem was, and submitted an update. At the same time, I compiled Moai from source so I could add more logs into the engine itself; prior to this I had been using the stock 1.3 version, as I didn’t need to make any changes.
Little by little the picture got a little clearer. Moai was unable to run the file main.lua, the entry point of the game. Also, I found out about some changes that Jelly Bean introduced into how Google Play handled paid app files (more details than you care for here). It clicked. The game was working fine on previous versions of Android, like Ice Cream Sandwich, but failing on Jelly Bean.
Another submission and some more logs revealed that the problem was that Moai couldn’t find the file main.lua. Something that Google Play was doing to the app made Moai unable to open my files.
A deep dive into the Moai source code exposed how their file handling works. Android packages (APK files) are actually simple zip files. When you download an app, the system doesn’t bother to decompress it; instead, it stores the APK as is, and decompresses the files on the fly, as needed. Moai uses this fact to read directly from the APK using zlib, which is a nice, efficient way of doing it, as you’re talking directly to the underlying operating system, eliminating the overhead of going through the Java layer.
This is still possible after the Jelly Bean update, but there is a problem. Instead of a single file containing the APK, Google Play will now create two files. The first one, called “res.zip”, contains just the resources for the app (everything under the “res” folder). The second one, called “pkg.apk” is the actual APK.
Moai was successfully mounting the first file, but all of my scripts, images and sounds were in the “assets” folder, as they should, according to the Android pipeline.
The solution, it turns out, is to tell Moai to mount the other file. This is the change to the file MoaiActivity.java (highlighted):
ApplicationInfo myApp = getPackageManager ().getApplicationInfo ( getPackageName (), 0 );
Moai.mount ( "bundle", myApp.sourceDir );
Moai.setWorkingDirectory ( "bundle/assets/@WORKING_DIR@" );
I’m in contact with the Moai developers to get this fix into the official repository.
For reference, this is the documentation for the “publicSourceDir” variable, in the ApplicationInfo class, that explains what the difference is with “sourceDir”. This only applies to forward-locked apps (a nice tip that I wish I’d known is that you can test forward-locked apps with adb by using the -l option )
And that’s it. A small change, with a big impact. A potential concern is that, moving forward the Moai implementation is still non-standard, in that it bypasses the official API to access file resources on Android, so the potential is there for it to break again in the future. But for now, my game looks like this again in Jelly Bean devices: