Android JNI GetMethodID 无法在发布版本中找到方法

Android JNI GetMethodID fails to find a method in release build

我正在 android 应用程序中从 C++ 调用 java 方法。在调试中工作正常,但 GetMethodID 在发布版本中失败。

// Java
public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        //...
        showKeyboard();
    }
    public void showKeyboard()
    {
        Log.i("my_app", "MainActivity::showKeyboard");
        //...
    }
}

// C++
JavaVM* gJvm; // Saved in JNI_OnLoad()
jobject gMainActivity; // Saved in call Java -> C++
                       // using JNIEnv->NewGlobalRef(mainActivity)
void my_thread_func() {
    JNIEnv* jniEnv = nullptr;
    gJvm->AttachCurrentThread(&jniEnv, nullptr);;
    jclass activityClass = jniEnv->GetObjectClass(gMainActivity);
    jmethodID methodId = jniEnv->GetMethodID(activityClass, "showKeyboard", "()V");
    // Debug build: methodId is valid
    // Release build: methodId is null
}

仅出于调试目的从 onCreate 调用 showKeyboard。我可以在输出中看到“MainActivity::showKeyboard”这一行。它在调试版本中也按预期工作。

我怀疑 java 优化启动并删除了发布中的方法。虽然它在 onCreate 中被调用,但它可能只是被内联。我试图添加 50 多行日志打印,希望阻止内联,但它没有改变任何东西。

有没有办法禁用此方法的 java 优化?或者我还能如何解决它?

是的,在发布模式下编译代码会启用 Proguard 缩小和混淆。如果你查看 documentation,你会发现几个选项:

  1. showKeyboard 方法上使用 @Keep annotation。这将被默认的 proguard 规则集获取并防止该方法被重命名或删除。
  2. 编写自己的 Proguard 规则以保留方法。我认为这应该是这样的:
-keep public class com.example.MainActivity {
    public void showKeyboard();
}