在 Release 中找不到 void com.organization.app.Activity.a() 的实现

No implementation found for void com.organization.app.Activity.a() in Release

我想做的只是从我的 Java android activity 中调用在我的 C++ 代码库中实现的本机函数。签名可以是任何东西,但我们将其定义为 void fooBar().

我的工作区是以 gradle 个项目的树结构组织的,所有这些都是 "com.android.library" 个项目,除了 "com.android.application" 的应用程序。 所有项目都包含某种形式的 C++ 代码,其中一些包含 Java classes。 activity class 在根项目中 ("Core")。该函数的本机实现位于同一项目的 .cpp 文件中。

这是 logcat:

的错误输出
E/com.organization.app: No implementation found for void com.organization.app.Activity.a() (tried Java_com_organization_app_Activity_a and Java_com_organization_app_Activity_a__)
E/AndroidRuntime: FATAL EXCEPTION: Thread-9
    Process: com.organization.app, PID: 3607
    java.lang.UnsatisfiedLinkError: No implementation found for void com.organization.app.Activity.a() (tried Java_com_organization_app_Activity_a and Java_com_organization_app_Activity_a__)
        at com.organization.app.Activity.a(Native Method)
        at com.organization.app.Activity.onStart(Unknown Source:0)

在为 Debug 构建时,我可以完美地调用此 fooBar() 函数,但在 Release 中它会尝试使用不同的名称加载该函数。即,a()。 native端的函数签名是没有问题的,因为我只要把函数名改成Java_com_organization_app_Activity_a就调用成功了。 我也尝试添加更多函数,这些函数的新名称分别变成了 b()c()

我在哪里调用该函数似乎也不重要,所以它在这里说 onStart 的事实是无趣的。

我试着找了一个有类似问题的人,但都是C/C++中函数签名的问题。

我找到了解决方案。

我在 Debug 和 Release 之间进行了一些交叉引用,发现关闭 minifyEnabled 或删除 proguard 文件声明会使异常消失。在那之后,我查看了我正在使用的 proguard 文件(恰好是用于优化的默认文件)并看到了两个有趣的部分。

# For native methods, see http://proguard.sourceforge.net/manual/examples.html#native
-keepclasseswithmembernames class * {
    native <methods>;
}

^ 这部分应该确保我的本机函数没有从二进制文件中被丢弃。为什么会这样,我到现在都不知道。

# Understand the @Keep support annotation.
-keep class android.support.annotation.Keep

^ 这部分让我想到了使用 @Keep 来强制它不丢弃函数。经过一些测试和确认,事实证明这是一个有效的解决方案。

我会做一些进一步的测试来找出收缩器没有保留我的原生功能的根本原因,但既然我找到了解决方案,我会把它标记为已解决。希望这对以后遇到此问题的任何人有所帮助。