如何在使用NDK时正确命名本机函数

时间:2012-08-01 15:33:21

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

我正在尝试运行我的应用程序,但每当我调用本机函数时,它都会给我一个错误并且程序崩溃了。我确定它与我在Java或C中命名的方式有关。

这是我对Java函数的调用:

package my.commander;

public class RelayAPIModel {

    public static class NativeCalls {

        static {
            System.loadLibrary( "RelayAPI");
        }

        public native static byte InitRelayJava();

        public native static void FreeRelayJava();
    }

以下是.c文件中的函数:

void Java_my_commander_RelayAPIModel_FreeRelayJava( JNIEnv * env, jobject this ) {
    RelayAPI_DataValid = 0;
    RelayAPI_SetBaud = 0;
    RelayAPI_get = 0;
    RelayAPI_put = 0;
    RelayAPI_flush = 0;
    RelayAPI_delay = 0;
    RelayAPI_initilized = 0;
}


BYTE Java_my_commander_RelayAPIModel_InitRelayJava( JNIEnv *env, jobject obj  ) {
    ...
    ...
}

这里它们位于.h文件中:

void Java_my_commander_RelayAPIModel_FreeRelayJava( JNIEnv * env, jobject obj );

BYTE Java_my_commander_RelayAPIModel_InitRelayJava( JNIEnv *env, jobject obj );

这是我的LogCat:

08-01 09:58:21.933: E/AndroidRuntime(17170): FATAL EXCEPTION: main
08-01 09:58:21.933: E/AndroidRuntime(17170): java.lang.UnsatisfiedLinkError: InitRelayJava
08-01 09:58:21.933: E/AndroidRuntime(17170):    at my.eti.commander.RelayAPIModel$NativeCalls.InitRelayJava(Native Method)
08-01 09:58:21.933: E/AndroidRuntime(17170):    at my.eti.commander.MainMenu.initMain(MainMenu.java:241)
08-01 09:58:21.933: E/AndroidRuntime(17170):    at my.eti.commander.MainMenu.onCreate(MainMenu.java:81)
08-01 09:58:21.933: E/AndroidRuntime(17170):    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
08-01 09:58:21.933: E/AndroidRuntime(17170):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1611)
08-01 09:58:21.933: E/AndroidRuntime(17170):    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1663)
08-01 09:58:21.933: E/AndroidRuntime(17170):    at android.app.ActivityThread.access$1500(ActivityThread.java:117)
08-01 09:58:21.933: E/AndroidRuntime(17170):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:931)
08-01 09:58:21.933: E/AndroidRuntime(17170):    at android.os.Handler.dispatchMessage(Handler.java:99)
08-01 09:58:21.933: E/AndroidRuntime(17170):    at android.os.Looper.loop(Looper.java:130)
08-01 09:58:21.933: E/AndroidRuntime(17170):    at android.app.ActivityThread.main(ActivityThread.java:3683)
08-01 09:58:21.933: E/AndroidRuntime(17170):    at java.lang.reflect.Method.invokeNative(Native Method)
08-01 09:58:21.933: E/AndroidRuntime(17170):    at java.lang.reflect.Method.invoke(Method.java:507)
08-01 09:58:21.933: E/AndroidRuntime(17170):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
08-01 09:58:21.933: E/AndroidRuntime(17170):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
08-01 09:58:21.933: E/AndroidRuntime(17170):    at dalvik.system.NativeStart.main(Native Method)

我现在想澄清一下,我已尝试将C方法名称更改为Java_my_commander_RelayAPIModel_NativeCalls_FreeRelayJavaJava_my_commander_RelayAPIModel_NativeCalls_InitRelayJava。应用程序仍然无法启动,这就是LogCat:

08-01 11:22:10.735: E/AndroidRuntime(17441): FATAL EXCEPTION: main
08-01 11:22:10.735: E/AndroidRuntime(17441): java.lang.UnsatisfiedLinkError: InitRelayJava
08-01 11:22:10.735: E/AndroidRuntime(17441):    at my.eti.commander.RelayAPIModel$NativeCalls.InitRelayJava(Native Method)
08-01 11:22:10.735: E/AndroidRuntime(17441):    at my.eti.commander.MainMenu.initMain(MainMenu.java:241)
08-01 11:22:10.735: E/AndroidRuntime(17441):    at my.eti.commander.MainMenu.onCreate(MainMenu.java:81)
08-01 11:22:10.735: E/AndroidRuntime(17441):    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
08-01 11:22:10.735: E/AndroidRuntime(17441):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1611)
08-01 11:22:10.735: E/AndroidRuntime(17441):    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1663)
08-01 11:22:10.735: E/AndroidRuntime(17441):    at android.app.ActivityThread.access$1500(ActivityThread.java:117)
08-01 11:22:10.735: E/AndroidRuntime(17441):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:931)
08-01 11:22:10.735: E/AndroidRuntime(17441):    at android.os.Handler.dispatchMessage(Handler.java:99)
08-01 11:22:10.735: E/AndroidRuntime(17441):    at android.os.Looper.loop(Looper.java:130)
08-01 11:22:10.735: E/AndroidRuntime(17441):    at android.app.ActivityThread.main(ActivityThread.java:3683)
08-01 11:22:10.735: E/AndroidRuntime(17441):    at java.lang.reflect.Method.invokeNative(Native Method)
08-01 11:22:10.735: E/AndroidRuntime(17441):    at java.lang.reflect.Method.invoke(Method.java:507)
08-01 11:22:10.735: E/AndroidRuntime(17441):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
08-01 11:22:10.735: E/AndroidRuntime(17441):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
08-01 11:22:10.735: E/AndroidRuntime(17441):    at dalvik.system.NativeStart.main(Native Method)


现在,我认为错误在于上面的代码。如果你们都认为它没有任何问题,我将在这里添加更多信息,以防问题出现在其他地方。

我正在创建的这个应用程序使用上面的函数来调用已经使用了一段时间的库。该库以前用于在Palm Pilot程序中调用函数,该程序利用Palm的蓝牙功能。由于Android设备具有不同的蓝牙库/功能,我将代码添加到本机库以调用BACK到java代码,以访问Android设备的蓝牙功能。我不想在这里发布与此相关的所有代码,但如果有人觉得需要发布,我会的。

2 个答案:

答案 0 :(得分:6)

错误消息显示在:

my.eti.commander.RelayAPIModel$NativeCalls.InitRelayJava (Native Method)

所以请确保:

  • native方法声明确实在RelayAPIModel类中,而不是RelayAPIModel.NativeCalls嵌套类。
  • Java端的包名称为my.commander,而不是my.eti.commander

编辑:或者你可以在C方面解决这个问题。如果要在嵌套类中创建本机方法,则其正确名称为:

Java_my_commander_RelayAPIModel_00024NativeCalls_InitRelayJava()

00024是$ character的代码,它是Java internals中的嵌套类分隔符。此外,第二个参数(jobject Obj)的含义将不同 - 而不是this的{​​{1}}指针/类指针,它将是RelayAPIModel的一个。您将无法使用它来解析/调用RelayAPIModel.NativeCalls

中的方法

答案 1 :(得分:5)

您可以使用javah生成具有正确命名的本机文件的.h文件:

javah -jni -classpath bin/classes com.example.app.MyClass