初識Android NDK

來源:互聯網
上載者:User

標籤:android   blog   http   io   ar   os   使用   sp   java   

本文介紹Windows環境下搭建Android NDK開發環境,並建立一個簡單的使用Native代碼的Android Application。

一、環境搭建

二、JNI函數綁定

三、例子

 

一、環境搭建

1. 作業系統:Windows7 64位

2. 安裝Java,最新的JDK8貌似還不支援,敢於折騰的同學可以試試,下載JDK7安裝即可,別忘了添加JDK的bin目錄到PATH環境變數。http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html。"jdk-7u71-windows-x64.exe"

3. 下載Android ADT Bundle,https://developer.android.com/sdk/index.html。"adt-bundle-windows-x86_64-20140702.zip"

4. [可選]使用SDK Manager更新到最新,本文編輯之時API Level已經更新到21了。

5. 下載NDK開發包,解壓即可,路徑要固定不要輕易改動,因為Eclipse的NDK外掛程式會配置這個路徑。https://developer.android.com/tools/sdk/ndk/index.html。"android-ndk-r10b"

6. 安裝NDK外掛程式,在Eclipse中,開啟菜單Help>Install New Software,Work with裡用下拉式功能表選擇Android Developer Tools Update Site,下面就會出現Developer Tools的分組,展開選擇Android Native Development Tool,點擊Finish安裝。不用選擇Developer Tools裡面其他的外掛程式,它們已經安裝好了。

從NDK r7開始就不需要使用cygwin了,因此以上就是所有的環境搭建步驟。

 

二、JNI函數綁定

先在Eclipse中建立一個Android Project。然後添加Native支援,在Project Explorer中右鍵選擇建立的工程,在菜單中選擇Android Tools>Add Native Support,會自動建立好JNI目錄和Android.mk,以及配置好C\C++ Include路徑。

JNI中Java方法調用Native方法的綁定有兩種方法:一種是自動綁定,只需要C函數名和Java方法名稱按照一定的規則能匹配上就能自動綁定。可以通過javah工具將綁定的規則都處理好,產生標頭檔方便使用,也可以根據規則自己定義函數,不使用產生標頭檔的方法。具體的規則是:

1. C函數要加上首碼"Java_"。

2. Java中package路徑中的圓點要轉換成底線,類名和方法名都保持原樣,用底線隔開。

3. C方法中比Java方法多了兩個參數放在最前面,JNIEnv*和jobject。前者是起到C代碼和Java代碼互動作用的一個結構體指標,後者是調用這個函數的Java對象在C代碼中的代表。

4. Java調用Native方法還涉及到參數和傳回值的傳遞,Java中的類型會轉換為C中的對應類型,可以精確對應的類型有基礎資料型別 (Elementary Data Type)(如jint, jdouble)、數組(如jintArray)、String(jstring),其他類型一律當做Object(jobject)。

例如Java中定義的一個Activity的類:

package com.example.myhellojni;public class MyHelloJniActivity extends Activity {    private native String getNativeString();}

在C檔案中的對應函數:

jstring Java_com_example_myhellojni_MyHelloJniActivity_getNativeString(JNIEnv* env, jobject thiz) {    return ...;}

還有一種動態註冊的方法,使得C代碼定義的函數不必遵守命名規則也可以與Java中的方法綁定起來。這種綁定是在C代碼中實現的,需要在載入這個動態連結程式庫的時候的回呼函數JNI_OnLoad中註冊。註冊方法見代碼:

#include <jni.h>#include <stdlib.h>
// 要綁定到Java的native方法jstring ajey_getNativeString(JNIEnv* env, jobject thiz) { return (*env)->NewStringUTF(env, "what? this is a native string!!!!");}// 計算數組大小的小技巧,只能用於數組,不能用於指標(因為指標的sizeof得不到指標指向記憶體的大小)#define SIZE_OF_ARRAY(array) (sizeof(array)/sizeof(array[0]))static JNINativeMethod gMethods[] = { // 這個結構體數組是傳給register函數的參數,定義了java方法和C函數的對應關係
// 成員依次是java方法名稱、參數和傳回值簽名字串、對應的C函數名 { "getNativeString", "()Ljava/lang/String;", (void*)ajey_getNativeString },};static int registerNatives(JNIEnv* env) {
// 先找到java的class。注意gMethods中並沒有定義是哪個類的方法,需要在註冊的時候指明。 jclass clazz = (*env)->FindClass(env, "com/ajeyone/myhellojni/MyHelloJniActivity"); if (clazz == NULL) { return JNI_FALSE; }
// 這一步是真正註冊的地方 if ((*env)->RegisterNatives(env, clazz, gMethods, SIZE_OF_ARRAY(gMethods)) < 0) { return JNI_FALSE; } return JNI_TRUE;}jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) { JNIEnv* env = NULL;
// 第一步擷取JNIEnv if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) { return -1; } // 第二步註冊 if (!registerNatives(env)) { return -1; } // 成功返回表示JNI version的常量,失敗返回-1 return JNI_VERSION_1_4;}

以上代碼有一個奇怪的地方:env指標(vm指標也是這樣)使用這種方式來調用函數:(*env)->function(env, ...),原因是JNIEnv實際上是typedef定義的指標類型,那麼JNIEnv* env就是二級指標,因此需要(*env)->的方式來使用;而且有點像C++中對象成員函數的調用,但這些代碼不是用C++編譯的而是用C編譯的,實際上是結構體中定義了函數指標,所以需要將"this"指標顯式地傳遞過去,也就是env本身。jni.h中也為C++定義了基於對象的訪問JNIEnv的方式,實際上是對C函數的封裝,使其在C++中更容易使用,如果你的代碼是寫在cpp檔案中的,那麼使用的就是C++對象的方式,這時JNIEnv不再是一個typedef的指標,而是一個類類型,直接使用env->function(...)就行了,而且也不需要將env當做第一個參數傳遞給function。

 

三、例子

使用Android Tools>Add Native Development Support的時候,將Library名稱定義成MyHelloJni。需要注意的是不要忘記寫載入動態庫的代碼,否則肯定是找不到Native方法的。在Eclipse中C\C++代碼不會在儲存時自動編譯,需要自己在菜單中選擇Build或者在運行App時觸發編譯。

前面Java代碼中Activity的全部內容:

package com.ajeyone.myhellojni;import android.app.Activity;import android.os.Bundle;import android.widget.TextView;public class MyHelloJniActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);TextView text = new TextView(this);
text.setText(getNativeString());setContentView(text); // 保持簡單,未使用layout檔案}private native String getNativeString();static { // 放在這裡是一般的做法,如果有需求可以在其他地方載入System.loadLibrary("MyHelloJni"); // 千萬不要忘了載入動態庫}}

 

初識Android NDK

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.