入手 JNA 跟 JNI 說拜拜

這裏寫圖片描述

簡介

JNA(Java Native Access )提供了一組Java工具類用於在運行期間動態訪問系統本地庫(native library:如Window的dll)而不需要編寫任何Native/JNI代碼。開發人員只要在一個java接口中描述目標native library的函數與結構,JNA將自動實現Java接口到native function的映射。

優點:JNA可以讓你像調用一般java方法一樣直接調用本地方法。就和直接執行本地方法差不多,而且調用本地方法還不用額外的其他處理或者配置什麼的,也不需要多餘的引用或者編碼,使用很方便。

GitHub 地址

JNA
JNAerator

JNA 相關資源下載配置

要想使用JNA,我們需要對應的jna.jar和libdispatch.so。下面提供了兩種方式:

一、直接下載 jar 和 so

Eclipse 下載jar和so。下載解壓aar後,得到jar和so,添加到工程即可。具體配置如下圖:

aar解壓後中文件

這裏寫圖片描述

jni文件夾中各個平臺的 so

這裏寫圖片描述

Eclipse中的配置

這裏寫圖片描述

二、用 gradle 產生依賴

Android Studio 的 gradle 添加依賴
compile 'net.java.dev.jna:jna:4.4.0@aar'

使用Proguard混淆代碼

-dontwarn java.awt.*
-keep class com.sun.jna.* { *; }
-keepclassmembers class * extends com.sun.jna.* { public *; }

JNA實戰

工程結構

這裏寫圖片描述

用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 <jni.h>
#include <stdio.h>
#include <string.h>
#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

<LinearLayout xmlns:android="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" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >

        <EditText
            android:id="@+id/id_et_num_1"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:gravity="center"
            android:inputType="numberSigned" >
        </EditText>

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="+"
            android:textAppearance="?android:attr/textAppearanceLarge" />

        <EditText
            android:id="@+id/id_et_num_2"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:gravity="center"
            android:inputType="number" />

        <Button
            android:id="@+id/id_bt_equal"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="="
            android:textAppearance="?android:attr/textAppearanceLarge" />

        <TextView
            android:id="@+id/id_tv_result"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:gravity="center"
            android:textAppearance="?android:attr/textAppearanceLarge" />
    </LinearLayout>

    <TextView
        android:id="@+id/id_tv_get"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text=""
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <Button
        android:id="@+id/id_bt_get"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="getStr" />

</LinearLayout>

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的代碼了。

JNAerator 資源下載

上面我們已經知道了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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章