Reading resource files from native code

If you’re working with android-ndk and you want to open an asset included in your apk package, you should make a request via jni to the Resource manager in your java code.
Something like:

[cc]
public int[] openAsset( String path )
{
AssetFileDescriptor ad = null;
try
{
ad = getResources().getAssets().openFd( path );
Integer off = (int) ad.getStartOffset();
Integer len = (int) ad.getLength();
int res[] = { off, len };
ad.close();
return res;
} catch( IOException e ) {
Log.e( TAG, e.toString() );
}
return null;
}
[/cc]

However this is not a optimal solution expecially when you have tons of file io operations, also because I prefer to limit the amount of calls between java and C++.
A better solution I’m using is to open the current apk application using the libzip library. Just download the library and compile as static library, then include it in your Android.mk make file under the LOCAL_STATIC_LIBRARIES section.
What you have to do first is to send the current application filename from java, once at startup, in this way:

[cc]
PackageInfo info = null;
try {
info = getContext().getPackageManager().getPackageInfo(“com.example.text”, 0);
} catch( NameNotFoundException e ) {
Log.e( TAG, e.toString() );
return;
}
setAppName( info.applicationInfo.sourceDir );
[/cc]

and in the C++ code you will have the corresponding setAppName method:

[cc]
#include
#include
#include

char packageName[1024] = {0};
zip *pkg_zip;

JNIEXPORT void JNICALL Java_com_example_test_MySurfaceView_setAppName( JNIEnv * env, jobject obj, jstring pkgname )
{
const char *buffer = env->GetStringUTFChars( pkgname, false );

int error;
pkg_zip = zip_open( buffer, 0, &error );
strcpy( packageName, buffer );
if( pkg_zip == NULL ){
LOGE(“Failed to open apk: %i”, error );
}
env->ReleaseStringUTFChars( pkgname, buffer );
}
[/cc]

Now you have a reference to the zip package. In this way now you can query the zip package asking if a particular file exists:

[cc]
bool FileExists(const char* fname)
{
if( pkg_zip != NULL )
{
int result = zip_name_locate( pkg_zip, fname, 0);
return result != -1;
}
return false;
}
[/cc]

And open any of the files included in your apk package:

[cc]
FILE *FileOpen( const char* fname )
{
zip_file *zfile = zip_fopen( pkg_zip, fname, 0 );
uint32_t offset = 0;
uint32_t length = 0;

if( zfile != NULL )
{
offset = zfile->fpos;
length = zfile->bytes_left;
zip_fclose( zfile );
zfile = NULL;
} else
{
return NULL;
}

FILE *fp = NULL;
fp = fopen( packageName, “rb” );
fseek( fp, offset, SEEK_SET );
return fp;
}
[/cc]

Using this method you will have a FILE pointer to the whole apk file so you have to take care of the offset and length field when reading and seeking the file itself.

Disable asset compression with Android aapt

Trying to embed all the assets resources into my final apk was not so easy as I tought.. at least using the ADT Eclipse plugin for building project.
In fact, using AssetManager.openFd to return to the C++ code a FileDescriptor does not work with compressed sources.
When aapt compile the resources into the apk file it compress by default all the files which extensions are not recognized and those which recognize as text files.

These are the extensions not compressed:

[cc]
static const char* kNoCompressExt[] = {
“.jpg”, “.jpeg”, “.png”, “.gif”,
“.wav”, “.mp2”, “.mp3”, “.ogg”, “.aac”,
“.mpg”, “.mpeg”, “.mid”, “.midi”, “.smf”, “.jet”,
“.rtttl”, “.imy”, “.xmf”, “.mp4”, “.m4a”,
“.m4v”, “.3gp”, “.3gpp”, “.3g2”, “.3gpp2”,
“.amr”, “.awb”, “.wma”, “.wmv”
};
[/cc]

I was looking into the .project file of my Eclipse project but it seems that changing things inside that file ( like values into the tag ) does not affect the builder.

The first thing I tried was to remap the aapt executable using a shell script ( and renaming the original aapt file into _aapt ):

[cc]
#!/bin/bash

strParams=””
CWD=’dirname $0’

for i in $@; do
if [ $i = “-S” ]; then
strParams=”$(echo $strParams) -v -0 \”\””
fi
strParams=”$(echo $strParams) $i”
done

tool=”$CWD/_aapt $strParams”
$tool 1>&2
[/cc]

In fact, when building the project in eclipse I could see the whole output, but the files are still being compressed, even if I call the same command in a shell the assets aren’t compressed.
I haven’t yet find a solution so for the meantime I decided to use ant to build my project overriding the default “-package-resources” target in this way:

[cce]

Packaging resources
${asset.absolute.dir}
command=”package”
verbose=”${verbose}”
versioncode=”${version.code}”
manifest=”AndroidManifest.xml”
assets=”${asset.absolute.dir}”
androidjar=”${android.jar}”
apkfolder=”${out.absolute.dir}”
resourcefilename=”${resource.package.file.name}”
resourcefilter=”${aapt.resource.filter}”>

[/cce]

In this way the project is being compiled correctly and all my assets are embedded not compressed!

P.S. my claim token is: 7C8AATS7Q5A3