Android NDK基础样例

         NDK(Native Development Kit),用C/C++封装一些东西?好像就这么理解好了==

 
一、环境准备
         这个好讨厌==!因为我环境都已经搭了很久了。
 
         已经搭建好,或者不一样环境的可以忽视。(当然看下也无妨撒^^)
 
1 )先说下我的环境吧
         1、系统环境:XP。(总感觉在这上做这些事情不协调T^T)
         2、运行环境:Eclispe+Cygwin。
 
2 )再说下这环境下的建议咯(不知道过时了没==
         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吧)。
 
3 )怎么开始呢?

         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。

create.png

图1.3.3 创建工程注意项

         4、右键工程属性,选中C/C++ Build,取消Use default build command,改为“bash --login -c "cd $STUDYSPACE/AndroidNDK && $NDKROOT/ndk-build"”。(cygwin下配的东西,你懂的,可以偷点懒==)

         提示:ndk-build在很早版本时还没这个,要自己写什么什么的(不太清楚T^T)。总之,你应该不会很低版本的。

create.png

图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”。

create.png

图1.3.4 Include路径增加
         6、把样例工程下的Android.mk、Application.mk复制到你的工程下。写完了你的程序后,仿照着修修改改就成了。
         具体的你可以搜“Android.mk详解”什么的。至于Application.mk,你2.2以上要用到Bitmap.h呢,这个就必须加了(不加编译会有什么错误来着?不记得了==)
 
二、基础样例
         这部分才是重点啊!多么切题。直接先看下运行的东西咯^^

create.png

         是不是更有看的动力了?还是你拉到下边直接下载去了==。(没被鄙视简单吧T^T)
 
