Search code examples
android-ndkproguardandroid-proguard

JNI RegisterNatives() can't find class method after running ProGuard


If I set minifyEnabled = true in Gradle setting for my Android app, calling the JNI function RegisterNatives() from the JNI shared library doesn't find its target class anymore. I tried a number of ProGuard rules but still can't get it to work.

Java code:

package net.pol_online.hyper;

...

public class Hyper extends Application {
  ...
  public native static void initializeLibrary(Context context, int maxImageMemoryCacheSize);
  ...
}

JNI code:

static JNINativeMethod _methods[] = {
    {"initializeLibrary", "(Landroid/content/Context;I)V", reinterpret_cast<void*>(&_InitializeLibrary)},
    ...
}

JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
  ...

  _hyperClass = env->FindClass("net/pol_online/hyper/Hyper");
  jint error = env->RegisterNatives(_hyperClass, _methods, sizeof(_methods) / sizeof(JNINativeMethod));
  assert(error == JNI_OK);

  ...
}

Gradle build settings (using the experimental Gradle NDK plug-in for Android Studio):

android.buildTypes {
    release {
        minifyEnabled = true
        proguardFiles.add(file("proguard-rules.txt"))
        ndk.with {
            CFlags.add("-Werror")
            cppFlags.add("-Werror")
        }
    }
}

ProGuard rules:

-keep class butterknife.** {
  *; 
}
-keep class **$$ViewBinder {
  *;
}
-keepclasseswithmembernames class * {
  @butterknife.* <fields>;
}
-keepclasseswithmembernames class * {
  @butterknife.* <methods>;
}
-dontwarn butterknife.internal.**

-keep public class net.pol_online.hyper.**

-dontnote android.support.v4.**
-dontwarn android.support.v4.**

The crash at launch:

Failed to register native method net.pol_online.hyper.Hyper.initializeLibrary(Landroid/content/Context;I)V in /data/app/net.pol_online.hyper-1/base.apk

java.lang.NoSuchMethodError: no static or non-static method "Lnet/pol_online/hyper/Hyper;.initializeLibrary(Landroid/content/Context;I)V"'


Solution

  • You do not include the default Proguard configuration for android:

    proguardFiles getDefaultProguardFile('proguard-android.txt')
    

    which includes a configuration to keep all native methods:

    -keepclasseswithmembernames class * {
        native <methods>;
    }
    

    This should fix the issue as well and is highly suggested.