一步一步學習androidNDK編程(hello world)

來源:互聯網
上載者:User

標籤:android   ndk   

         上一篇部落格,已經搭建好了windows下的linux環境(cygwine),這次我們試著寫一個hello world。首先需要去android的官網下載android-ndk壓縮包,之後解壓,進入解壓後的目錄,我們發現有一個ndk-build的指令檔,這個指令檔就是我們用交叉編譯的檔案。我們通過  "./ndk-build"  來運行該命令,如:


        因為目前我們沒有編譯任何c代碼,所以會提示"could not find application project directory"這樣的錯誤,這說明我們的ndk的環境,已經是ok的。但是如果我們每次執行該命令"ndk-build",難道都必須進入ndk的解壓縮目錄下來運行嗎?答案是"no",我們可以配置ndk的環境變數,就像配置java環境變數一樣。

        我們開啟cygwine的安裝目錄,我的是在c盤下的cygwine目錄下,也是預設的目錄,在該目錄下有一個etc檔案夾,在etc檔案夾下有一個profile的檔案,我們開啟它

將PATH原先的路徑:"PATH="/usr/local/bin:/usr/bin:" ,我們在"bin:"之後添加ndk的解壓縮的目錄,我的是在f:盤下,如:紅色標註的就是我新添加的ndk的路徑:


         完成之後,儲存,然後重新開啟cygwine,在任意目錄輸入"ndk-build" ,查看是否配置好了“ndk-build”的環境變數。

===============================================================================================


       接下來,我們來寫一個hello world,首先在eclipse下建立一個android工程,這裡我取名為"helloworld",建立好工程以後,我們需要在java代碼中申明一個native方法,如下:

public native String helloWorldNdk();
這裡注意,括弧後邊不能添加大括弧,因為我們只是聲明而並未實現該方法,native關鍵字,表明該方法的實現是在c語言層面實現的。

      接下來我們呢需要在helloworld工程下建立一個jni目錄。在該目錄下建立一個hello.c檔案,在編寫hello.c檔案之前,我們需要用javah產生public native String helloWorldNdk(); 方法對應的標頭檔,由於我們在MainActivity中聲明該方法,當我們用javac編譯的時候,由於用到了R檔案,導致產生位元組碼失敗,由於我們只是需要.h標頭檔,所以我們可以建立一個java工程,來產生.h檔案,如:


其中JavahTest.java中的內容,就是我們在Mainactivty中聲明的native方法,如下:

package com.test.example;public class JavahTest {public native String helloWorldNdk();}
接下來,我們產生.h檔案,首先運行javac產生.class位元組碼。

javac JavahTest.java

運行以上命令,會產生.class位元組碼,接下來產生.h檔案,如:


此時,會產生一個com_test_example_JavahTest.h檔案,該檔案內容如下:

#include <jni.h>/* Header for class com_test_example_JavahTest */#ifndef _Included_com_test_example_JavahTest#define _Included_com_test_example_JavahTest#ifdef __cplusplusextern "C" {#endif/* * Class:     com_test_example_JavahTest * Method:    helloWorldNdk * Signature: ()Ljava/lang/String; */JNIEXPORT jstring JNICALL Java_com_test_example_JavahTest_helloWorldNdk  (JNIEnv *, jobject);#ifdef __cplusplus}#endif#endif
其中jstring JNICALL Java_com_test_example_JavahTest_helloWorldNdk (JNIEnv *, jobject);

就是我們需要在hello.c中聲明的方法,這裡需要注意,由於我們的native方法是在MainActivity中聲明的,所以,我們需要將jstring JNICALL Java_com_test_example_JavahTest_helloWorldNdk (JNIEnv *, jobject);中的JavahTest替換成MainActivity,如下:

jstring Java_com_example_helloworld_MainActivity_helloWorldNdk(JNIEnv* env ,jobject obj)

     接下來就是完整實現hello.c的代碼,如下:

#include<stdio.h>#include<jni.h>jstring Java_com_example_helloworld_MainActivity_helloWorldNdk(JNIEnv* env ,jobject obj) {return (*env)->NewStringUTF(env,"hello world");} 
可以看到這裡我們返回"hello world"字串。


      記住,需要編譯該android工程中的c檔案,我們還需要編寫Android.mk檔案,同樣在jni目錄下,建立一個Android.mk檔案,內容如下:

   LOCAL_PATH := $(call my-dir)   include $(CLEAR_VARS)   LOCAL_MODULE    := hello   LOCAL_SRC_FILES := hello.c   include $(BUILD_SHARED_LIBRARY)
