Android中JNI和NDK的使用

最近乘着找工作闲余时间又温故了一遍android中的JNI何NDK的使用,一方面是为了巩固一下基础以防面试会问到,一方面是丰富一下博客内容,言归正传。

了解android中NDK的使用之前首先要知道JNI和NDK到底有什么关系,这是很多初学者的疑惑,我开始接触的时候也有过类似的疑问。如下解释(网络拷贝过来):

对于JNI和NDK很多Android开发初学者没有搞明白这个问题,JNI是Java调用Native机制,是Java语言自己的特性全称为Java Native Interface,类似的还有微软.Net Framework上的p/invoke,可以让C#或Visual Basic.Net可以调用C/C++的API,所以说JNI和Android没有关系,在PC上开发Java的应用,如果运行在Windows平台使用JNI是是经常的,比如说读写Windows的注册表。

而NDK是Google公司推出的帮助Android开发者通过C/C++本地语言编写应用的开发包,包含了C/C++的头文件、库文件、说明文档和示例代码,我们可以理解为Windows Platform SDK一样,是纯C/C++编写的,但是Android并不支持纯C/C++编写的应用,同时NDK提供的库和函数功能很有限,仅仅处理些算法效率敏感的问题,所以Android123推荐初学者学好Java后再学习JNI。

说白了,JNI是JAVA特有的东西,是为了提升JAVA语言的性能,C/C++效率肯定比JAVA的高,JNI的作用就是将一些耗时耗内存的工作交给C/C++来做,然后通过JNI来调用,因为JAVA不能直接使用外部语言。本地方法的声明,实现以及调用接下来会一一介绍。

在PC端例如在windows中,通过VC等编译器可以将生成的本地方法(也就是.c文件)生成动态链接库(.dll),而在android中(基于Linux的系统)会生成.so文件,而NDK就起到了类似如VC编译器的作用,为了方面开发者将所编写的.c文件打包成.so文件之用。

下面写个小例子方面理解Android中JNI和NDK的使用。

首先在eclipse中新建工程JNI_1,如下:

1、MainActivity.java如下:

package com.ldw.jni;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

public class MainActivity extends Activity {

	private static String libName = "Hello";

	static {
		System.loadLibrary(libName);
	}

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
	}

	public void startJNI(View v) {
		Toast.makeText(getApplicationContext(), getStringFromJNI(), Toast.LENGTH_SHORT).show();
	}

	public native String getStringFromJNI();

}

这里有个地方要注意下,生成的so文件NDK默认会在前面加上lib,loadLibrary的时候注意库文件的名字不要加lib。

2、生成.h头文件

在工程的bin/classes中找到编译器生成的.class文件,会有一个MainActivity.class,使用如下命令生成头文件:

或者可以在环境变量中配置好classpath也可以,因为MainActivity中有我们引用的android中才有的SDK,注意类名要用全名且不能带.class拓展名。这样执行以后会在bin\classes中生成com_ldw_jni_MainActivity.h的头文件。里面的内容主要是生成的

JNIEXPORT jstring JNICALL Java_com_ldw_jni_MainActivity_getStringFromJNI
(JNIEnv *, jobject)函数,可以这样理解:.h文件相当于java里面的接口,而Java_com_ldw_jni_MainActivity_getStringFromJNI方法相当于接口里面的方法,也就是说我们在编写C/C++程序的时候所使用的方法名必须和这里的一致。

3、接下来是编写本地方法,在工程下建立一个名为jni的目录,新建一个名为HelloWorld.c的文件,如下:

#include<string.h>
#include<jni.h>
jstring JNICALL Java_com_ldw_jni_MainActivity_getStringFromJNI(JNIEnv *env, jobject thiz) {
	return (*env)->NewStringUTF(env, "HelloWorld from JNI!");
}

返回一个字符串,JNI函数的说明网上有很多例子。

4、编写mk文件,mk文件的可以看看这里

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := libHello

LOCAL_SRC_FILES := HelloWorld.c

include $(BUILD_SHARED_LIBRARY)

5、使用NDK编译.c文件,这里可以看看环境变量的配置

此时在libs/armeabi目录下会多个.so文件。

运行一下程序试试看看效果如何。这里是源文件。

JNI很多高深的东西需要我们慢慢去摸索,我也是初学者,接下来可以尝试着编译一些开源的项目。

《Android中JNI和NDK的使用》上有2条评论

    1. 有道理,把上个博客的内容给补上来,先基础,然后再整点高级的。

评论已关闭。