天天看點

Android開發環境搭建NDK(系列二)

一、關于NDK:

NDK全稱:Native

Development Kit。

1、NDK是一系列工具的集合。

NDK提供了一系列的工具,幫助開發者快速開發C(或C++)的動态庫,并能自動将so和java應用一起打包成apk。這些工具對開發者的幫助是巨大的。

NDK內建了交叉編譯器,并提供了相應的mk檔案隔離CPU、平台、ABI等差異,開發人員隻需要簡單修改mk檔案(指出“哪些檔案需要編譯”、“編譯特性要求”等),就可以建立出so。

NDK可以自動地将so和Java應用一起打包,極大地減輕了開發人員的打包工作。

2、NDK提供了一份穩定、功能有限的API頭檔案聲明。

Google明确聲明該API是穩定的,在後續所有版本中都穩定支援目前釋出的API。從該版本的NDK中看出,這些API支援的功能非常有限,包含有:C标準庫(libc)、标準數學庫(libm)、壓縮庫(libz)、Log庫(liblog)。

二、NDK執行個體的實作:

于Windows環境下NDK的開發,如果使用的NDK是r7之前的版本,必須要安裝Cygwin才能使用NDK,是以為Eclipse需要配置的

builder,其實是執行Cygwin,然後傳遞ndk-build作為參數。在NDKr7開始,Google的Windows版的NDK提供了一個

ndk-build.cmd的腳本,這樣,就可以直接利用這個腳本編譯,而不需要使用Cygwin了。隻需要為Eclipse

Android工程添加一個Builders,就能讓Eclipse自動編譯NDK。

本文是講述NDK-r7下的實作執行個體。

下面是使用NDK-r7在windows下配置自動編譯的builders的過程(實際上對于Linux,隻需要修改ndk-build.cmd為ndk-build就可以了。)。

(1)先下載下傳安裝NDK-r7。

下載下傳位址:

下載下傳後解壓縮就可以用了。

(2)打開Eclipse,建立一個Android工程(我的取名為TestNdk),在工程目錄TestNdk下建立jni檔案夾,該檔案夾就用來儲存NDK需要編譯的檔案代碼等。

(3)建立并配置一個Builder:

(a)Project->Properties->Builders->New,建立一個Builder。

(b)在彈出的【Choose configuration type】對話框,選擇【Program】,點選【OK】:

(c)在彈出的【Edit

Configuration】對話框中,配置頁籤【Main】。

在“Name“中輸入新builders的名稱(我取名為Ndk_Builder)。

在“Location”中輸入nkd-build.cmd的路徑。

(我的是D:\AndroidDev\android-ndk-r7\ndk-build.cmd,根據各自的ndk路徑設定,也可以點選“Browser File

System…”來選取這個路徑)。

       在“Working

Diretcoty”中輸入${workspace_loc:/TestNdk}(也可以點選“Browse

Workspace”來選取TestNdk目錄)。

  (d)【Edit

Configuration】對話框中,配置頁籤【Refresh】。

      勾選“Refresh

resources upon completion”,

      勾選“The entire

workspace”,

      勾選“Recuresively include

sub-folders”。

  (e)【Edit Configuration】對話框中,配置頁籤【Build

options】。

      勾選“After a

“Clean””,

      勾選“During manual

builds”,

      勾選“During auto

      勾選“Specify working set of relevant

resources”。

      點選“Specify

Resources…”

      勾選TestNdk工程的“jni“目錄,點選”finish“。

點選“OK“,完成配置。

OK,到這裡Eclipse就能夠自動調用NDK編譯jin目錄下的C/C++代碼了。

(4)在TestNdk工程中建立一個JniClient.class(為了調用C/C++代碼),其内容如下:

package

com.ndk.test;

public class JniClient {

    static public native String AddStr(String strA, String

strB);

    static public native int AddInt(int a, int

b);

}

(5) 用cmd指令定位到JniClient.class 所在目錄,輸入“javac

