Home » Android » Android assets, C, JNI

Android assets, C, JNI

Posted by: admin June 15, 2020 Leave a comment

Questions:

How do you access an Android asset, such as a .txt file, from C with the JNI?

I’m trying “file:///android_asset/myFile.txt”, and locally “myFile.txt” with a duplicate of myFile.txt in the jni folder with the C implementation file.

How to&Answers:

The thing with assets is that you can’t access them directly as files. This is because the assets are read directly from the APK. They’re not unzipped to a given folder upon installation.

Starting from Android 2.3, there is a C API to access assets. Have a look at <android/asset_manager.h> and the assetManager field in <android/native_activity.h>. I’ve never used this though, and I’m not sure that you can use this asset manager API if you don’t rely on a native activity. And anyway, this won’t work on Android 2.2 and below.

So I see three options:

  • you could extract the assets into some directory but this will take extra space
  • you could (bunlde and) use something like libzip to read the assets from the APK in pure C.
  • or, to avoid bundling an extra library, my personal preference is to read data in C, using JNI, from the Java InputStream object returned by AssetManager.open(). It takes a little code but it works great.

Answer:

If you cannot use the AssetManager C API, because you need to call a C/C++ library that requires a filename, a raw resource can be used, instead.

The only disadvantage is that it needs to be copied to your app’s data (temp) dir at runtime.

Place the File in res/raw

Place the file you want to read from native code in the res/raw dir.

Make a Copy

At runtime, copy the file from res/raw/myfile.xml to the data dir:

File dstDir = getDir("data", Context.MODE_PRIVATE);
File myFile = new File(dstDir, "tmp_myfile.xml");
FileMgr.copyResource(getResources(), R.raw.my_file, myFile);

Now the filename to pass to your native code is myFile.getAbsolutePath()

copyResource (rsrcId, dstFile)

public static File copyResource (Resources r, int rsrcId, File dstFile) throws IOException
{
    // load cascade file from application resources
    InputStream is =  r.openRawResource(rsrcId);
    FileOutputStream os = new FileOutputStream(dstFile);

    byte[] buffer = new byte[4096];
    int bytesRead;
    while ((bytesRead = is.read(buffer)) != -1)
        os.write(buffer, 0, bytesRead);
    is.close();
    os.close();

    return dstFile;
}