其中LOCAL_MODULE是我們需要編譯的模組名稱,這個名稱隨便命名的,LOCAL_SRC_FILES是我們需要編譯的源檔案

       當hello.c和Android.mk檔案都建立好了以後,我們就可以編譯該hello.c檔案了,開啟cygwine,進入該android工程,運行"ndk-build"命令,即可產生libhello.so檔案,如:

        同時,我們發現在helloworld的android工程中,產生了以下檔案:


          在libs目錄下產生的libhello.so檔案就是一個可以執行的二進位檔案。下面我們就要在java代碼中使用該二進位檔案。我們通過靜態代碼塊經該二進位檔案載入進來。如下:

static{System.loadLibrary("hello");}
        這裡需要注意的是:這裡的"hello",就是我們在Android.mk檔案中的 LOCAL_MODULE的值

       接下來就是,調運之前產生的二進位檔案,我們只需要在MainActivity.java中這樣寫即可

Toast.makeText(this,helloWorldNdk(),Toast.LENGTH_LONG).show();
 此時,當運行我們的helloworld工程,即會彈出toast,顯示我們在hello.c中返回的字串。

       到這裡,一個最基本的ndk實現就完成了,現在我在加上一個聲明的方法:

public native String hello_World_Ndk();
      那麼,我們的hello.c中的方法應該怎麼寫呢?參照之前的寫法:

jstring Java_com_example_helloworld_MainActivity_hello_World_Ndk

這裡需要注意,這種寫法是錯誤的,ndk會以為我們是在MainActivity中的內部類hello,以及hello中的內部類World中的方法Ndk,這樣顯然是不對的,ndk為這種情況提供了一個標準,我們需要在方法中的每一個底線之後加上數字1即可,如下:

jstring Java_com_example_helloworld_MainActivity_hello_1World_1Ndk(JNIEnv* env ,jobject obj) {return (*env)->NewStringUTF(env,"i am from china");} 
這一點,我們可以通過javah來產生,我在d:盤下建立一個MainActivity.java,內容如下:

public class MainActivity {public native String hello_World_Ndk();}
然後,我們進入d:盤運行如下命令,產生.h檔案,如:


此時在d:盤下產生了一個MainActivity.h檔案,內容如下:

JNIEXPORT jstring JNICALL Java_MainActivity_hello_1World_1Ndk  (JNIEnv *, jobject);
可以看到是以這樣命名的。

        這裡有一點需要注意的是,如果我們的類是有包名的話,此時運用javah來產生.h檔案的時候,首先要將產生的.class檔案拷貝到對應的包地下,然後運行如下命令:

javah   包名.類名      這樣才可以產生.h檔案。


       那麼現在呢,有了以上這些基礎之後呢,就可以為MainActivity.java中聲明的native方法直接產生.h標頭檔了,cmd進入命令列,首先進入helloworld工程的bin/classes目錄下,執行如下命令即可:

javah com.example.helloworld.MainActivity

此時,會在bin/classes檔案夾下新產生一個com_example_helloworld_MainActivity.h檔案,我們將該檔案拷貝到jni目錄下,如:


這個時候,我們的hello.c就可以這樣寫了:

#include<stdio.h>#include<jni.h>#include "com_example_helloworld_MainActivity.h"/*jstring Java_com_example_helloworld_MainActivity_helloWorldNdk(JNIEnv* env ,jobject obj) {return (*env)->NewStringUTF(env,"hello world");} jstring Java_com_example_helloworld_MainActivity_hello_1World_1Ndk(JNIEnv* env ,jobject obj) {return (*env)->NewStringUTF(env,"i am from china");} */JNIEXPORT jstring JNICALL Java_com_example_helloworld_MainActivity_helloWorldNdk  (JNIEnv * env, jobject obj) {  return (*env)->NewStringUTF(env,"hello world two");}JNIEXPORT jstring JNICALL Java_com_example_helloworld_MainActivity_hello_1World_1Ndk  (JNIEnv * env, jobject obj) {  return (*env)->NewStringUTF(env,"i am from china two");  }

      此時運行helloworld工程,toast會一次彈出"hello world two"和"i am from china two"


總結一下:

1.首先需要聲明native方法:

public native String helloWorldNdk();public native String hello_World_Ndk();
2.然後運用javah產生對應的.h標頭檔

3.根據.h標頭檔,編寫hello.c代碼

4.編寫Android.mk檔案

#交叉編譯編譯c/c++代碼所依賴的設定檔#擷取當前Android.mk的路徑  LOCAL_PATH := $(call my-dir)#變數初始化操作include $(CLEAR_VARS)#libhello.so 其實產生的libhello.so就是在我們這個模組的名稱前面加上lib後邊加上.soLOCAL_MODULE    := helloLOCAL_SRC_FILES := hello.cinclude $(BUILD_SHARED_LIBRARY)

5.在java中通過靜態快引入二進位檔案:

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

源碼下載





     





一步一步學習androidNDK編程(hello world)

聯繫我們

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