首页 » Android程序设计:第2版 » Android程序设计:第2版全文在线阅读

《Android程序设计:第2版》Android NDK

关灯直达底部

Android本地开发工具箱(Native Development Kit,NDK)是Android SDK的辅助工具。如果你使用NDK创建本地代码,则你的应用仍然需要打包到.apk文件中并在设备的虚拟机上运行。基本的Android应用模式没有改变。

设置NDK环境

为了使用NDK,首先必须安装和设置SDK。安装和使用NDK的系统需求如下:

·Windows XP(32位)或Vista(32位或64位),包含Cygwin 1.7版本或更新,Mac OS X 10.4.8版本或更新,Linux(32位或64位)

·GNU Make 3.8.1或更新

·GNU AWK或nawk

首先,下载并安装NDK(http://developer.android.com/sdk/ndk/index.html)。NDK的安装很简单:把NDK解压到任何目录下。这里,我们把它解压到ndk目录。根目录下会包含NDK的版本号。这里,我们把该目录命名为ndk。如果当前可用的版本号比我们在本章使用的版本号更新,你会发现其支持更多的本地API。

一旦下载并安装完NDK,就可以找到很多文档(在ndk/docs目录下)。强烈建议你阅读这些文档,从文件OVERVIEW.html开始。NDK中还提供了一些示例(在ndk/samples目录下)。这些示例涵盖的范围远远超出本章,因此当你对NDK稍有认识后,我们建议你查看并运行这些示例。

在Eclipse中编辑C/C++代码

要充分利用Eclipse来编写C语言代码,需要安装Eclipse C/C++开发工具,即Eclipse CDT。该工具可以在Eclipse环境中提供C语言代码编辑器,和Eclipse的Java编辑功能类似,它也提供语法高亮、格式化以及其他高级功能。

要使用哪个CDT库的版本取决于你的Eclipse版本。对于Eclipse Indigo,在Install New Software对话框中输入库http://download.eclipse.org/tools/cdt/releases/indigo/。关于如何使用Eclipse的更多说明,请参考第5章的为Eclipse添加包以及使用静态分析器两节的内容。

使用NDK编译

为了使用NDK开发本地代码,需要执行如下操作:

1.在项目中创建jni目录。

2.把源代码放到jni目录中。

3.在jni目录下创建Android.mk文件(或者Application.mk文件)。

4.在jni目录下运行ndk/ndk-build命令。

可选的Application.mk文件描述了应用需要什么样的本地模块,以及要编译的具体ABI类型。关于Application.mk的更多信息,可查看文档中的APPLICATION-MK.html文件。Application.mk示例文件如下:


  # Build both ARMv5TE and ARMv7-A machine code.APP_ABI := armeabi armeabi-v7a  # What platform to build against (android-3 (1.5) - android-9 (2.3))APP_PLATFORM := android-9  

Android.mk文件是描述编译系统的源文件。它实质上是一个小的GNU Makefile文件,当编译应用时由编译系统解析它。关于Android.mk的更多信息,可查看文档中的ANDROID-MK.html文件。Android.mk示例文件如下所示:


  # Must define the LOCAL_PATH and return the current dirLOCAL_PATH := $(call my-dir)  # Cleans various variables... making a clean buildinclude $(CLEAR_VARS)  # Identify the module/library/'s nameLOCAL_MODULE := sample  # Specify the source filesLOCAL_SRC_FILES := sample.c  # Load local libraries (here we load the log library)LOCAL_LDLIBS := -llog  # Build the shared library defined aboveinclude $(BUILD_SHARED_LIBRARY)  

Android.mk、Application.mk及本地源文件都准备好之后,可以在项目路径下运行ndk/ndk-build来编译你的库文件。只要编译成功,共享库会被复制到应用的根项目路径中,并被添加到应用的构建之中。

如果你下载并查看Android源代码,会发现在Android的编译系统中一直使用类似以上给出的makefile文件。熟悉JNI、本地代码以及本地代码如何在Android中编译的最好方式是自己编写一个使用Android NDK的简单应用。

JNI、NDK和SDK:应用示例

为了帮助你理解SDK和本地源代码具体是如何结合在一起的,我们提供了一个示例应用,其名称为SampleActivityWithNativeMethods,是一个活动。Android的manifest文件片段如下:


<activity android:name=/".SampleActivityWithNativeMethods/"            android:label=/"Sample Activity With Native Methods/"            android:debuggable=/"true/" />  

这个SampleActivityWithNativeMethods示例应用使用的布局如下所示:


<?xml version=/"1.0/" encoding=/"utf-8/"?><LinearLayout xmlns:android=/"http://schemas.android.com/apk/res/android/"    android:orientation=/"vertical/"    android:layout_    android:layout_    ><Button    android:id=/"@+id/whatami/"    android:layout_    android:layout_    android:paddingTop=/"5dp/"    android:paddingBottom=/"5dp/"    android:text=/"What CPU am I?/"    /></LinearLayout>  

示例C语言库的源代码中实现的是一个名为whatAmI的方法,我们的Java activity会通过whatami ID hook到按钮上。还定义了一个函数,名为LOGINFO,归结为__android_log_print调用。以下是Android log示例:


// the jni library MUST be included#include <jni.h>// the log lib is included#include <android/log.h>// usage of log#define LOGINFO(x...) __android_log_print(ANDROID_LOG_INFO,/"SampleJNI/",x)jstring     Java_com_oreilly_demo_android_pa_ndkdemo_SampleActivityWithNativeMethods_whatAmI(                                                JNIEnv* env,jobject thisobject) {    LOGINFO(/"SampleJNI/",/"Sample Info Log Output/");    return (*env)->NewStringUTF(env, /"Unknown/");}  

示例应用的Android.mk文件如下所示。注意,它会加载log库:


LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE    := sampleLOCAL_SRC_FILES := sample.cLOCAL_LDLIBS    := -lloginclude $(BUILD_SHARED_LIBRARY)  

最后,是Java activity SampleActivityWithNativeMethods的源代码。该类加载示例库,并声明本地方法whatAmI。当单击按钮时,会调用whatAmI方法,并返回“Unknown”,然后显示字符串“CPU:Unknown”。如果你觉得输出的信息量很低,不要着急,在下一节中会添加CPU信息:


package com.oreilly.demo.android.pa.ndkdemo;import com.oreilly.demo.android.pa.ndkdemo.R;import android.widget.Toast;public class SampleActivityWithNativeMethods extends Activity {    static {        System.loadLibrary(/"sample/"); // load our sample lib    }    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.sample);        setupview;    }    public native String whatAmI; // sample lib native method    private void setupview {        findViewById(R.id.whatami).setOnClickListener(                                        new View.OnClickListener {            public void onClick(View v) {                String whatami = whatAmI;                Toast.makeText(getBaseContext, /"CPU: /"+whatami,                                            Toast.LENGTH_SHORT).show;            }        });    }