Android NDK C ++ JNI(未找到本机实现…)


86

我正在尝试将NDK与C ++一起使用,并且似乎无法正确使用方法命名约定。我的本机方法如下:

extern "C" {
JNIEXPORT void JNICALL Java_com_test_jnitest_SurfaceRenderer_drawFromJni
(JNIEnv* env, jclass c)
{
   //
}
}

标题包装在extern“ C” {} aslo中。

一切都可以正常编译,创建一个.so文件,然后复制到我项目下的libs文件夹中,但是当我在Eclipse中调试并运行时,我不断收到一条日志消息,内容为“未找到针对本机的实现...”。因为所有NDK示例都在C中,所以我缺少什么吗?

谢谢。


您是否正在使用生成JNI存根javah?如果不是,你应该是。:-P
Chris Jester-Young 2010年

7
最有可能是因为您没有打给您System.loadLibrary
IgorGanapolsky '16

1
谢谢你的问题。我今天学到新东西。
Shady Mohamed Sherif

Answers:


148

有几件事可能导致“找不到实现”。一种是错误的函数原型名称,另一种则根本无法加载.so。您确定System.loadLibrary()在使用该方法之前已调用该方法吗?

如果没有JNI_OnLoad定义函数,则可能要创建一个函数并让其吐出一条日志消息,以验证是否已成功拉入库。

您已经避开了最常见的问题-忘记使用extern "C"-所以是上面的问题或一些轻微的拼写错误。Java声明是什么样的?


13
耶稣!您为我节省了数小时的工作-在阅读本文时,我刚刚记得我把loadLibrary呼叫注释掉了……
zeboidlund 2012年

11
你也救了我!我对函数名和其他几项进行了四重检查……但是我忘记了extern“ C”,甚至在问题中都没有注意到它!
Qwertie 2012年


2
还有一种情况没有人告诉您:您不能在函数名称中使用'_'(下划线),因为下划线被视为包分隔符。因此,只能使用驼峰式案例函数名称
Nulik

2
@Nulik:如果将“ _”转义为“ _1”,则可以使用“ _ ”。
fadden

18

导致此错误的另一个原因:未经修饰的本机方法名称不得包含下划线!

例如,我想导出一个名为的C函数AudioCapture_Ping()。这是我在C中的出口申报单:

JNI_EXPORT int Java_com_obsidian_mobilehashhost_MainActivity_AudioCapture_Ping(JNIEnv *pJniEnv, jobject object);  //Notice the underscore before Ping

这是我的Java类导入函数:

package com.obsidian.mobileaudiohashhost;
...
public class MainActivity extends Activity {
    private native int AudioCapture_Ping();  // FAILS
    ...

在删除下划线之前,我无法让Android动态链接到本机方法:

JNI_EXPORT int Java_com_obsidian_mobilehashhost_MainActivity_AudioCapturePing(JNIEnv *pJniEnv, jobject object); 

package com.obsidian.mobileaudiohashhost;
...
public class MainActivity extends Activity {
    private native int AudioCapturePing();  // THIS WORKS!
    ...

5
Java语言声明中出现的“ _”必须在本机声明中替换为“ _1”。请参阅docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/…中的表2-1 。
渐行渐远的

1
很明显,但是经过几个小时的调试,我还是无法自行解决……谢谢,您救了我!
乔治·阿塞夫

@ user1222021我有一个问题,我们可以为项目中的所有活动导出cpp方法,是否需要在.cpp文件中的方法中指定活动名称?
Balflear19年

14

我遇到了同样的问题,但对我来说,错误出在文件Android.mk中。我有:

LOCAL_SRC_FILES := A.cpp
LOCAL_SRC_FILES := B.cpp 

但应具有以下内容:

LOCAL_SRC_FILES := A.cpp
LOCAL_SRC_FILES += B.cpp 

注意细节+ =而不是:=

希望对您有所帮助。


2
或者,您可以将它们全部添加到一行上,或者使用`\`换行符。
IgorGanapolsky '16

6

如自动生成的Studio示例中所提供的那样称为extern“ C”,但是忘记将文件的其余部分(包括以下函数)包装在{}括号中。只有第一个功能起作用。


4

另一个原因:在android.mk中使用LOCAL_WHOLE_STATIC_LIBRARIES而不是LOCAL_STATIC_LIBRARIES。这将阻止库优化未使用的API调用,因为NDK无法检测到Java代码对本机绑定的使用。


1
区别在哪里:“在android.mk中使用LOCAL_WHOLE_STATIC_LIBRARIES代替LOCAL_STATIC_LIBRARIES”
乔什(Josh)


2

使用javah(Java SDK的一部分)。它正是为此的工具(从.class文件生成.h标头)。


2

如果软件包名称中包含_字符,则应在_字符后写1(一个),如下所示:

MainActivity.java

package com.example.testcpp_2;

本机lib.cpp

JNICALL
Java_com_example_testcpp_12_MainActivity_stringFromJNI(

0

我尝试了所有上述解决方案,但是没有人可以解决我的构建错误(jni java.lang.UnsatisfiedLinkError:找不到实现...),最后我发现我忘记将我的verify.cpp源文件添加到CMakeList.txt中add_library segement(verify.cpp是通过Ctrl +输入短键(也许是其他文件名)自动生成的),希望我的回答对您有所帮助。

我的构建环境:Gradle + CMake


0

我遇到了同样的问题,在我的情况下,原因是我在软件包名称“ RFID_Test”中加了下划线,因此我将该软件包重命名,并且可以正常工作。谢谢user1222021


-3

我两次遇到同样的问题。碰巧,我尝试从Android Studio启动该应用程序的手机使用的API级别尚未在Android Studio中下载。

  1. 将Android Studio升级到最新版本
  2. 从Android Studio中下载必要的API
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.