JNI是什么?
JNI(Java Native Interface)意为JAVA本地调用,它允许Java代码和其他语言写的代码进行交互,简单的说,一种在Java虚拟机控制下执行代码的标准机制。
NDK是什么?
Android NDK(Native Development Kit )是一套工具集合,允许你用像C/C++语言那样实现应用程序的一部分。
为什么要用NDK?
1、安全性,java是半解释型语言,很容易被反汇编后拿到源代码文件,我们可以在重要的交互功能使用C语言代替。
2、效率,C语言比起java来说效率要高出很多(该不该使用jni这个需要结合项目环境需求,并不一定使用jni效率就比java高)。
JNI和NDK的区别?
从工具上说,NDK其实多了一个把.so和.apk打包的工具,而JNI开发并没有打包,只是把.so文件放到文件系统的特定位置。从编译库说,NDK开发C/C++只能能使用NDK自带的有限的头文件,而使用JNI则可以使用文件系统中带的头文件。从编写方式说,它们一样。
JNI具体的介绍就不多说了,网上很多的,这里主要讲一下编译so库和调用。之前是在eclipse里边编译的so库,相对来说比较起android studio麻烦一些,因为编译过程中又使用到了cygwin。
下面说说在android studio中编译so库,首先新建一个工程
新建一个类,并写一个native方法,用来调用so库中的方法
下一步就是清空工程,然后再编译工程
直到build目录下出现classes目录
接着使用命令生成c的头文件
使用命令进入到项目build目录下的debug目录
然后再使用javah -jni 类的包名加类名
如果java环境没错的话就会在debug目录下生产一个头文件
生产了头文件然后在src/main目录下新建一个jni的目录用来存放c的代码文件
将刚刚生成的c的头文件拷贝到jni目录下,文件的名字可以改
之后新建一个.c的文件,这个文件用来实现头文件中的方法,首先来看看生成的头文件的内容
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_caidongdong_contentprovider_util_JniUtil */
#ifndef _Included_com_caidongdong_contentprovider_util_JniUtil
#define _Included_com_caidongdong_contentprovider_util_JniUtil
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_caidongdong_contentprovider_util_JniUtil
* Method: getStringFromC
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_caidongdong_contentprovider_util_JniUtil_getStringFromC
(JNIEnv * env, jobject obj);
#ifdef __cplusplus
}
#endif
#endif
这个头文件是不用改的,下面贴上.c文件的内容
#include "mystring.h"
#include <string.h>
JNIEXPORT jstring JNICALL Java_com_caidongdong_contentprovider_util_JniUtil_getStringFromC
(JNIEnv * env, jobject obj){
return (*env)->NewStringUTF(env,"Hello from JNI !");
}
这个c文件的内容需要自己写的,首先引入头文件,使用#include 引入需要的头文件,这个跟java的import类似,但是有区别。拷贝生成的头文件中的方法到c文件中,注意要把行参补全
然后写上该方法的实现,当然这里只是简单的返回一个字符串,多说一句c和c++的方法有些是有区别的,所以写的时候注意选择。
c文件写好之后就可以配置编译环境,编译需要ndk我这里使用的ndk的版本是android-ndk-r11,下载好解压后在Android studio中配置ndk路径
选择ndk的路径
下一步,启用ndk编译,需要在gradle.properties中配置
android.useDeprecatedNdk=true
下一步,需要在app的build.gradle中的defaultConfig配置ndk生成的so库名称依据生成多个平台的包
下一步,在含有native方法的类中加载so库
public class JniUtil {
static {
System.loadLibrary("my_lib");
}
public native String getStringFromC();
}
然后在activity中使用该类并调用其中的方法
JniUtil jniUtil = new JniUtil();
content.setText(jniUtil.getStringFromC());
最后的运行效果图
在工程目录下的lib并没有生成so库,因为gradle已经自动的帮我们生成好了,工程目录下就有,如果反编译apk的话,就会发现so库是存在于lib中的。