1. 程式人生 > >Android使用最新版本NDK開發步驟與環境配置

Android使用最新版本NDK開發步驟與環境配置

     問題二:使用c++來編寫本地庫,會有一些相容問題。

(1)直接黏貼HelloJni的stringFromJNI函式過來測試,提示Method 'NewStringUTF' could not be resolved解決方法:改為:將(*env)->NewStringUTF(env, "Hello from JNI !")改為return env->NewStringUTF("Hello from JNI !")即可

原因是:

         NDK plugin預設為我們生成的是cpp檔案,而C與C++呼叫函式的引數不一致,因此找不到函式,具體參考jni.h中的定義。cpp檔案中形如(*env)->Method(env, XXX)改成env->Method(XXX)即可。



(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)

[java] view plaincopy

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++");
}

     原因是1:

      被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++中的變數除支援區域性變數外,還支援類成員變數和全域性變數。使用者所編寫程式的類成員變數可能與全域性變數同名,我們以"."來區分。而本質上,編譯器在進行編譯時,與函式的處理相似,也為類中的變數取了一個獨一無二的名字,這個名字與使用者程式中同名的全域性變數名字不同。