JniClient.java“後回車,生成JniClinet.class檔案(如果是用的Eclipse建的工程,在TestNdk\bin

\classes\com\ndk\test目錄下就已經有JniClinet.class檔案了)。

(6)

将JniClinet.class拷貝到TestNdk\bin\classes\com\ndk\test目錄,将cmd指令定位到TestNdk

\bin\classes目錄,輸入”javah

com.ndk.test.JniClient“後回車,在TestNdk\bin\classes目錄下就生成了C++頭檔案

com_ndk_test_JniClient.h。com_ndk_test_JniClient.h的檔案内容如下:

/* DO

NOT EDIT THIS FILE - it is machine generated */

#include <jni.h>

/*

Header for class com_ndk_test_JniClient */

#ifndef _Included_com_ndk_test_JniClient

#define

_Included_com_ndk_test_JniClient

#ifdef __cplusplus

extern "C"

{

#endif

 * Class:    

com_ndk_test_JniClient

 * Method:    AddStr

 *

Signature:

(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;

 */

JNIEXPORT

jstring JNICALL Java_com_ndk_test_JniClient_AddStr

  (JNIEnv *, jclass,

jstring, jstring);

 * Method:    AddInt

Signature: (II)I

JNIEXPORT jint JNICALL

Java_com_ndk_test_JniClient_AddInt

  (JNIEnv *, jclass, jint, jint);

(7)在jni目錄下建立一個Android.mk檔案,其内容如下(詳細的文法以後再另外解釋):

LOCAL_PATH

:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE :=

TestNdk

LOCAL_SRC_FILES := com_ndk_test_JniClient.c

include

$(BUILD_SHARED_LIBRARY)

(8)将

com_ndk_test_JniClient.h拷貝到TestNdk工程的jni目錄下,

然後建立一個com_ndk_test_JniClient.c檔案完成頭檔案中函數的實作,其内容如下(本來

Java_com_ndk_test_JniClient_AddStr是想完成字元串相加的功能的,但資料轉換有點問題,想先寫完本文檔,後續再研究

jni資料類型的問題,是以隻簡單的傳回一個字元串。):

#include

"com_ndk_test_JniClient.h"

#include <stdlib.h>

<stdio.h>

#ifdef __cplusplus  

extern "C" 

{  

#endif 

  (JNIEnv *env,

jclass arg, jstring instringA, jstring instringB)

jstring str = (*env)->NewStringUTF(env, "HelloWorld from JNI

!");

    return str;      

* Class:     com_ndk_test_JniClient

*

Method:    AddInt

* Signature: (II)I

*/

JNIEXPORT jint

JNICALL Java_com_ndk_test_JniClient_AddInt

  (JNIEnv *env, jclass arg,

jint a, jint b)

    return a + b;

}  

編輯com_ndk_test_JniClient.c并儲存後,可以看到TestNkd工程下的obj/local/armeabi目錄下将自動生成libTestNdk.so庫。

(9)在TestNdkActivity.java中完成對JniClient.java中函數的調用:

import android.app.Activity;

import android.os.Bundle;

import

android.widget.TextView;

public class TestNdkActivity extends Activity {

    static

System.loadLibrary("TestNdk");

    }

    /** Called when the activity is first created.

    @Override

    public void

onCreate(Bundle savedInstanceState)

super.onCreate(savedInstanceState);

//       

setContentView(R.layout.main);

        String str =

JniClient.AddStr("prefix",

"suffix");

        int iSum = JniClient.AddInt(5,

2);       

        String strSum = "5 + 7 = " +

iSum;

        TextView tv1 = new

TextView(this);

tv1.setText(str);

setContentView(tv1);

(10)運作TestNdk工程,在模拟器中可以看到界面輸出來自com_ndk_test_JniClient.c

檔案中的“HelloWorld from JNI ! “。

OK,NDK執行個體到此完成。後續就可以深入的學習NDK/JNI了,比如C/C++與Java的資料類型轉換,Android.mk檔案的編寫格式等。