"放棄Jni"愉快的奔向JNA

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
3.png

編譯得到wer.so里面有add方法。

  • 現(xiàn)在我們使用Jni方式去調(diào)用wer里面的add方法。
  • 先去封裝jni調(diào)用的中間鍵,代碼如如圖:


    4.png
5.png
6.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 ,并在項目中配置好。

懶人傳送門CSDN下載。也可以clone我的demo里面有項目源碼

  • 根據(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)換我不想干,其實我也不想干,么么噠那么便成全你吧 高不高興?。?!

哈哈.jpg

前方高能,放大招中。。。。

jnatools.png
  • 如上圖所示將c的頭文件復(fù)制到左邊,配置好類名,然后點擊JNAerate ,自動轉(zhuǎn)換成我們所有的Java文件。

寫在最后,作為程序員的我保存住了程序員的優(yōu)良傳統(tǒng)(語言表達(dá)能力捉急)以上文章中如有不當(dāng)之處,歡迎大家狠狠的批評指正

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容