1 )C 部分
1.1)TestJni.h
 
  
  1. /* 
  2.  * TestJni.h 
  3.  * 
  4.  *  Created on: 2011-12-20 
  5.  *      Author: Join 
  6.  */ 
  7.  
  8. #ifndef TESTJNI_H_ 
  9. #define TESTJNI_H_ 
  10.  
  11. #include <jni.h> 
  12. #include <stdio.h> 
  13. #include <stdlib.h> 
  14. #include <android/log.h> 
  15. #include <android/bitmap.h> 
  16.  
  17. // 测试回调Java 
  18. #include "CallJava.h" 
  19.  
  20. #define LOG_TAG "JNI_DEBUG" 
  21. #define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) 
  22. #define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) 
  23.  
  24. // JNI调用函数必须要用C编译器编译 
  25. // C++不加extern "C",调用会有异常 
  26. #ifdef __cplusplus 
  27. extern "C" { 
  28. #endif 
  29.  
  30. /* 
  31.  * 说明: 
  32.  * 1、JNIEXPORT、JNICALL:jni的宏,在android的jni中不必须 
  33.  * 2、jstring:返回值类型(对应java的jni基本类型) 
  34.  * 3、C方法名:Java_pacakege_class_method 
  35.  * 4、JNIEnv*、jobject:jni必要参数(分别表示jni环境、java对象) 
  36.  */ 
  37. // 样例1:获取字符串 
  38. JNIEXPORT jstring JNICALL Java_org_join_ndk_jni_TestJni_getStr(JNIEnv*, 
  39.         jobject); 
  40. // 样例2:C回调Java静态及非静态方法 
  41. JNIEXPORT jstring JNICALL Java_org_join_ndk_jni_TestJni_callJava(JNIEnv*, 
  42.         jobject, intintintint); 
  43. // 样例3:灰度化图像(Bitmap作为参数)(注:android-8才提供Bitmap.h) 
  44. JNIEXPORT void JNICALL Java_org_join_ndk_jni_TestJni_convertToGray(JNIEnv*, 
  45.         jobject, jobject); 
  46.  
  47. // 样例4:缺少JNIEXPORT、JNICALL测试 
  48. jintArray Java_org_join_ndk_jni_TestJni_getIntArray(JNIEnv*, jobject); 
  49.  
  50. // 样例5:C方法不按规则命名尝试 
  51. jint getInt(JNIEnv*, jobject); 
  52.  
  53. #ifdef __cplusplus 
  54. #endif 
  55.  
  56. // C++调用C 
  57. //extern "C" { 
  58. //#include "ImageUtil.h" 
  59. //} 
  60.  
  61. //标准头文件为何有如下结构? 
  62. //#ifdef __cplusplus 
  63. //extern "C" { 
  64. //#endif 
  65. //... 
  66. //#ifdef __cplusplus 
  67. //} 
  68. //#endif 
  69.  
  70. #endif /* TESTJNI_H_ */ 
 
1.2)TestJni.cpp
 
  
  1. /* 
  2.  * TestJni.cpp 
  3.  * 
  4.  *  Created on: 2011-12-20 
  5.  *      Author: Join 
  6.  */ 
  7.  
  8. #include "TestJni.h" 
  9.  
  10. // 样例1:获取字符串 
  11. JNIEXPORT jstring JNICALL Java_org_join_ndk_jni_TestJni_getStr(JNIEnv *env, 
  12.         jobject obj) { 
  13.     return env->NewStringUTF("I'm from C!"); 
  14.  
  15. int min(int x, int y) { 
  16.     return (x <= y) ? x : y; 
  17.  
  18. // 样例2:C回调Java静态及非静态方法 
  19. JNIEXPORT jstring JNICALL Java_org_join_ndk_jni_TestJni_callJava(JNIEnv *env, 
  20.         jobject obj, int add_x, int add_y, int sub_x, int sub_y) { 
  21.     char str[128]; // 字符数组 
  22.     int result_add = add(env, add_x, add_y); // 回调Java静态方法求和 
  23.     LOGE("==[%d+%d=%d]==", add_x, add_y, result_add); 
  24.     int result_sub = sub(env, sub_x, sub_y); // 回调Java非静态方法求差 
  25.     LOGE("==[%d-%d=%d]==", sub_x, sub_y, result_sub); 
  26.     // 将比较得的整数转成字符串 
  27.     sprintf(str, "Hello, I'm Join! min=%d", min(result_add, result_sub)); 
  28.     return env->NewStringUTF(str); 
  29.  
  30. typedef struct { 
  31.     uint8_t red; 
  32.     uint8_t green; 
  33.     uint8_t blue; 
  34.     uint8_t alpha; 
  35. } argb; 
  36.  
  37. // 样例3:灰度化图像(Bitmap作为参数)(注:android-8才提供Bitmap.h) 
  38. /** 
  39.  * bitmap:ARGB_8888,32位ARGB位图 
  40.  */ 
  41. JNIEXPORT void JNICALL Java_org_join_ndk_jni_TestJni_convertToGray(JNIEnv * env, 
  42.         jobject obj, jobject bitmap) { 
  43.     AndroidBitmapInfo info; 
  44.     void* pixels; 
  45.     int ret; 
  46.  
  47.     LOGI("convertToGray"); 
  48.     if ((ret = AndroidBitmap_getInfo(env, bitmap, &info)) < 0) { 
  49.         LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret); 
  50.         return
  51.     } 
  52.  
  53.     LOGI( 
  54.             "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); 
  55.     if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) { 
  56.         LOGE("Bitmap format is not RGBA_8888 !"); 
  57.         return
  58.     } 
  59.  
  60.     if ((ret = AndroidBitmap_lockPixels(env, bitmap, &pixels)) < 0) { 
  61.         LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret); 
  62.     } 
  63.  
  64.     // modify pixels with image processing algorithm 
  65.  
  66.     int x, y; 
  67.     uint8_t gray; 
  68.     for (y = 0; y < info.height; y++) { 
  69.         argb * line = (argb *) pixels; 
  70.         for (x = 0; x < info.width; x++) { 
  71.             gray = 0.3 * line[x].red + 0.59 * line[x].green 
  72.                     + 0.11 * line[x].blue; 
  73.             line[x].red = line[x].green = line[x].blue = gray; 
  74.             // line[x].alpha = 0xff; // 完全不透明 
  75.         } 
  76.  
  77.         pixels = (char *) pixels + info.stride; 
  78.     } 
  79.  
  80.     LOGI("unlocking pixels"); 
  81.     AndroidBitmap_unlockPixels(env, bitmap); 
  82.  
  83.  
  84. // 样例4:缺少JNIEXPORT、JNICALL测试 
  85. jintArray Java_org_join_ndk_jni_TestJni_getIntArray(JNIEnv *env, jobject obj) { 
  86.     int array[] = { 12, 34 }; // 新建一个int[] 
  87.     jintArray result = env->NewIntArray(2); // 新建一个jintArray 
  88.     env->SetIntArrayRegion(result, 0, 2, array); // 将int[]存入result 
  89.     return result; 
  90.  
  91. // 样例5:C方法不按规则命名尝试 
  92. jint getInt(JNIEnv *env, jobject obj) { 
  93.     return 256; 
 
1.3)回调相关
         参照我的 Java JNI简单实现一文,讲了些jni注意点的吧?
 
2 )Java 部分
2.1)TestJni
 
  
  1. public class TestJni { 
  2.  
  3.     /** TAG标识 */ 
  4.     private static final String TAG = "TestJni"
  5.  
  6.     /** 
  7.      * 载入动态库 
  8.      */ 
  9.     static { 
  10.         System.loadLibrary("TestJni"); 
  11.     } 
  12.  
  13.     /** 样例1:获取字符串 */ 
  14.     public static native String getStr(); 
  15.  
  16.     /** C回调Java方法(静态) */ 
  17.     public static int add(int x, int y) { 
  18.         Log.e(TAG, "==Java静态add方法=="); 
  19.         return x + y; 
  20.     } 
  21.  
  22.     /** C回调Java方法(非静态) */ 
  23.     public int sub(int x, int y) { 
  24.         Log.e(TAG, "==Java非静态sub方法=="); 
  25.         return x - y; 
  26.     } 
  27.  
  28.     /** 样例2:C回调Java静态及非静态方法 */ 
  29.     public static native String callJava(int add_x, int add_y, int sub_x, 
  30.             int sub_y); 
  31.  
  32.     /** 样例3:灰度化图像(Bitmap作为参数)(注:android-8才提供Bitmap.h) */ 
  33.     public static native void convertToGray(Bitmap bitmap); 
  34.  
  35.     /** 样例4:缺少JNIEXPORT、JNICALL测试 */ 
  36.     public static native int[] getIntArray(); 
  37.  
  38.     /** 样例5:C方法不按规则命名尝试 */ 
  39.     public static native int getInt(); 
  40.  

2.2)AndroidNDKActivity
 
  
  1. public class AndroidNDKActivity extends Activity implements 
  2.         View.OnClickListener { 
  3.  
  4.     /** 标签 */ 
  5.     private TextView text; 
  6.  
  7.     /** 按钮 */ 
  8.     private Button btn1, btn2, btn3, btn4, btn5; 
  9.  
  10.     /** 图像 */ 
  11.     private ImageView imageView; 
  12.  
  13.     @Override 
  14.     public void onCreate(Bundle savedInstanceState) { 
  15.         super.onCreate(savedInstanceState); 
  16.         setContentView(R.layout.main); 
  17.  
  18.         /* 初始化话各组件 */ 
  19.         text = (TextView) findViewById(R.id.text); 
  20.         btn1 = (Button) findViewById(R.id.btn1); 
  21.         btn1.setOnClickListener(this); 
  22.         btn2 = (Button) findViewById(R.id.btn2); 
  23.         btn2.setOnClickListener(this); 
  24.         btn3 = (Button) findViewById(R.id.btn3); 
  25.         btn3.setOnClickListener(this); 
  26.         btn4 = (Button) findViewById(R.id.btn4); 
  27.         btn4.setOnClickListener(this); 
  28.         btn5 = (Button) findViewById(R.id.btn5); 
  29.         btn5.setOnClickListener(this); 
  30.         imageView = (ImageView) findViewById(R.id.imageView); 
  31.     } 
  32.  
  33.     @Override 
  34.     public void onClick(View v) { 
  35.         switch (v.getId()) { 
  36.         case R.id.btn1: 
  37.             // 样例1:获取字符串 
  38.             text.setText(TestJni.getStr()); 
  39.             break
  40.         case R.id.btn2: 
  41.             // 样例2:C回调Java静态及非静态方法 
  42.             text.setText(TestJni.callJava(2583)); 
  43.             break
  44.         case R.id.btn3: 
  45.             // 获得Bitmap资源(32位) 
  46.             // BitmapFactory.Options options = new BitmapFactory.Options(); 
  47.             // options.inPreferredConfig = Bitmap.Config.ARGB_8888; 
  48.             // Bitmap bitmap = BitmapFactory.decodeResource(getResources(), 
  49.             // R.drawable.ic_launcher, options); 
  50.             Bitmap bitmap = BitmapFactory.decodeResource(getResources(), 
  51.                     R.drawable.ic_launcher); 
  52.             // 样例3:灰度化图像(Bitmap作为参数) 
  53.             TestJni.convertToGray(bitmap); 
  54.             imageView.setImageBitmap(bitmap); 
  55.             break
  56.         case R.id.btn4: 
  57.             // 样例4:缺少JNIEXPORT、JNICALL测试 
  58.             int[] array = TestJni.getIntArray(); 
  59.             int len = array.length; 
  60.             StringBuffer sb = new StringBuffer(); 
  61.             for (int i = 0; i < len - 1; i++) { 
  62.                 sb.append(array[i]); 
  63.                 sb.append(","); 
  64.             } 
  65.             sb.append(array[len - 1]); 
  66.             text.setText(sb.toString()); 
  67.             break
  68.         case R.id.btn5: 
  69.             // 样例5:C方法不按规则命名尝试 
  70.             try { 
  71.                 int value = TestJni.getInt(); 
  72.                 text.setText(String.valueOf(value)); 
  73.             } catch (UnsatisfiedLinkError e) { 
  74.                 text.setText("UnsatisfiedLinkError!"); 
  75.                 e.printStackTrace(); 
  76.             } 
  77.             break
  78.         } 
  79.     } 
 
三、后记
         也是整理的基础样例工程,嘿嘿!
 
         注意:
         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^^)