织梦CMS - 轻松建站从此开始!

罗索

当前位置: 主页>嵌入式开发>Android>

ANDROID上NDK开发初探

罗索客 发布于 2010-02-21 23:15 点击:次 
总的来说ANDROID的NDK远不及其应用开发的SDK完善(虽然经过一番不算复杂的折腾发现NDK用起来很方便),而且它本身也不推荐使用这种做法,至少目前也不将此作为重点。
TAG:

总的来说ANDROID的NDK远不及其应用开发的SDK完善(虽然经过一番不算复杂的折腾发现NDK用起来很方便),而且它本身也不推荐使用这种做法,至少目前也不将此作为重点。但是某些中间层面系统测试(主要如多媒体和OpenGL ES的测试和演示等)必须通过本地代码实现,因此NDK应当是必由之路。

最近尝试了一下,目前将JNI部分基本理顺(而后续则需要链接相关的ANDROID本地库,如OpenCore系统)。
网上这方面相关介绍也有不少,但是多不太完整,此处权作工作记录。

1 NDK使用

1.1 配置NDK


本处讨论在Windows下使用cygwin处理NDK的Windows版本。Linux下的使用方法基本一致。根据unix系系统的规范,所有讨论中涉及名称的字符串均大小写敏感。这里仅NDK的配置和C代码编译须用cygwin,此后的ANDROID调试等均可使用普通的命令行操作。
参考链接:http://developer.android.com/sdk/ndk/1.5_r1/index.html
收到NDK后首先在NDK的主目录(其中包含apps, build, docs, …文件夹)下,输入命令:
build/host-setup.sh
用来配置NDK工具(例如编译器的使用,目标平台等),最终生成out/host/config-host。由于out必须在主目录中,因此上述命令须在主目录中输入。

1.2 编译本地源码

本地源码(主要如C文件)均放在sources下。NDK提供了两个示例,放在sources/sample目录下。
编译只需要在主目录中输入命令:
make APP=<名称>
对于上述示例,分别为hello-jni和two-libs。

1. sources文件夹配置
由于NDK已将MAKE生成系统建立妥善,所以只需要在sources中建立包含源文件的文件夹。
由于NDK的配置是以sources目录作为源文件工程的根节点,因此如果要将源文件工程放在更深的目录,例如sources\package1\proj1,那么就需要在中间的目录中加入一个Android.mk文件,用以转到更深的目录其内容示例可见sources\samples\Android.mk。
上述文件夹proj1名称建议以源文件模块的名称命名。
在源文件工程文件夹中需要有至少一个Android.mk文件用以定义源文件编译信息。可以参照sources\samples中的两个工程中的示例。其中LOCAL_MODULE变量必须定义成指定源文件工程(模块)的名称。

2. C源程序JNI入口
C源程序的入口遵照JNI规范:
Java_<PackageName>_<JAVA类名>_<FuncName>
其中包名称和Android的JAVA类所属包需要保持一致,只是“.”用“_”替换;JAVA类即是包含这个(实例)方法的类;FuncName则是呈现在JAVA中使用的方法名称。

3. apps文件夹配置
在apps文件夹中创建一个ADNROID工程文件夹,名称为APP工程(JAVA)名称,在其中新建一个Application.mk的配置文件,参照两个示例工程设置。主要设置两个变量:
APP_PROJECT_PATH,这个是ANDROID工程路径和相应指定库生成目录(复制而来,名称为“lib源文件模块名”),一般设置成$(call
my-dir)/project,即当前目录下project中,而库生成目录就是project/libs。
APP_MODULES则是这个ANDROID将包含的上述源文件工程,填入涉及的一个或多个源文件工程名称。
最后在主目录中用make APP=<APP工程名称>

1.3 创建工程
NDK两个例程已经含有完整的ANDROID例程,可以在Eclipse中直接导入打开。
如果新建一个工程,只需要仿照ANDROID工程的一般过程开始,由于本地库so处于工程目录下,Eclipse会自动将其包含在工程中,并最终一并链入apk。

