JNI(Java Native Interface)
目的:
** 实现了Java和其他语言(主要是c和c++)的通信**
通过JNI我们可以从java调用c/c++中的代码,或c/c++中调用java中的代码。
今天我们来看看JNI到底有多简单,根据国际惯例,我们先从HelloWorld开始,下面我们用java调用c中的方法。
前提:
- NDK环境(具体怎么配置我这就不讲了,问Google和度娘都行)
- 新建一个Android项目
项目右击,打开Module Settings
在Module Settings中配置ndk路径,如下图:
正文:
新建一个JNI类,在里面写一个本地方法printHelloWorld,用来调用c中的函数
<code>
public class JNI {
public native String printHelloWorld();
}
</code>生成c语言中与java中printHelloWorld方法匹配的函数,C语言方法的格式:<b>返回类型 Java_包名(包名用_代替原来的.)_类名</b>,这里我们可以使用<b>javah</b>命令防止我们将方法写错和在很多方法的情况下快速的生成。
-
打开AS的Terminal,进入java目录下
<code>cd /d D:\work\work_as\JNIDemo\app\src\main\java
</code>
进入java目录.png -
使用javah命令生成.h文件(javah -jni 包名.类名)
<code>>javah -jni com.chen.jnidemo.JNI
</code>
进入java目录,使用javah命令.png -
刷新项目,你会发现在java目录下多了一个.h文件。
javah命令之后.png 在java目录下新建jni文件夹,在其中添加c文件
- 将生成的.h文件中的 <code>JNIEXPORT jstring JNICALL Java_com_chen_jnidemo_JNI_printHelloWorld (JNIEnv *, jobject);</code>方法复制到c文件中,实现该方法:
<code>
/#include <jni.h>
JNIEXPORT jstring JNICALL Java_com_chen_jnidemo_JNI_printHelloWorld
(JNIEnv env, jobject jobj) {
return (env)->NewStringUTF(env, "Hello World");
}
</code>
在gradle.properties文件中添加<code>android.useDeprecatedNdk=true</code>
在app下的build.gradle添加
<code>
defaultConfig {
...
ndk {
moduleName "jnitest"
abiFilters "armeabi", "armeabi-v7a", "x86"
}
}</code>
(注意:注意这里的moduleName,就是在类里面加载的so库名)在类中加载库名,使用System.loadLibrary("库名");
<code>
package com.chen.jnidemo;
public class JNI {
static {
System.loadLibrary("jnitest");
}
public native String printHelloWorld();
}
</code>-
设置源码路径(可以不设置,不设置的话Rebuild Project,然后去app\build\intermediates\ndk\debug\lib下将各个版本的so文件拷到lib目录下,和我们平时导入so文件一样)
<code>
sourceSets.main {
jni.srcDirs = ['src/main/jni']
}
</code>
不设置源码路径时的so文件
不设置源码路径.png
- 在windows中的AS下ndk编译有一个bug,如果只有一个源文件(.C和.cpp文件,不算.h),则会编译错误,目前还没有修复,所以我们可以新建一个空的.c文件就可以编译通过了
- 代码中调用JNI中的方法
<code>
package com.chen.jnidemo;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.main_btn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showToast();
}
});
}
private void showToast() {
JNI jni = new JNI();
Toast.makeText(this, jni.printHelloWorld(), Toast.LENGTH_SHORT).show();
}
}
</code>
-
完成
完成.jpg