Android NDK開發常見錯誤

來源:互聯網
上載者:User

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而沒找到。

錯誤二:

 

 

 

一 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一下工程,再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

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

}

再次嘗試,調用成功!


 


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.