天天看點

Android NDK基礎樣例

 <b>Android NDK</b><b>基礎樣例</b>

         NDK(Native Development Kit),用C/C++封裝一些東西?好像就這麼了解好了==

<b>一、環境準備</b>

         這個好讨厭==!因為我環境都已經搭了很久了。

         已經搭建好,或者不一樣環境的可以忽視。(當然看下也無妨撒^^)

<b>1</b><b>)先說下我的環境吧</b>

         1、系統環境:XP。(總感覺在這上做這些事情不協調T^T)

         2、運作環境:Eclispe+Cygwin。

<b>2</b><b>)再說下這環境下的建議咯(不知道過時了沒==</b><b>)</b>

         1、Eclispe重新下個C/C++版本,不要在原Android的Eclispe上加CDT元件了。貌似會有沖突。(補充:CDT 8.0.2已不存在這個問題。我在配Linux下內建環境時一起裝了沒事)

         2、Cygwin根目錄\home\[your name]\ .bash_profile檔案内配置下你的NDK路徑、工程路徑等。先這兩樣吧==

         如果你的ndk路徑是“E:\android-ndk-r6”,工作空間在“E:\studyspace”。

         export NDKROOT="/cygdrive/e/android-ndk-r6"

         export STUDYSPACE="/cygdrive/e/studyspace"

         這個ndk版本有點低了哈,我自己筆記本上也有配,是比較高的版本(好像是r9吧)。

<b>3</b><b>)怎麼開始呢?</b>

         1、Eclispe+Cygwin先跑出個C工程的hello world!确定環境沒什麼問題。

         2、在你的Android工程下建一個jni的目錄(這個網上搜搜ndk開發,很多的。簡要講講了,關鍵的再截個圖吧==)

         3、在你的C版Eclispe建立C++工程。注意取消Use default location,選擇你工程下的jni目錄。Project type選擇Empty Project。Toolchains選擇Other Toolchain。

<a target="_blank" href="http://blog.51cto.com/attachment/201202/163820197.png"></a>

圖1.3.3 建立工程注意項

         4、右鍵工程屬性,選中C/C++ Build,取消Use default build command,改為“bash --login -c "cd $STUDYSPACE/AndroidNDK &amp;&amp; $NDKROOT/ndk-build"”。(cygwin下配的東西,你懂的,可以偷點懶==)

         提示:ndk-build在很早版本時還沒這個,要自己寫什麼什麼的(不太清楚T^T)。總之,你應該不會很低版本的。

<a target="_blank" href="http://blog.51cto.com/attachment/201202/163820987.png"></a>

圖1.3.4 Build屬性修改

         5、繼續選至C/C++ General的Paths and Symbols。右側Includes的C++項目,增加include路徑。繼續假設你的ndk路徑是“E:\android-ndk-r6”==,如果是Android 2.2工程。

         Include的路徑則為“E:\android-ndk-r6\platforms\android-8\arch-arm\usr\include”。

<a target="_blank" href="http://blog.51cto.com/attachment/201202/163820647.png"></a>

圖1.3.4 Include路徑增加

         6、把樣例工程下的Android.mk、Application.mk複制到你的工程下。寫完了你的程式後,仿照着修修改改就成了。

         具體的你可以搜“Android.mk詳解”什麼的。至于Application.mk,你2.2以上要用到Bitmap.h呢,這個就必須加了(不加編譯會有什麼錯誤來着?不記得了==)

<b>二、基礎樣例</b>

         這部分才是重點啊!多麼切題。直接先看下運作的東西咯^^

<a target="_blank" href="http://blog.51cto.com/attachment/201202/163820223.png"></a>

         是不是更有看的動力了?還是你拉到下邊直接下載下傳去了==。(沒被鄙視簡單吧T^T)

<b>1</b><b>)C</b><b>部分</b>

1.1)TestJni.h

/* 

 * TestJni.h 

 * 

 *  Created on: 2011-12-20 

 *      Author: Join 

 */ 

#ifndef TESTJNI_H_ 

#define TESTJNI_H_ 

#include &lt;jni.h&gt; 

#include &lt;stdio.h&gt; 

#include &lt;stdlib.h&gt; 

#include &lt;android/log.h&gt; 

#include &lt;android/bitmap.h&gt; 

// 測試回調Java 

#include "CallJava.h" 

#define LOG_TAG "JNI_DEBUG" 

#define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) 

#define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) 

// JNI調用函數必須要用C編譯器編譯 

// C++不加extern "C",調用會有異常 

#ifdef __cplusplus 

