Android 应用程序是运行在Dalvik虚拟机之上的。NDK可以让你用本地代码例如C/C++来实现应用程序的一部分。这样可以为应用程序的某些类在复用已有代码或提高性能方面提供便利。
如果你的代码是用C/C++来实现的,你的应用程序仍然会被打包成.apk文件,并且仍然运行在虚拟机上。Android应用程序的模型是不变的。NDK的官方下载地址为:
http://developer.android.com/sdk/ndk/index.html
下载完成后进行解压,就可以直接使用目录中的ndk-build了。为了使用方便,可以用如下命令将ndk-build放入默认路径中:
export PATH=$PATH:<你解压好的目录地址>
目前为止,用C/C++编写Android应用程序有两种方式:
1. 用C/C++编写主要的逻辑层,再用java编写界面层并调用C/C++的库;
2. 用C/C++直接开发完整的应用程序,完全不用java。(仅Android 2.3之后的版本支持)
第一种方法较为通用,因为用java开发Android应用程序的界面比较简单;第二种方法较为复杂并且很少用到。在此我们只介绍第一种使用方法的步骤,第二种使用方法可以在第一种方法的基础上,参照NDK目录中自带的例子程序samples/native-activity。
我们以一个简单的例子,一步步带领大家写出一个简单的hello-jni程序。
如果你使用eclipse进行开发,很简单,在此就不赘述了。不过为了与下文的名称保持一致,请把项目名设为hello-jni,包名为com.example.hellojni,类名为HelloJni。
如果你使用shell进行开发,执行如下三行命令即可:
mkdir hello-jni cd hello-jni android create project -p . -t android-8 -k com.example.hellojni -a HelloJni
在项目目录下新建一个jni目录,然后在jni目录下建立两个文件:
第一个:main.c文件,内容如下:
#include <string.h> #include <jni.h> /* This is a trivial JNI example where we use a native method * to return a new VM String. See the corresponding Java source * file located at: * * hello-jni/src/com/example/HelloJni/HelloJni.java */ 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)
直接在hello-jni目录下执行ndk-build。如果编译成功,可以看到生成了libs/armeabi/libhello-jni.so文件,该文件就是我们得到的C库了。
第四步 在java源码中调用C库中的函数
在hello-jni下打开src/com/example/jni/HelloJni.java文件,可以看到Android SDK已经帮我们自动生成了一些代码:
package com.example.jni; import android.app.Activity; import android.os.Bundle; 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); } }为了调用我们用C写好的函数,需要对其进行简单修改,修改后内容如下:
package com.example.hellojni; import android.app.Activity; import android.widget.TextView; import android.os.Bundle; public class HelloJni extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); TextView tv = new TextView(this); tv.setText( stringFromJNI() ); setContentView(tv); } public native String stringFromJNI(); static { System.loadLibrary("hello-jni"); } }对比两个文件可以看到需要修改的几个地方:
1. 引入了一个 TextView
TextView tv = new TextView(this);2. 在末尾,我们在static域内调用了:
System.loadLibrary("hello-jni");这个调用的目的就是引入刚刚编译好的那个C库,这个C库的名字就叫hello-jni,这个名字是我们在Android.mk文件中指定的:
LOCAL_MODULE := hello-jni这两处的名称需要保持一致。
3. 我们声明了一个函数
public native String stringFromJNI();并在TextView中调用了它,将其返回结果显示出来
tv.setText( stringFromJNI() );这个函数定义的地方,就是我们在刚刚C文件中写道的
jstring Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env, jobject thiz ) { return (*env)->NewStringUTF(env, "Hello from JNI !"); }有人会问这两个函数的名称为什么不一样,有什么对应关系。没错,是不同。对应关系是
C中定义的名称为:Java_包名_类名_函数名
java中调用的名称为:函数名
如果你使用eclipse进行开发,点击编译运行就可以了。
如果你使用shell进行开发,输入命令:
ant debug在bin下就得到了HelloJni-debug.apk,用adb install即可进行安装了。