1.4 关于JAVA本地(Native)接口JNI
一些参考文档:
1. http://java.sun.com/docs/books/jni/
2. http://java.sun.com/j2se/1.5.0/docs/guide/jni/spec/functions.html
3. http://journals.ecs.soton.ac.uk/java/tutorial/native1.1/implementing/method.html
有几个注意点:
1. 不能在本地代码中跨线程使用JNI量,而目前又暂没找到联入正确JNI环境量和对象或者JVM的方法,因此只能在调用线程中使用回调,意味着设计需要让回调发生在JAVA调用者线程中。
2. CallXXXMethodX(env, obj, methodid, va_arg)中,va_arg必须输入指针(对象的指针如jstring *,原子的指针如int *)。
3. 对于跨线程的UI操作侧需要用runOnUiThread。

2 ANDROID工具使用

2.1 虚拟设备创建(AVD)


使用android命令
创建:
android create avd –n <虚拟设备名称> -t <目标ID>
在通常情况下接受默认选项(不建立hardware profile)
删除:
android delete avd –n <虚拟设备名称>
列印:
android list

2.2 (在命令行)运行虚拟机

命令:
emulator –avd <虚拟设备名称>

2.3 ADB常用命令

参考:http://oxen.javaeye.com/blog/142373
安装程序:
adb install <待安装APK文件本地位置>
运行命令SHELL:
adb shell ,进入SHELL,可以操作访问设备文件系统
adb shell ,直接执行命令(SHELL中可以执行logcat)
复制文件:
adb push <本地源> <设备文件系统绝对地址> ,复制入文件
adb pull <设备文件系统绝对地址> <本地位置> ,复制出文件
adb devices ,查看运行的模拟器/设备状态


【示例程序】

一个简单的在屏幕上间歇打印的程序。

