入手 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

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