在标准的JAVA平台下,每一个Process都可以产生很多JAVA VM对象,每一个JAVA VM都有一个与之对应的JAVA VM对象,但是在Android平台上,每一个Process只可以产生一个Dalvik VM对象,也就是说一个Android中的进程有且只有一个虚拟机对象来服务所有的JAVA/C/C++代码。
JNIEnv*内部包含一个Pointer,Pointer指向Dalvik虚拟机的JAVA VM对象的Function Table,JNIEnv*关于程序执行环境的众多函数正是来源于Dalvik虚拟机。
Android中每一个JAVA线程第一个调用本地C/C++代码时,Dalvik虚拟机实例会为这个线程产生一个JNIEnv * 指针。
安装完Cygwin、NDK之后就可以开发程序了。
首先编写JAVA代码,新建一个安卓工程,本地方法要在函数名前加Native关键字声明,同时在static代码块中加载本地动态链接库。
package com.example.hellojni;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
public class HelloJNI extends Activity {
static{
System.loadLibrary("hello-jni");
}
public native String hello();
public native boolean isPrime(int num);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView tvBox = new TextView(HelloJNI.this);
StringBuilder msgBuilder = new StringBuilder();
msgBuilder.append(hello()).append("\n");
msgBuilder.append(isPrime(12)).append("\n");
tvBox.setText(msgBuilder.toString());
setContentView(tvBox);
}
}
然后,打开命令行Cmd,进入工程根目录,执行命令生成C代码的头文件,这一步主要是利用javah命令来帮助我们生成函数名,因为JNI是一个协议,对函数名称有苛刻的要求,我们用javah来生成,然后复制一下就相当方便了!当然,如果你闲的慌,也可以根据要求自己手写哦。
javah -classpath bin/classes -d jni com.example.hellojni.HelloJNI
我们刷新一下工程目录,就会工程下面出现了jni目录,打开它,就出现了我们想要的头文件:com_example_hellojni_HelloJNI.h,复制一下里面的函数名,在jni目录下新建hello-jni.c文件。这里要注意文件名和之前在java中LoadLibrary的参数相同。
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <jni.h>
#include <assert.h>
#include <android/log.h>
#define LOG_TAG "NDK study"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
/*
* Class: com_example_hellojni_HelloJNI
* Method: hello
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_example_hellojni_HelloJNI_hello
(JNIEnv * env, jobject jobj)
{
return (*env)->NewStringUTF(env, "Hello, Android NDK");
}
/*
* Class: com_example_hellojni_HelloJNI
* Method: isPrime
* Signature: (I)Z
*/
JNIEXPORT jboolean JNICALL Java_com_example_hellojni_HelloJNI_isPrime
(JNIEnv * env, jobject jobj, jint number)
{
LOGI("Java_com_example_hellojni_HelloJNI_isPrime called!");
jint i = 0;
jboolean bPrime = JNI_TRUE;
for( i = 2; i < number; i++){
if(number % i == 0){
bPrime = JNI_FALSE;
break;
}
}
return bPrime;
}
好了,代码写完了,编写Makefile文件。在Android中,Makefile文件名为Android.mk。同样,在jni目录下新建Android.mk文件,这里我也是抄的,修改一下文件名!
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hello-jni
LOCAL_SRC_FILES := hello-jni.c
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)
现在,只需要编译一下C语言文件就可以了,运行
$NDK/ndk-build
命令即可。相信你环境已经配好了。
运行Android程序即可。