Light notes

Workaround for Unable to load native library: libnative-activity.so

So, another bug I had to deal with NativeActivity and for which I have no clear solution but a workaround for.

The problem

I compiled a version of libnative-activity.so that depends on my own library, libmyy.so, in order to add more flexibility during the testing process.

However, when trying to load the app, the app crashed with the following error :

    05-23 22:59:00.650: E/AndroidRuntime(4758): Caused by: java.lang.IllegalArgumentException: Unable to load native library: /data/app-lib/my.pack.name-2/libnative-activity.so

The workaround

  • Create a java class that subclasses android.app.NativeActivity and load the libnative-activity.so library with System.loadLibrary, in a static initialiser.
  • Edit AndroidManifest.xml to use this library, and remember to set android:hasCode to true in the tag.

Example

Here the java class will be called NativeDebug

app/src/main/java/my/pack/name/NativeDebug.java

package my.pack.name;

import android.app.NativeActivity;

public class NativeDebug extends NativeActivity {
  static { System.loadLibrary("native-activity"); }
}

app/src/main/AndroidManifest.xml

<!-- The package name is generally set up by gradle. It is not very important here-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="my.pack.name">

  <!-- Actually this .apk Java has code ! Set hasCode to true. Else your NativeDebug
        class will not be inserted in the final apk and your app will crash failing to find it. -->
  <application
      android:allowBackup="false"
      android:fullBackupContent="false"
      android:icon="@mipmap/ic_launcher"
      android:label="AppName"
      android:hasCode="true">

    <!-- Our activity is the built-in NativeActivity framework class.
         This will take care of integrating with our NDK code. -->
    <activity android:name=".NativeDebug"
              android:configChanges="orientation|keyboardHidden">
      <!-- Tell NativeActivity the name of or .so -->
      <meta-data android:name="android.app.lib_name"
                 android:value="native-activity" />
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>
  </application>

</manifest>

Note that this AndroidManifest.xml is based on the one provided with the NDK sample named native-activity.

Then install the new app (./gradlew installDebug or Android Studio ▶ button) and try your application.
In my case, it worked ! The library was loaded, my library was loaded too in the process, and the native code in my library was executed !

I still do not understand why NativeActivity.java tries to load libraries with a native C++ method named loadNativeCode. However, I do understand that loadNativeCode returns 0 when trying to load my libnative-activity.so file and NativeActivity in return throws an exception, with no hint about the problem whatsoever. A slightly more useful exception message seems to have been added now, though…

In the case that System.loadLibrary fails to load the library, your app will still crash but with a nice and helpful error message that you can use to solve the problem, this time.