• Android NDK开发常见错误


    错误一:

    make: *** No rule to make target `/cygdrive/d/1-workspace/showmap-android-opengles/jni/showmap_opengles_OpenGLESRenderer.c', needed by `/cygdrive/d/1-workspace/showmap-android-opengles/obj/local/armeabi/objs/OpenGLESMap/showmap_opengles_OpenGLESRenderer.o'.  Stop.

    该错误是将showmap_opengles_OpenGLESRenderer.c改成showmap_opengles_OpenGLESRenderer.cpp后出现,当然android.mk文件里也作了对应改动

    删除 obj 目录,预计是有缓存信息导致去找showmap_opengles_OpenGLESRenderer.c而没找到。

    错误二:

    JNI:no implementation found in native...(转载http://laokaddk.blog.51cto.com/368606/1349386)

    一  javah引发的问题



    BUG:
    D/dalvikvm( 1704): Trying to load lib /data/data/com.ulang/lib/libulangaudio.so 0x41052a38
    D/dalvikvm( 1704): Shared lib '/data/data/com.ulang/lib/libulangaudio.so' already loaded in same CL 0x41052a38
    W/dalvikvm( 1704): No implementation found for native Lcom/ulang/AudioLib;. sayHelloEx ()Ljava/lang/String;
    D/AndroidRuntime( 1704): Shutting down VM
    W/dalvikvm( 1704): threadid=1: thread exiting with uncaught exception (group=0x409961f8)
    E/AndroidRuntime( 1704): FATAL EXCEPTION: main
    E/AndroidRuntime( 1704): java.lang.UnsatisfiedLinkError: sayHelloEx
    E/AndroidRuntime( 1704):       at com.ulang.AudioLib.sayHelloEx(Native Method)
    E/AndroidRuntime( 1704):       at com.ulang.One.onClick(One.java:76)
    E/AndroidRuntime( 1704):       at android.view.View.performClick(View.java:3480)
    E/AndroidRuntime( 1704):       at android.view.View$PerformClick.run(View.java:13983)
    E/AndroidRuntime( 1704):       at android.os.Handler.handleCallback(Handler.java:605)
    E/AndroidRuntime( 1704):       at android.os.Handler.dispatchMessage(Handler.java:92)
    E/AndroidRuntime( 1704):       at android.os.Looper.loop(Looper.java:137)


    发现第二个參数 javah生成为 jclass, 因此出错 ,
    要将其换成 jobject则能够.
    Javah并非全部情况都将第二项生成 jclass, 有时也是生成的jobject.
    NE:要特别注意!

    #define __cplusplus

    #ifdef __cplusplus
    extern "C" {
    #endif
    /*
    * Class:     com_ulang_AudioLib
    * Method:    sayHelloEx
    * Signature: ()Ljava/lang/String;
    */
    JNIEXPORT jstring JNICALL Java_com_ulang_AudioLib_sayHelloEx
     (JNIEnv *, jclass);

    #ifdef __cplusplus
    }
    #endif
    #endif




      在实验JNI接口调用的时候,发现时而成功,时而运行就异常。在logcat上就有提示:
      no implementation found in native ....
      后来搜索了一下网络,发现出现这样的情况有可能有几种情况
      1.函数名字写错了
      2.确认在更改了接口函数的时候。要又一次clean一下project,再rebuild all。

      在确认以上两点后。JNI接口调用的no implementation error没有出现了。




    (2)执行c++生成的.so库,若报下面错误:(既找不到函数)

    No implementation found for native Lcom/dgut/android/MainActivity;.stringFromJNI ()Ljava/lang/String;

    java.lang.UnsatisfiedLinkError: stringFromJNI

    at com.dgut.android.MainActivity.stringFromJNI(Native Method)

    解决方法:

    为供Java调用的c++函数前增加extern "C" 修饰。如:(NDK example里面的cpp文件也是这么声明的。參考hello-gl2)

    extern "C" {
    	JNIEXPORT jstring JNICALL Java_com_dgut_android_MainActivity_stringFromJNI( JNIEnv* env, jobject thiz );
    }
    
    JNIEXPORT jstring JNICALL Java_com_dgut_android_MainActivity_stringFromJNI( JNIEnv* env, jobject thiz )
    {
        return env->NewStringUTF("Hello from JNI bear c++");
    }
    
    原因是:

           被extern "C"修饰的变量和函数是依照C语言方式编译和连接的。

           首先看看C++中对类似C的函数是如何编译的:作为一种面向对象的语言,C++支持函数重载,而过程式语言C则不支持。

    函数被C++编译后在符号库中的名字与C语言的不同。

    比如,如果某个函数的原型为:void foo( int x, int y );该函数被C编译器编译后在符号库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字(不同的编译器可能生成的名字不同,可是都採用了同样的机制,生成的新名字称为“mangled name”)。_foo_int_int这种名字包括了函数名、函数參数数量及类型信息,C++就是靠这种机制来实现函数重载的。

    比如。在C++中,函数voidfoo( int x, int y )与void foo( int x, float y )编译生成的符号是不同样的,后者为_foo_int_float。
    相同地,C++中的变量除支持局部变量外,还支持类成员变量和全局变量。用户所编敲代码的类成员变量可能与全局变量同名。我们以"."来区分。

    而本质上,编译器在进行编译时,与函数的处理相似,也为类中的变量取了一个独一无二的名字,这个名字与用户程序中同名的全局变量名字不同。

    因此,若我们没有使用extern "C"修饰函数,依照C语言方式编译和连接,Jni调用将可能找不到该函数。

    错误三:

    JNI 调用时,一直报 No implementation found for native

     

    有一个可能是,假设调用的是C++的代码,必须加extern "C"

     

    【转】 jni 调用c和c++的差别.

     

    1、JNIEnv *env參数的使用

    全部JNI接口的第一个參数是JNIEnv *env, 在C中。用法是

    (*env)->NewStringUTF(env, "Hello from JNI!");

    但在C++中,其调用方法是

    env->NewStringUTF("Hello from JNI!");

    为什么有这样的差别呢,看看jni.h中关于JNIEnv的定义就能够知道了:

    #if defined(__cplusplus)

    typedef _JNIEnv JNIEnv;

    #else

    typedef const struct JNINativeInterface* JNIEnv;

    #endif

    能够看到,对于C和C++,定义有所不同,主要原因是C不支持类。所以採用了一种变通的方法。

     

    2、接口找不到

    在Java中调用JNI接口时,出现异常。察看日志。发现有例如以下错误:

    WARN/dalvikvm(422): No implementation found for native Lcom/whty/wcity/HelixPlayer;.setDllPath (Ljava/lang/String;)V

    检查了几遍代码,Cpp中确实定义了这个接口,并且细致对比了Java的包名、类名,确实没有错误,那为什么会出现这样的问题呢。后来突然想到。JNI接口 都是以C的方式定义的。如今使用C++实现,函数定义前是否须要加上extern "C"呢?为此定义了一个头文件。在CPP文件里include该头文件,头文件加上例如以下代码片断:

    #ifdef __cplusplus

    extern "C" {

    #endif

    #endif

    ...

    #ifdef __cplusplus

    }

    再次尝试,调用成功!



  • 相关阅读:
    The network connection was lost 文件下载错误提示
    ThinkPHP第一课 环境搭建
    Docs-.NET-C#-指南-语言参考-关键字-值类型:内置数值转换
    Docs-.NET-C#-指南-语言参考-关键字-值类型-:浮点数值类型
    Docs-.NET-C#-指南-语言参考-关键字-内置类型-值类型:整型数值类型
    Docs-.NET-C#-指南-语言参考-关键字-内置类型-值类型:值类型的功能
    Docs-.NET-C#-指南-语言参考-关键字:C# 关键字
    Docs-.NET-C#-指南-语言参考-预处理器指令:#pragma checksum(C# 参考)
    Docs-.NET-C#-指南-语言参考-预处理器指令:#pragma warning(C# 参考)
    Docs-.NET-C#-指南-语言参考-预处理器指令:#pragma(C# 参考)
  • 原文地址:https://www.cnblogs.com/jhcelue/p/7238192.html
Copyright © 2020-2023  润新知