本节书摘来自异步社区《Android应用开发与系统改造实战》一书中的第1章,第1.5节Android NDK开发环境搭建,作者 王保卫 , 申波,更多章节内容可以访问云栖社区“异步社区”公众号查看
1.5 Android NDK开发环境搭建
Android应用开发与系统改造实战
1.5.1 Android NDK简介
Android NDK是编译嵌入在Android应用中的原生代码(C或C++)的工具。
Android应用运行在Dalvik虚拟机上。NDK允许开发者用原生代码(C或C++)实现应用的一部分。这将给某些应用带来好处,这种方式可重用代码,而且在某些情况下可加快运行速度。
NDK提供了将C和C++源代码生成原生代码库的工具和文件;提供了将原生库嵌入apk文件的方法;提供了兼容Android1.5版本以上的原生系统头文件和库;提供了文档,示例和指引。
最新发布的NDK版本支持ARMv5TE和ARMv7-A机器指令集,提供稳定的C库头文件(C library),JNI接口和其他的库。在将来的版本中还将支持x86 instructions。
ARMv5TE机器指令可以运行在所有的包含ARM CPU的计算机上。ARMv7-A机器指令只能运行在Verizon Droid 或者Google Nexus One这种具有兼容性的CPU的机器上。这两种机器指令的不同之处在于,ARMv7-A支持硬件FPU、Thumb-2和NEON指令。你可以以其中一个或者两个为目标来设置,默认情况下是ARMv5TE,你可以通过在应用程序的Application.mk文件的开始(通过设置默认指令的类型就很容易地切换到ARMv7-A)其他的部分都不用改变。你也可以建立同时适配两种结构,并且将所有的东西都存储在最终的.apk文件中。
NDK并不适用于大部分应用。作为开发者,你应该衡量它的优缺点。很明显,用原生代码并不能自动提升性能,却增加了应用的复杂度。NDK适合用于独立的、占用内存少、占用较多CPU资源的处理,例如,信号处理、物理仿真等。简单的用C重写代码一般不会带来性能的大幅提升。不过,NDK提供了重用现有C/C++的有效途径。
Android Framework层提供了两种方法来访问本地native代码。
(1)利用Android Framework来编写应用,并且使用JNI来访问Android NDK提供的API。这项技术允许你充分利用Framework层提供的便利,而且允许你在必要的时候编写native代码。不过编写出来的应用只可以运行在Android 1.5以上的设备上。
(2)编写一个native的Activity,这个Activity允许你在native代码中实现Activity生命周期中的某个部分的回调。Android SDK提供了nativeActivity类,它可以很方便地提示你,在Activity的生命周期的某个部分,如onCreate( )、onResume( )或者onStop等时候再在native代码中实现你的回调。利用native Activity编写的应用程序必须运行在Android 2.3以及以后的系统版本平台上才可以。
注意 NDK并不能让你开发纯原生应用。Android的主要运行时仍然是Dalvik虚拟机。
NDK包含了一套交叉编译工具(编译,linkers等),它可生成Linux、OS X和Windows(用Cygwin)上的原生ARM的二进制码。
它提供了一套原生API的系统头文件(兼容今后版本)。
libc(C library)headers。
libm(math library)headers。
JNI interface headers。
libz(Zlib compression)headers。
liblog(Android logging)header。
OpenGL ES 1.1 and OpenGL ES 2.0(3D graphics libraries)headers。
libjnigraphics(Pixel buffer access)header(for Android 2.2 and above)。
A Minimal set of headers for C++ support。
OpenSL ES native audio libraries。
Android native application APIS。
NDK也提供了编译系统,可以快速编译源代码,而不用处toolchain/platform/CPU/ABI的细节问题。只需创建很短的编译文件,用来说明哪些源代码需要编译,以及编译到哪个目标Android应用,编译工具将根据此文件编译,并将生成的共享库放到对应的应用下。
重要 提示 除上述的库之外,Android 1.5的原生系统库在以后的版本有可能改变。因此,你的应用应该只适用NDK提供的库。
1.5.2 开发环境配置
1.配置命令行的编译方式
(1)Cygwin安装。
首先下载Cygwin软件,下载地址如下:
http://www.cygwin.com/setup.exe。
Cygwin安装比较麻烦些,安装的快慢主要依靠网络速度。
我这里选择的是Default安装后,再安装以下模块。
make。
binutils。
gcc-core。
gcc4-core。
gdb。
GNU awk。
在搜索输入框里分别输入上面的关键字查找出来安装,如图1.43所示。
(2)NDK安装。
从官方网站上下载NDK后解压到一个目录下就可以了,解压后的绝对路径是E:/paul/developandroid/AndroidNDKDevelop/android-ndk-r5。
(3)上面的软件安装完成后,下面设置环境变量。
进入C:cygwinhomeAdministrator目录,打开目录里的.bash_profile文件,在最下面一行输入设置NDK的编译工具的目录如下:
export DK_HOME=/cygdrive/e/paul/developandroid/AndroidNDKDevelop/android-ndk-r5
(4)使用该工具的命令行进行编译NDK自带的程序。
打开已经安装好的Cygwin.exe文件,如图1.44所示。
然后开始编译该目录下的文件。
输入命令:$NDK_HOME/ndk-build,回车后开始编译,编译完成后,会在libs目录下找到编译完成的.so文件,如图1.47所示。
安装完成后重启Eclipse就可以了。
其实运行一个NDK的例子工程后发现,CDT并不是必须的,不过至少安装CDT后并没有什么坏处。在利用NDK时,其中的C或C++文件就可以利用Android中的CDT工具进行开发。
安装CDT之前C++文件的编辑如图1.51所示。
1.5.3 NDK的实例开发
1.新建工程
运行Eclipse,新建一个Android Project,取名HelloJni(或者自己喜欢的其他名字,比如fxxk-jni也行)。
工程代码就从NDK/samples/hello-jni复制一份即可,记得复制jni那个目录,最终的配置目录结构如图1.53所示。
Libs目录会自动创建,如图1.53所示。
下面是各部分的代码,其中,HelloJni.java的代码如下:
public class HelloJni extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView tv = new TextView(this);
tv.setText( stringFromJNI() );
setContentView(tv);
}
public native String stringFromJNI();
static {
System.loadLibrary("hello-jni");
}
}
hello-jni.c的代码如下:
#include <string.h>
#include <jni.h>
jstring
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
jobject thiz )
{
return (*env)->NewStringUTF(env, "Hello from JNI !");
}
Android.mk的代码如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hello-jni
LOCAL_SRC_FILES := hello-jni.c
include $(BUILD_SHARED_LIBRARY)
如果现在运行这个工程,就会在Android控制台看到如下错误:
java.lang.UnsatisfiedLinkError: Library hello-jni not found。
因为还没有产生那个libhello-jni.so出来。没关系,下面继续进行可以解决问题。
2.工程属性设置
打开hello-jni工程属性,选择Builders,点击New,选择Program,点击“OK”按钮,如图1.54所示。
配置如下,名字随便取一个,Location和working directory要和你的Cygwin目录一致,arguments要和工程目录一致。arguments是:
---login -c "cd /cygdrive/e/paul/developandroid/workspace21/AnroidNDKTest && $NDK_HOME/ndk-build"
其中命令第一部分e/paul/developandroid/workspace21/AnroidNDKTest是你的工程所在的目录,第二部分$NDK_HOME/ndk-Build是在cygwin下设置的环境变量,这是在使用NDK工具,如图1.55所示。
从上面的图片应该看得清,然后勾选其他配置如图1.56和图1.57所示。
当以上步骤都正确配置无误,保存配置后应该就会自动编译jni目录下的C相关代码,并输出相应的.so库文件到工程的libs目录下,libs目录会自动创建。
注意如图1.58所示,将ndk_Builder向上移动到第一位,因为C++需要先编译成.so后Java程序才能使用。
编译时控制台输出类似如图1.59所示。
至此,我们的NDK环境搭配完毕,并且在此时,或许你对NDK有了初步的了解,能够掌握这些就可以进行NDK的开发了,用到NDK的时候一般是具有独立功能的部分,如播放器的编解码部分,可以将这部分用C++开发并生成so文件,再从Java程序中调用就可以了。