extern "C" { 

#endif 

 * 說明: 

 * 1、JNIEXPORT、JNICALL:jni的宏,在android的jni中不必須 

 * 2、jstring:傳回值類型(對應java的jni基本類型) 

 * 3、C方法名:Java_pacakege_class_method 

 * 4、JNIEnv*、jobject:jni必要參數(分别表示jni環境、java對象) 

// 樣例1:擷取字元串 

JNIEXPORT jstring JNICALL Java_org_join_ndk_jni_TestJni_getStr(JNIEnv*, 

        jobject); 

// 樣例2:C回調Java靜态及非靜态方法 

JNIEXPORT jstring JNICALL Java_org_join_ndk_jni_TestJni_callJava(JNIEnv*, 

        jobject, int, int, int, int); 

// 樣例3:灰階化圖像(Bitmap作為參數)(注:android-8才提供Bitmap.h) 

JNIEXPORT void JNICALL Java_org_join_ndk_jni_TestJni_convertToGray(JNIEnv*, 

        jobject, jobject); 

// 樣例4:缺少JNIEXPORT、JNICALL測試 

jintArray Java_org_join_ndk_jni_TestJni_getIntArray(JNIEnv*, jobject); 

// 樣例5:C方法不按規則命名嘗試 

jint getInt(JNIEnv*, jobject); 

// C++調用C 

//extern "C" { 

//#include "ImageUtil.h" 

//} 

//标準頭檔案為何有如下結構? 

//#ifdef __cplusplus 

//#endif 

//... 

#endif /* TESTJNI_H_ */ 

1.2)TestJni.cpp

 * TestJni.cpp 

#include "TestJni.h" 

