JNA(Java Native Access )提供了一组Java工具类用于在运行期间动态访问系统本地库(native library:如Window的dll)而不需要编写任何Native/JNI代码。开发人员只要在一个java接口中描述目标native library的函数与结构,JNA将自动实现Java接口到native function的映射。
优点:JNA可以让你像调用一般java方法一样直接调用本地方法。就和直接执行本地方法差不多,而且调用本地方法还不用额外的其他处理或者配置什么的,也不需要多余的引用或者编码,使用很方便。
JNA
JNAerator
要想使用JNA,我们需要对应的jna.jar和libdispatch.so。下面提供了两种方式:
Eclipse 下载jar和so。下载解压aar后,得到jar和so,添加到工程即可。具体配置如下图:
aar解压后中文件
jni文件夹中各个平台的 so
Eclipse中的配置
Android Studio 的 gradle 添加依赖
compile 'net.java.dev.jna:jna:4.4.0@aar'
-dontwarn java.awt.*
-keep class com.sun.jna.* { *; }
-keepclassmembers class * extends com.sun.jna.* { public *; }
工程结构
用test.h test.cpp生成libtest.so,然后通过jna的api与test.h中的接口一一对应即可。
jni/test.h
#ifndef TEST_H
#define TEST_H
#ifdef __cplusplus
extern "C" {
#endif
void getStr(char *name);
int add(int a, int b);
#ifdef __cplusplus
};
#endif
#endif
jni/test.cpp
#include
#include
#include
#include "test.h"
void getStr(char *name) {
char str[10] = "abcdefg\n";
memcpy(name, str, strlen(str));
}
int add(int a, int b) {
return a+b;
}
上面是so部分即C++部分,下面java部分。
src/com/pachong/jnatest/MainActivity.java
public class MainActivity extends Activity implements OnClickListener {
private EditText mETNumber1, mETNumber2;
private TextView mTVResult, mTVGetStr;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mETNumber1 = (EditText) findViewById(R.id.id_et_num_1);
mETNumber2 = (EditText) findViewById(R.id.id_et_num_2);
mTVResult = (TextView) findViewById(R.id.id_tv_result);
mTVGetStr = (TextView) findViewById(R.id.id_tv_get);
findViewById(R.id.id_bt_equal).setOnClickListener(this);
findViewById(R.id.id_bt_get).setOnClickListener(this);
}
public interface TestLibrary extends Library {
public static final TestLibrary INSTANCE = Native.loadLibrary("test", TestLibrary.class);
public void getStr(ByteBuffer name);
public int add(int a, int b);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.id_bt_equal:
String numberStr1 = mETNumber1.getText().toString();
String numberStr2 = mETNumber2.getText().toString();
if (TextUtils.isEmpty(numberStr1)) {
numberStr1 = "0";
}
if (TextUtils.isEmpty(numberStr2)) {
numberStr2 = "0";
}
int number1 = Integer.parseInt(numberStr1);
int number2 = Integer.parseInt(numberStr2);
int result = TestLibrary.INSTANCE.add(number1, number2);
mTVResult.setText(Integer.toString(result));
break;
case R.id.id_bt_get:
byte[] buffer = new byte[20];
ByteBuffer byteBuffer = ByteBuffer.wrap(buffer);
TestLibrary.INSTANCE.getStr(byteBuffer);
String str = new String(byteBuffer.array());
mTVGetStr.setText(str);
break;
default:
break;
}
}
}
res/layout/activity_main.xml
"http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
"match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
"@+id/id_et_num_1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:inputType="numberSigned" >
"wrap_content"
android:layout_height="wrap_content"
android:text="+"
android:textAppearance="?android:attr/textAppearanceLarge" />
"@+id/id_et_num_2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:inputType="number" />
"@+id/id_tv_get"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:textAppearance="?android:attr/textAppearanceLarge" />
java部分最重要的就是下面这段代码了。
public interface TestLibrary extends Library {
public static final TestLibrary INSTANCE = Native.loadLibrary("test", TestLibrary.class);
public void getStr(ByteBuffer name);
public int add(int a, int b);
}
通过继承jna的Libraray类,然后调用Native.loadLibrary加载so库,然后重写对应C++接口函数即可。
上面是运行后的结果,成功从C++层获取到了相关接口,完全不用再自己去写jni的代码了。
上面我们已经知道了JNA的基本用法,但是对于jna的api和C++代码之间的一些类型定义,我们还不是很熟练。怎么办?有没有办法一键生成相应的C++和java的对应关系,这个时候JNAerator就派上用场了。
第一步:下载jar
jnaerator.jar 下载
第二步:使用cmd命令打开JNAerator
java -jar jnaerator-0.12-shaded.jar
第三步:用JNAerator将C++代码生成对应的java代码
将C++代码复制粘贴到左边编辑框中,点击菜单栏的 JNAerate 即可生成对应的java代码。是不是很简单!从此,再也不用为写JNI代码而头疼了。
jna.aar
jnaerator.jar
demo apk