Android relies heavily on something called “resources” to access portions of the system that aren’t directly in the Java code. For instance, if you had an ogg file that you wanted to use to play a sound with, you would add it as
res/raw/foo.ogg. Then, during compilation, the
aapt tool transforms all your resources into a Java file called
R.java, which is basically a series of integers that can be used to reference the actual resources. For instance, to set up our hypothetical ogg file, we would do:
MediaPlayer mp = MediaPlayer.create(context, R.raw.foo);
That’s all well and good as far as it goes, and if you don’t have any reason not to use it, you should.
However, with Hecl, one of my goals is to make it very easy to create applications. This means:
No complex directory layout structure.
No big long build files that require tools like ant.
No complex compilation steps.
I’m not there yet, on the Android platform, which is a bit more complex than Java ME (where it is indeed so easy to create new Hecl .jars that it’s possible to do it on the fly via this web site: http://builder.hecl.org), but I am making progress.
One thing that a user might want to do is add their own files to the
.apk file that actually gets installed on the phone. Since it’s just a zip file, that’s pretty easy:
zip -r Hecl.apk res/raw/foo.ogg
However, without a resource, there is no way to access that file, so the question is: how can we get ahold of it somehow?
The first piece of the puzzle is Java’s
ZipFile class, which lets us open up a zip compressed file, such as the .apk file that contains the ogg file we’re interested in in this case.
The critical passage is getting ahold of the actual filename on the Android filesystem of the code that’s currently running. It turns out to not be too difficult, if a bit obscure:
String filename = this.getPackageManager().getApplicationInfo(packagename, 0).sourceDir;
With that information in hand, we can feed it to ZipFile, and then access the contents at run time.
It’s not a perfect nor complete solution, yet. So many of the Android API’s require a resource ID, so it takes some extra coding to do things from the
InputStream that we can get out of the zip file, but there may be ways to make this easier. For instance, we could simply dump the contents of
raw/ into an application specific data directory the first time an application runs, in order to at least be able to access the files as files, rather than InputStreams connected to ZipEntries. In any case, at least it’s possible to access files added to the .apk without requiring the compilation step.
I’m not sure how many other use cases there might be for direct access to the
.apk file, but if other people need to do this, hopefully this information will be helpful.