JNIEXPORT jstring JNICALL Java_org_join_ndk_jni_TestJni_getStr(JNIEnv *env, 

        jobject obj) { 

    return env-&gt;NewStringUTF("I'm from C!"); 

int min(int x, int y) { 

    return (x &lt;= y) ? x : y; 

JNIEXPORT jstring JNICALL Java_org_join_ndk_jni_TestJni_callJava(JNIEnv *env, 

        jobject obj, int add_x, int add_y, int sub_x, int sub_y) { 

    char str[128]; // 字元數組 

    int result_add = add(env, add_x, add_y); // 回調Java靜态方法求和 

    LOGE("==[%d+%d=%d]==", add_x, add_y, result_add); 

    int result_sub = sub(env, sub_x, sub_y); // 回調Java非靜态方法求差 

    LOGE("==[%d-%d=%d]==", sub_x, sub_y, result_sub); 

    // 将比較得的整數轉成字元串 

    sprintf(str, "Hello, I'm Join! min=%d", min(result_add, result_sub)); 

    return env-&gt;NewStringUTF(str); 

typedef struct { 

    uint8_t red; 

    uint8_t green; 

    uint8_t blue; 

    uint8_t alpha; 

} argb; 

/** 

 * bitmap:ARGB_8888,32位ARGB位圖 

JNIEXPORT void JNICALL Java_org_join_ndk_jni_TestJni_convertToGray(JNIEnv * env, 

        jobject obj, jobject bitmap) { 

    AndroidBitmapInfo info; 

    void* pixels; 

    int ret; 

    LOGI("convertToGray"); 

    if ((ret = AndroidBitmap_getInfo(env, bitmap, &amp;info)) &lt; 0) { 

        LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret); 

        return; 

    } 

    LOGI( 

            "color image :: width is %d; height is %d; stride is %d; format is %d;flags is %d", info.width, info.height, info.stride, info.format, info.flags); 

    if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) { 

        LOGE("Bitmap format is not RGBA_8888 !"); 

    if ((ret = AndroidBitmap_lockPixels(env, bitmap, &amp;pixels)) &lt; 0) { 

        LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret); 

    // modify pixels with image processing algorithm 

    int x, y; 

    uint8_t gray; 

    for (y = 0; y &lt; info.height; y++) { 

        argb * line = (argb *) pixels; 

        for (x = 0; x &lt; info.width; x++) { 

            gray = 0.3 * line[x].red + 0.59 * line[x].green 

                    + 0.11 * line[x].blue; 

            line[x].red = line[x].green = line[x].blue = gray; 

            // line[x].alpha = 0xff; // 完全不透明 

        } 

        pixels = (char *) pixels + info.stride; 

    LOGI("unlocking pixels"); 

    AndroidBitmap_unlockPixels(env, bitmap); 

jintArray Java_org_join_ndk_jni_TestJni_getIntArray(JNIEnv *env, jobject obj) { 

    int array[] = { 12, 34 }; // 建立一個int[] 

    jintArray result = env-&gt;NewIntArray(2); // 建立一個jintArray 

    env-&gt;SetIntArrayRegion(result, 0, 2, array); // 将int[]存入result 

    return result; 

jint getInt(JNIEnv *env, jobject obj) { 

    return 256; 

1.3)回調相關

<b>2</b><b>)Java</b><b>部分</b>

2.1)TestJni<b></b>

public class TestJni { 

    /** TAG辨別 */ 

    private static final String TAG = "TestJni"; 

    /** 

     * 載入動态庫 

     */ 

    static { 

        System.loadLibrary("TestJni"); 

    /** 樣例1:擷取字元串 */ 

    public static native String getStr(); 

    /** C回調Java方法(靜态) */ 

    public static int add(int x, int y) { 

        Log.e(TAG, "==Java靜态add方法=="); 

        return x + y; 

    /** C回調Java方法(非靜态) */ 

    public int sub(int x, int y) { 

        Log.e(TAG, "==Java非靜态sub方法=="); 

        return x - y; 

    /** 樣例2:C回調Java靜态及非靜态方法 */ 

    public static native String callJava(int add_x, int add_y, int sub_x, 

            int sub_y); 

    /** 樣例3:灰階化圖像(Bitmap作為參數)(注:android-8才提供Bitmap.h) */ 

    public static native void convertToGray(Bitmap bitmap); 

    /** 樣例4:缺少JNIEXPORT、JNICALL測試 */ 

    public static native int[] getIntArray(); 

    /** 樣例5:C方法不按規則命名嘗試 */ 

    public static native int getInt(); 

2.2)AndroidNDKActivity<b></b>

public class AndroidNDKActivity extends Activity implements 

        View.OnClickListener { 

    /** 标簽 */ 

    private TextView text; 

    /** 按鈕 */ 

    private Button btn1, btn2, btn3, btn4, btn5; 

    /** 圖像 */ 

    private ImageView imageView; 

    @Override 

    public void onCreate(Bundle savedInstanceState) { 

        super.onCreate(savedInstanceState); 

        setContentView(R.layout.main); 

        /* 初始化話各元件 */ 

        text = (TextView) findViewById(R.id.text); 

        btn1 = (Button) findViewById(R.id.btn1); 

        btn1.setOnClickListener(this); 

        btn2 = (Button) findViewById(R.id.btn2); 

        btn2.setOnClickListener(this); 

        btn3 = (Button) findViewById(R.id.btn3); 

        btn3.setOnClickListener(this); 

        btn4 = (Button) findViewById(R.id.btn4); 

        btn4.setOnClickListener(this); 

        btn5 = (Button) findViewById(R.id.btn5); 

        btn5.setOnClickListener(this); 

        imageView = (ImageView) findViewById(R.id.imageView); 

    public void onClick(View v) { 

        switch (v.getId()) { 

        case R.id.btn1: 

            // 樣例1:擷取字元串 

            text.setText(TestJni.getStr()); 

            break; 

        case R.id.btn2: 

            // 樣例2:C回調Java靜态及非靜态方法 

            text.setText(TestJni.callJava(2, 5, 8, 3)); 

        case R.id.btn3: 

            // 獲得Bitmap資源(32位) 

            // BitmapFactory.Options options = new BitmapFactory.Options(); 

            // options.inPreferredConfig = Bitmap.Config.ARGB_8888; 

            // Bitmap bitmap = BitmapFactory.decodeResource(getResources(), 

            // R.drawable.ic_launcher, options); 

            Bitmap bitmap = BitmapFactory.decodeResource(getResources(), 

                    R.drawable.ic_launcher); 

            // 樣例3:灰階化圖像(Bitmap作為參數) 

            TestJni.convertToGray(bitmap); 

            imageView.setImageBitmap(bitmap); 

        case R.id.btn4: 

            // 樣例4:缺少JNIEXPORT、JNICALL測試 

            int[] array = TestJni.getIntArray(); 

            int len = array.length; 

            StringBuffer sb = new StringBuffer(); 

            for (int i = 0; i &lt; len - 1; i++) { 

                sb.append(array[i]); 

                sb.append(","); 

            } 

            sb.append(array[len - 1]); 

            text.setText(sb.toString()); 

        case R.id.btn5: 

            // 樣例5:C方法不按規則命名嘗試 

            try { 

                int value = TestJni.getInt(); 

                text.setText(String.valueOf(value)); 

            } catch (UnsatisfiedLinkError e) { 

                text.setText("UnsatisfiedLinkError!"); 

                e.printStackTrace(); 

<b>三、後記</b>

         也是整理的基礎樣例工程,嘿嘿!

         注意:

         1)需要2.2系統才可,用了Bitmap.h。

         2)樣例5(不按命名規則的那個),用jni對方法進行注冊,不按要求寫方法名也是可以的。

         3)灰階化是用的标準公式:Gray = R*0.299 + G*0.587 + B*0.114(考慮效率的話,有移位公式)

         4)在android-ndk-r6\platforms\android-8\arch-arm\usr\lib目錄下是NDK提供的可調用庫。(有OpenGL ES^^)

<a href="http://down.51cto.com/data/2359862" target="_blank">附件:http://down.51cto.com/data/2359862</a>

     本文轉自winorlose2000 51CTO部落格,原文連結:http://blog.51cto.com/vaero/782787,如需轉載請自行聯系原作者