本地C代码
(仅用于示例,不保证正确性和安全性)

  1. #include <jni.h>  
  2. #include <stdio.h>  
  3. #include <string.h>  
  4. #include <malloc.h>  
  5. #include <pthread.h>  
  6. #include <unistd.h>  
  7.  
  8. typedef struct 
  9. {  
  10.    JNIEnv* env;  
  11.    jobject thiz;  
  12.    jclass cls;  
  13. } UpdateTextContext;  
  14.  
  15. static int gRunnerRunning = 0;  
  16.  
  17. static int update_text(UpdateTextContext *context, char *buf)  
  18. {  
  19.    JNIEnv* env = context->env;  
  20.    jobject thiz = context->thiz;  
  21.    jclass cls = context->cls;  
  22.    jmethodID mid = (*env)->GetMethodID(env, cls, "appendText""(Ljava/lang/String;)V");  
  23.    if (mid == NULL)  
  24.        return -1;  
  25.    jstring s = (*env)->NewStringUTF(env, buf);  
  26.    (*env)->CallVoidMethodV(env, thiz, mid, &s);  
  27.    return 0;  
  28. }  
  29.  
  30. void Java_com_eden_sample_Sample_initTextGenerator(JNIEnv* env, jobject thiz)  
  31. {  
  32.    gRunnerRunning = 0;  
  33. }  
  34. void Java_com_eden_sample_Sample_runTextGenerator(JNIEnv* env, jobject thiz)  
  35. {  
  36.    char buf[64];  
  37.    int counter = 0;  
  38.    UpdateTextContext context;  
  39.    context.env = env;  
  40.    context.thiz = thiz;  
  41.    context.cls = (*env)->GetObjectClass(env, thiz);  
  42.    gRunnerRunning = 1;  
  43.    while(gRunnerRunning)  
  44.    {  
  45.        sprintf(buf, "sample counting: %d\n", counter);  
  46.        int r = update_text(&context, buf);  
  47.        if (r != 0)  
  48.            break;  
  49.        counter++;  
  50.        sleep(1);   /* sleep for one second */ 
  51.    }  
  52.    gRunnerRunning = 0;  
  53. }  
  54. void Java_com_eden_sample_Sample_stopTextGenerator(JNIEnv* env, jobject thiz)  
  55. {  
  56.    gRunnerRunning = 0;  

JAVA程序
(JAVA本不十分熟悉,权当c#写了)

1:
package
com.vendor.sample;  /* package that must keep in accordance with the native code */

   2:
  
   3:
 import
 android.app.Activity;
   4:
 import
 android.os.Bundle;
   5:
 import
 android.widget.TextView;
   6:
 import
 java.util.*;
   7:
  
   8:
 public
 class
 Sample extends
 Activity {
   9:
  
  10:
     enum
 UpdateType {
  11:
         Modify,
  12:
         Append
  13:
     }
  14:
     
  15:
     private
 class
 UpdateTextRunner implements
 Runnable {
  16:
         public
 UpdateTextRunner(String s, UpdateType type) {
  17:
             mS = s;
  18:
             mType = type;
  19:
         }
  20:
  
  21:
         public
 void
 run() {
  22:
             if
 (mType ==  UpdateType.Modify) {
  23:
                 mLines.clear();
  24:
                 mLines.add(mS);
  25:
                 mTV.setText(mS);
  26:
             } else
 {
  27:
                 mLines.add(mS);
  28:
                 /* intended to display no more than `mMaxLineCount'
  29:
                  * lines and scroll, however this is not
  30:
                  * always the case, consider if mS is broken
  31:
                  * into several lines
  32:
                  */
  33:
                 while
 (mLines.size() > mMaxLineCount)
  34:
                     mLines.remove(0);
  35:
  
  36:
                 StringBuilder sb = new
 StringBuilder();
  37:
                 for
 (int
 i = 0; i < mLines.size(); i++)
  38:
                 sb.append(mLines.get(i));
  39:
                 mTV.setText(sb.toString());
  40:
             }
  41:
         }
  42:
  
  43:
         private
 String mS;
  44:
         private
 UpdateType mType;
  45:
     }
  46:
  
  47:
     /** Called when the activity is first created. */
  48:
     @Override
  49:
     public
 void
 onCreate(Bundle savedInstanceState) {
  50:
         super
.onCreate(savedInstanceState);
  51:
  
  52:
         mTV = new
 TextView(this
);
  53:
         mTV.setText( "initial text"
 );
  54:
         setContentView(mTV);
  55:
  
  56:
         initTextGenerator();
  57:
  
  58:
         /* The following thread object simply contains
  59:
          * an overriden run method which invokes 
  60:
          * runTextGenerator on this Sample object
  61:
          */
  62:
         mThread = new
 TextUpdatorThread(this
);
  63:
         mThread.start();
  64:
     }
  65:
  
  66:
     @Override
  67:
     public
 void
 onDestroy() {
  68:
         stopTextGenerator();
  69:
  
  70:
         try
 {
  71:
             mThread.join();
  72:
         } catch
 (InterruptedException e) {
  73:
             e.printStackTrace();
  74:
         }
  75:
         super
.onDestroy();
  76:
     }
  77:
  
  78:
     public
 void
 modifyText(String s) {
  79:
         this
.runOnUiThread(new
 UpdateTextRunner(s, UpdateType.Modify));
  80:
     }
  81:
  
  82:
     public
 void
 appendText(String s) {
  83:
         this
.runOnUiThread(new
 UpdateTextRunner(s, UpdateType.Append));
  84:
     }
  85:
  
  86:
     public
 native
 void
 initTextGenerator();
  87:
     public
 native
 void
 stopTextGenerator();
  88:
     public
 native
 void
 runTextGenerator();
  89:
  
  90:
     private
 TextView mTV;
  91:
     private
 ArrayList mLines = new
 ArrayList();
  92:
     private
 int
 mMaxLineCount = 20;
  93:
  
  94:
     private
 TextUpdatorThread mThread;
  95:
  
  96:
     static
 {
  97:
         System.loadLibrary("sample"
);   // the corresponding C library is libsample.so
  98:
     }
  99:
 }
(俞怡炜)
本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www.rosoo.net/a/201002/8534.html]
本文出处:CSDN博客 作者:俞怡炜
顶一下
(7)
77.8%
踩一下
(2)
22.2%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容