NDK and resource files on Android

Some while a go I have started to play with the Android platform and the NDK, being curious about what does offer.

One of issues I found annoying was the resources issue. While you could embed resources in the application .apk file, and access them from java easily, accessing them from native code is not so easy, and seems like there is no supported/easy way to do it. The main issue is that the resource files are stored inside the apk file, which is a zip file (if I understood correctly) and as for now, is not unpacked after application install.

There are some workarounds for this, like:

  • retrieving the path to the apk itself, and uncompress it from native code to retrieve the required resource files.
  • try to store the resource in a format which won’t be compressed (mp3 for example), by renaming the resource to a file extension we know is not compressed. Then from java obtain the file descriptor, offset and length of the file, and from native code get the handle from file decriptor, then usingthe offset and length, open the file and read the resource file.

One more friendly approach would be to have the resources renamed to shared library extension. We know, in order to be able to run the native code, when installing the application, these shared libraries have to be extracted somewhere and stored separately from the apk file. By having our resource file delivered as shared library, the installer does all the job of putting the file to a right place, all we have to do is to open the file and read our data.

There are however some limitations / rules to be followed:

  • the resource name must be (at least with ndk 1.6) following the lib[ResourceName].so or it won’t be deployed in the application lib folder on install.
  • the path of the resource should be fixed (you can put it either in the libs/armeabi/ folder, or in libs.armeabi package).
  • the library’s path will be at /data/data//lib/lib[ResourceName].so

Bellow is an example of opening such a resource (libResource.so) file from native code:

void appInit()
{
	char str[1024];
	bzero(str, 1024);

	int handle = open("/data/data/com.package.test0/lib/libResource.so", O_RDONLY);

	if( handle < 0)
	{
		__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG,"Error oppening the file!\n");
	}
	int res = read(handle, str, 1024);

	if( res < 0)
	{
		__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG,"Error reading from the file!\n");
	}

	if (handle > 0)
	{
		close(handle);
	}

	__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG,
			"Loaded from resource: %s\n", str);
}

In order to minimize the number of installed resources as shared library, a virtual filesystem could be implemented, this way only one shared library is copied additionally to the application’s shared library.

I have tried this and seems to work in emulator. I hope also works on real devices.

Leave a Comment

Trackbacks and Pingbacks: