JNA的使用
使用背景
- 在安卓開發(fā)過程中,常常會需要和C,C++等交互,這時候我們就想起了JNI,但是JNI的使用過程十分繁瑣,而且容易出現(xiàn)各種形形色色的問題,還得封裝而且問題不好定位所以對調(diào)用大量的c程序造成困擾。相比之下JNA的簡易程度令人發(fā)指,你只需要一個jar包,就可以像調(diào)用一個java方法一樣簡單。假如我們只有一個.so文件,我們使用JNI去調(diào)用,我們需要另外用C語音寫一個.so的共享文件,并且得使用SUN規(guī)定的數(shù)據(jù)結(jié)構(gòu)去替代C語言的數(shù)據(jù)結(jié)構(gòu),至此才能調(diào)用so文件里面公布的函數(shù)。作為搞JAVA的程序員這個過程是令人頭疼的。
如上圖所示Jna省去了令Java程序員頭疼的Jni中間鍵共享庫的封裝。官方言簡意賅的描述:JNA provides Java programs easy access to native shared libraries without writing anything but Java code - no JNI or native code is required.
-
為了更加直觀的體現(xiàn)Jna的優(yōu)勢,我編了一個簡單的so庫,分別用JNA和Jni來調(diào)用Native方法。
Native 方法和頭文件內(nèi)容如下:
2.png
編譯得到wer.so里面有add方法。
- 現(xiàn)在我們使用Jni方式去調(diào)用wer里面的add方法。
-
先去封裝jni調(diào)用的中間鍵,代碼如如圖:
4.png
在編寫jni中間鍵的時候還要注意頭文件的引用,方法的全路徑,Android.mk的配置,稍有不慎在調(diào)用的時候就會引起喜聞樂見的崩潰。
-
在項目中調(diào)用封裝好的庫,如下圖:
7.png
注意這塊的方法全路徑必須和native里面的一致。Jni必須這樣,然后jna就可以不這樣。
Jna的調(diào)用
-
引入jna的jar包和對應(yīng)的jnidispatch.so.然后編寫jnatools 如下:
8.png
僅僅這么一步就搞定了,激動不?。。?/p>
JNA簡介
- JNA(Java Native Access )提供一組Java工具類用于在運行期動態(tài)訪問系統(tǒng)本地庫(native library:如Window的dll,Android的so)而不需要編寫任何Native/JNI代碼。開發(fā)人員只要在一個Java接口中描述目標(biāo)native library的函數(shù)與結(jié)構(gòu),JNA將自動實現(xiàn)Java接口到native function的映射。
- 在github上的傳送門---JNA
-
對應(yīng)的數(shù)據(jù)類型如下圖:
type.png
JNA的使用
- 在github上下載jna.jar和對應(yīng)平臺的 libjnidispatch.so ,并在項目中配置好。
根據(jù)Native的頭文件愉快的編寫Java代碼。
-
一路哼著小歌就把Native方法調(diào)起來了,再也不用考慮jni的路徑問題,可以在任意路徑下折騰啦。
運行結(jié)果如下:
展示 .png
jna中 一些常用數(shù)據(jù)類型的簡單示例。
char *
c代碼實現(xiàn)
int getName(char *name,char * s) {
if(name==NULL||s==NULL){
return -1;
}
int result=strcmp(name, "大包子");
char dabaozi[40] ="大包子最帥!";
char other [40] = "其他人一般帥。。。";
if (result == 0) {
memcpy(s, dabaozi, strlen(dabaozi));
}
else {
memcpy(s, other, strlen(other));
}
return 0;
}
java代碼調(diào)用
String s = et_name.getText().toString();
byte [] bytename=new byte[50];
ByteBuffer call=ByteBuffer.wrap(bytename);
ByteBuffer name=ByteBuffer.wrap(new String(s).getBytes());
int re = JnaTools.INSTANCE.getName(name, call);
tv_result.setText(new String(call.array()));
- int *
c代碼實現(xiàn)
int getAge(int *age){
*age=18;
return 0;
}
java代碼
String s = et_name.getText().toString();
byte [] bytename=new byte[50];
ByteBuffer call=ByteBuffer.wrap(bytename);
ByteBuffer name=ByteBuffer.wrap(new String(s).getBytes());
int re = JnaTools.INSTANCE.getName(name, call);
tv_result.setText(new String(call.array()));
- C結(jié)構(gòu)體
c代碼實現(xiàn)
int getStructInfo(struct _Person * person){
person->age=18;
char name[10] ="大包子";
memcpy(person->name, name, strlen(name));
return 0;
}
java代碼調(diào)用
JnaTools._Person person=new JnaTools._Person();
JnaTools.INSTANCE.getStructInfo(person);
tv_result.setText("name="+new String(person.name)+"age="+person.age);
- JnaTools代碼
package com.bigbaozi.jna.api;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Structure;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.util.Arrays;
import java.util.List;
/**
* Name: JnaTools
* Author: dabaozi
* Email:
* Comment: //TODO
* Date: 2017-11-09 14:04
*/
public interface JnaTools extends Library {
public static final String JNA_LIBRARY_NAME = "wer";
public static final JnaTools INSTANCE = (JnaTools) Native.loadLibrary(JnaTools.JNA_LIBRARY_NAME, JnaTools.class);
public static class _Person extends Structure {
public int age;
public byte[] name = new byte[11];
public byte[] type = new byte[20];
public _Person() {
super();
}
protected List<String> getFieldOrder() {
return Arrays.asList("age", "name", "type");
}
public _Person(int age, byte name[], byte type[]) {
super();
this.age = age;
if ((name.length != this.name.length))
throw new IllegalArgumentException("Wrong array size !");
this.name = name;
if ((type.length != this.type.length))
throw new IllegalArgumentException("Wrong array size !");
this.type = type;
}
public static class ByReference extends _Person implements Structure.ByReference {
};
public static class ByValue extends _Person implements Structure.ByValue {
};
};
int add(int x, int y);
int getAge(IntBuffer age);
int getName(ByteBuffer name, ByteBuffer s);
int getStructInfo(JnaTools._Person Person);
}
這時候有人會說每次去寫JnaTools這個里面的數(shù)據(jù)類型轉(zhuǎn)換我不想干,其實我也不想干,么么噠那么便成全你吧 高不高興?。?!
前方高能,放大招中。。。。
- 如上圖所示將c的頭文件復(fù)制到左邊,配置好類名,然后點擊JNAerate ,自動轉(zhuǎn)換成我們所有的Java文件。
寫在最后,作為程序員的我保存住了程序員的優(yōu)良傳統(tǒng)(語言表達(dá)能力捉急)以上文章中如有不當(dāng)之處,歡迎大家狠狠的批評指正