JNI即 Java Native Interface,支持java调用C和C++代码。 android使用c++的好处:
Cocos2d
、Box2D
等本文以HelloWorld为例,学习JNI的基本使用,教程参考自 极客学院wiki 。
最终目录结构:
└─Helloworld
├─bin
│ HelloWorld.class
│
├─jni
│ HelloWorld.c
│ HelloWorld.dll
│ HelloWorld.exp
│ HelloWorld.h
│ HelloWorld.lib
│ HelloWorld.obj
│
└─src
HelloWorld.java
native
关键字声明要c/c++实现的方法。public class HelloWorld {
// 声明native实现的方法
public static native String sayHello(String name);
public static void main(){
// 调用native方法
String result = HelloWorld.sayHello("chiyiw");
System.out.println(result);
}
static {
System.loadLibrary("HelloWorld"); // 加载类库
}
}
javac src\HelloWorld.java -d .\bin
javah -jni -classpath .\src -d .\jni HelloWorld
此时查看jni目录,已经生成了包含了HelloWorld类的native方法的HelloWorld.h文件
#include <jni.h>
#ifndef _Included_HelloWorld
#define _Included_HelloWorld
/*
* Class: HelloWorld
* Method: sayHello
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_HelloWorld_sayHello
(JNIEnv *, jclass, jstring);
#endif
这里的在JNIEXPORT
和JNICALL
之间的jstring
代表返回值
在jni中 jstring对应于Java中的String,jclass 对应 Class
参数:
参数 | 含义 |
---|---|
JNIEnv | 指向 VM 中的java方法的指针 |
jclass | 调用 方法的对象或类(当方法为static时) |
jstring | 传入参数 |
#include <HelloWorld.h>
JNIEXPORT jstring JNICALL Java_HelloWorld_sayHello
(JNIEnv *env, jclass cla, jstring j_str){
// jstring 转化为 char*
const char* name = (*env)->GetStringUTFChars(env, j_str, NULL);
printf("Hello %s\n");
// char* 转化为 jstring
return (*env)->NewStringUTF(env, "from jni");
}
由于java默认使用Unicode编码,而c/c++默认使用UTF编码,所以要相互转化使用。
动态库文件名命名规则:lib+动态库文件名+后缀(操作系统不一样,后缀名也不一样)
名称 | 平台 |
---|---|
libHelloWorld.so | Linux |
HelloWorld.dll | Windows (不需要lib ) |
libHelloWorld.jnilib | MacOS |
这里的不同只是因为在不同平台的环境不同,Android属于Linux,所以在Android中使用.so
以下在Windows 10 + VS2015 命令行下运行
F:\Code\Android\JNI\Helloworld\jni>cl -I"%JAVA_HOME%\include" -I"%JAVA_HOME%\include\win32" -LD HelloWorld.c -FeHelloWorld.dll
F:\Code\Android\JNI\Helloworld\jni>
编译完成,jni目录下自动生成了.dll文件
Linux 下:
gcc -I$JAVA_HOME/include -I$JAVA_HOME/include/linux -fPIC -shared HelloWorld.c -o libHelloWorld.so
java -Djava.library.path=F:\Code\Android\JNI\Helloworld\jni -classpath .\bin HelloWorld
Hello chiyiw
from jni
到此,HelloWorld就运行成功了! java运行时要传入了动态库绝对路径,否则不能加载到动态库。 当然,也可以在代码中直接指定,此时要使用完整路径和文件名
static {
System.loadLibrary("F:\Code\Android\JNI\Helloworld\jni\HelloWorld.dll");
}