使用java类的本机应用程序。无法从java调用本机代码

时间:2015-01-29 20:44:13

标签: android android-ndk java-native-interface native-activity

我希望在本机活动的情况下从java调用本机代码。

假设我在engine.so中有游戏引擎。 现在我想添加语音识别。 我添加了java wrapper-class并通过jni从本机代码开始语音识别。 我想将结果返回到原生方。 在jni示例之后,我在java类中声明了本机方法,并在识别完成后调用它:

public native void onSpeechRecognized ( String value );

我在engine.so中实现了这个方法。 当然我没有加载带有System.loadLibrary的engine.so,因为它已经加载了。 但java代码没有看到方法实现,报告:

FATAL EXCEPTION: main
java.lang.UnsatisfiedLinkError: onSpeechRecognized
    at com.company.appname.SpeechRecognizerWrapper.onSpeechRecognized(Native Method)
    at com.company.appname.SpeechRecognizerWrapper$SpeechRecognitionListener.onResults(SpeechRecognizerWrapper.java:92)
    at android.speech.SpeechRecognizer$InternalListener$1.handleMessage(SpeechRecognizer.java:428)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:130)
    at android.app.ActivityThread.main(ActivityThread.java:3687)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:507)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:842)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:600)
    at dalvik.system.NativeStart.main(Native Method)

nm实用程序显示engine.so包含Java_com_company_appname_SpeechRecognizerWrapper_onSpeechRecognized
使用javah生成签名 我的Android.mk

PROJ_PATH := $(call my-dir)
LIB_PATH := $(PROJ_PATH)/../../../../../Smart/Lib

include $(LIB_PATH)/Log/Projects/android/jni/Android-prebuilt.mk

...

LOCAL_PATH := $(PROJ_PATH)/../../../../../Smart/Smart
include $(CLEAR_VARS)
LOCAL_C_INCLUDES := \
    $(PROJ_PATH)/../../../../../Smart \
    $(LIB_PATH)/Hash
LOCAL_MODULE    := smart
LOCAL_SRC_FILES := Animation/TextureAnimation.cpp
LOCAL_SRC_FILES += Base/Director.cpp

...

LOCAL_CFLAGS += -DNDEBUG -O3 -mcpu=cortex-a8 -mfpu=neon -ftree-vectorize -mvectorize-with-neon-quad -std=gnu++11
LOCAL_LDLIBS := -llog -landroid -lGLESv2 -lEGL -lOpenSLES
LOCAL_STATIC_LIBRARIES := android_native_app_glue Slb freetype Image FileSystem Noise Log Math Threads SharedPtr vmath png jpeg ScriptEngine QuestEngine Time tremolo

include $(BUILD_SHARED_LIBRARY)

$(call import-module,android/native_app_glue)

那么为什么java方面没有看到本机端实现?

2 个答案:

答案 0 :(得分:0)

不知道为什么java wrapper-class看不到本机函数,但我只是使用本机代码中的RegisterNatives解决了这个问题。

答案 1 :(得分:0)

我注意到你正在编译.ccp文件而不是普通的C.对于jni能够根据函数名自动查找函数(而不是使用RegisterNatives注册),对象中函数的名称文件必须遵循特定的模式。

是否有可能没有声明函数“extern C”来阻止C ++名称修改(这是C ++在目标文件中重命名函数所做的事情,因此它们包含类型信息,这将导致jni失败找到该函数,因为目标文件中的函数名称不再适合正确的模式)。

如果是这样,您可以通过围绕要从JNI调用的函数来解决问题:

extern "C" { <your function here> }

参见,例如,这个答案:

UnsatisfiedLinkError for native cpp function in Android app (ndk)

上面的nm实用程序的输出似乎没有显示为该函数打印的完整行nm。如果原始nm输出中函数名称的两侧都有乱码,则可能表示该函数不是“extern C”,并且名称重整是您遇到问题的根源。