JNI(Java Native Interface)的本意是Java本地调用,它是为了方便java调用C/C++等本地代码所封装的一层接口
Android NDK(Native Development Kit )是一套工具集合,通过NDK可以在Android中更加方便的使用JNI来访问本地代码
使用JNI的好处:
- 1.提高代码安全性,本地C代码反编译困难
- 2.方便的使用成熟C开源库,如:OpenGL,OpenSSL,SQLite3,FFmpeg
- 3.便于平台间的移植,so动态库可以很方便的在其他平台使用
- 4.应用程序对运行效率有要求,图形渲染,音视频解码等
- 5.操作底层硬件,Android平台上传感器
JNI的开发流程:
- 1.编写.c代码和.mk编译文件,执行ndk-build命令生成SO库
Android.mk
LOCAL_PATH := $(call my-dir) #提定当前路径
include $(CLEAR_VARS) #清除全局配置变量,LOCAL_XXX,除了LOCAL_PATH
LOCAL_MODULE := hello #指定生成动态库名hello,生成的动态库文件libhello.so
LOCAL_SRC_FILES := hello.c #指定生成动态库的源文件
include $(BUILD_SHARED_LIBRARY) #提定生成动态库
hello.c
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_ansen_activity_JNIActivity */
/*
* Class: com_ansen_activity_JNIActivity
* Method: test
* Signature: ()Ljava/lang/String;
*/
jstring JNICALL Java_com_ansen_activity_JNIActivity_hello(JNIEnv *env, jobject obj){
//jstring (*NewStringUTF)(JNIEnv*, const char*); 把C字符串转化为java中字符串
return (*env)->NewStringUTF(env,"C : hello world");
}
可以使用javah命令将JNIActivity生成.h的头文件,如下:
D:\Workspace_AS\CodeRepository\app\src\main\java>javah com.ansen.activity.JNIActivity
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_ansen_activity_JNIActivity */
#ifndef _Included_com_ansen_activity_JNIActivity
#define _Included_com_ansen_activity_JNIActivity
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_ansen_activity_JNIActivity
* Method: hello
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_ansen_activity_JNIActivity_hello
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
把.c和.mk文件放到jni目录下,在D:\Workspace_AS\CodeRepository\app\src\main\jni>路径下执行ndk-build命令(配置好了ndk环境)生成so文件,命令执行log如下:
D:\Workspace_AS\CodeRepository\app\src\main\jni>ndk-build
[arm64-v8a] Compile : hello <= hello.c
[arm64-v8a] SharedLibrary : libhello.so
[arm64-v8a] Install : libhello.so => libs/arm64-v8a/libhello.so
[x86_64] Compile : hello <= hello.c
[x86_64] SharedLibrary : libhello.so
[x86_64] Install : libhello.so => libs/x86_64/libhello.so
[mips64] Compile : hello <= hello.c
[mips64] SharedLibrary : libhello.so
[mips64] Install : libhello.so => libs/mips64/libhello.so
[armeabi-v7a] Compile thumb : hello <= hello.c
[armeabi-v7a] SharedLibrary : libhello.so
[armeabi-v7a] Install : libhello.so => libs/armeabi-v7a/libhello.so
[armeabi] Compile thumb : hello <= hello.c
[armeabi] SharedLibrary : libhello.so
[armeabi] Install : libhello.so => libs/armeabi/libhello.so
[x86] Compile : hello <= hello.c
[x86] SharedLibrary : libhello.so
[x86] Install : libhello.so => libs/x86/libhello.so
[mips] Compile : hello <= hello.c
[mips] SharedLibrary : libhello.so
[mips] Install : libhello.so => libs/mips/libhello.so
- 2.在java中加载so库,声明native方法
package com.ansen.activity;
import android.app.Activity;
import android.os.Bundle;
import com.ansen.common.ToastUtils;
public class JNIActivity extends Activity {
static {
System.loadLibrary("hello");
}
public native String hello();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ToastUtils.show(hello() + " ");
}
}
- 3.配置gradle ndk脚本
在app/build.gradle文件的android{}中添加一下代码:
// for JNI @{
sourceSets.main {
jni.srcDirs = []
jniLibs.srcDir 'src/main/libs'
}
task nativeLibsToJar(type:Zip,description:"create a jar archive of the native libs"){
destinationDir file("$projectDir/libs")
baseName "libJniTest"
extension "jar"
from fileTree(dir: "libs",include: "**/*.so")
into "lib"
}
tasks.withType(JavaCompile){
compileTask -> compileTask.dependsOn(nativeLibsToJar)
}
//}@