平时在开发中,或多或少都会用到JNI方面的技术,比如我们项目中,消息的加密和解密就是通过C来实现的,然后打包为.so动态库,并提供Java接口供应用层调用,这么做的目的主要就是为了提供应用的安全性,防止被反编译后被分析加密的逻辑。
接下来就要介绍JNI和NDK的区别,怎样创建一个项目开发JNI。

JNI与NDK

JNI

Java Native Interface,即Java本地接口,使用JNI可以使得Java与本地其他类型语言(如C、C++)交互。
JNI是 Java调用Native语言的一种特性,JNI是属于Java的,与 Android无直接关系。

NDK

Native Development Kit,是Android的一个工具开发包。
NDK是属于Android的,与Java并无直接关系,只是通过NDK可以快速方便的使用JNI,开发C、C++动态库。

##开发JNI

开发JNI,一般都有两种途径:

Java项目直接引用生成好的动态库,动态库的具体C、C++代码在其他地方编写变生成动态库(常见的为在Window平台上的VS编写,在Mac平台上的Xcode编写,或者直接用命令行编写),引用第三方库大多就是采用这种方式

Android Studio项目中通过NDK实现JNI

Java项目调用Xcode编译动态库

1.创建Xcode项目,选择Library,选择为C++库

pic
pic

2.先删除多余文件和代码,引入jni.h头文件

pic

此时你的jni.h会报错.
不用急

3.设置jni.h头文件的路径,即Java环境的配置路径

分别添加进include目录和include/darwin目录

pic

编译运行就不会报找不到头文件的错误了,同时,可以看到生成了动态库libStudyNdk.dylib,记录动态库的路径/Users/…../Library/Developer/Xcode/DerivedData/StudyNdk-asdfasdfadsfeeeyglsvxjelvnth/Build/Products/Debug/libStudyNdk.dylib,接下来会使用到。

4.编写Java代码调用native代码

调用native代码,可以直接使用Test包中的测试类来进行测试,只要是Java类就可以了,可以在Android Studio中创建Java目录。上面介绍jni也说到,jni是与Java有关的,与Android没关系,只要是Java项目都可以使用到。

接下来,使用IntelliJ IDEA来测试.

pic

加载动态库,传入动态库的绝对路径,另外还有System.loadLibrary()方法,传入为动态库的名字,不需要动态库的后缀。

5.在XCode中完成native代码

方法名格式为Java_包名_类名_方法名(JNIEnv,jobject){},编译运行生成动态库

1
2
3
4
JNIEXPORT void JNICALL Java_com_uilucky_demo_MyClass_getString
(JNIEnv *env, jclass type) {//具体实现
printf("接收到Java的调用");
}

也可以自行创建MyClass.h文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_uilucky_dome_MyClass */

#ifndef _Included_com_uilucky_dome_MyClass
#define _Included_com_uilucky_dome_MyClass
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_guidongyuan_jnilib_MyClass
* Method: test
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_uilucky_demo_MyClass_getString
(JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

6.运行Java代码

可以看到终端的输出,成功调用到native的代码

pic

要注意的是,Mac平台上的动态库,和Android平台上使用的.so平台上不一样的,就算是在Mac平台上,编译为后缀名为.so,不过不是生成arm架构编译的话,直接放在apk包中去调用,同样会出现异常.