【问题标题】:Native application with java class. Can't call native code from java带有 java 类的本机应用程序。无法从java调用本机代码
【发布时间】:2015-03-29 05:46:51
【问题描述】:

我想在本地活动的情况下从 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 生成签名。
我的安卓.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 端看不到原生端实现呢?

【问题讨论】:

  • 也许这个方法在你的引擎中是静态的。所以你应该像这样声明它 public static native void onSpeechRecognized (String value);
  • 不,它不是静态的JNIEXPORT void JNICALL Java_com_company_appname_SpeechRecognizerWrapper_onSpeechRecognized (JNIEnv *, jobject, jstring);
  • 阅读这里developer.android.com/training/articles/perf-jni.html#faq_ULE也许你会自己发现问题
  • 感谢您的链接,但没有任何帮助。使用 hello-jni 之类的解决方案,一切都很清楚。但是我还没有找到像我的情况一样的东西。我不明白实现必须位于何处 - 在单独的库中或在 android_main 所在的相同位置
  • 抱歉,我帮不上忙,但我可以给你这个视频,当我开始在我的应用程序中使用本机代码时,它对我有帮助 youtube.com/…

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


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    我注意到您正在编译 .ccp 文件而不是纯 C。为了让 jni 能够根据函数名称(而不是向 RegisterNatives 注册)自动查找函数,对象中的函数名称文件必须遵循特定的模式。

    您是否有可能没有声明函数“extern C”以防止 C++ 名称修改(这是 C++ 对目标文件中的函数进行重命名以便它们包含类型信息的做法,这将导致 jni 失败查找函数,因为目标文件中的函数名称不再符合正确的模式)。

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

    extern "C" { <your function here> }
    

    参见,例如,这个 SO 答案:

    UnsatisfiedLinkError for native cpp function in Android app (ndk)

    上述 nm 实用程序的输出似乎没有显示为该函数打印的完整行 nm。如果原始 nm 输出中函数名称的任一侧存在乱码,则可能表明该函数不是“extern C”,并且名称修改是您的麻烦的根源。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-08-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多