Android JNI 开发

①:NDK与JNI简介

NDK:Native Development Kit,是Android的一种开发工具包,能够快速开发C,C++的动态库,并自动将so和应用打包成APK。而NDK的使用场景就是通过NDK在Android中使用JNI。

JNI:Java Native Interface的缩写,即Java的本地接口,JNI可以使得Java与C,C++语言进行交互。

NDK优点:

1.APK的Java层代码很容易被反编译,而C/C++库反编译难度较大

2.将要求高性能的应用逻辑使用C开发,从而提高应用程序的执行效率。

3.用C/C++写的库可以方便在其他的嵌入式平台上再次使用,如在Android、iOS使用

②:JNI项目结构

1.在新建native项目后,项目目录结构会包含一个cpp目录,包含CMakeLists.txt(AS版本差异,不一定在cpp目录下)与native-lib.cpp两个文件。native-lib中包含一个本地方法的实现。

 2.demo的MainActivity中,加载了名为native-lib的so库,并声明了一个本地方法。该方法与native-lib.cpp文件中的方法对应。

3.app的build.gradle中,会声明cmake的版本与路径,路径依据CMakeLists.txt文件路径决定

 

4.demo中CMakeLists.txt主要配置说明:

add_library():将native-lib.cpp转换成SHARED(共享)库,命名为native-lib;

find_library():寻找想要添加的NDK库名,一般为系统提供的库;

target_link_libraries():将目标库与库文件进行连接,可以链接多个库;

set_target_properties():加载第三方so库;

 

 

③:JNI开发

例子一:C对象转换为Java对象,基本数据类型的转换与方法互调用练习

step 1:新增一个名为Hero.cpp文件,并编写各类C方法,详细信息间注释。


/**
 * Herocpp
 *
 * @author wangqikai5
 * @version 1.0, 2022/1/17
 * @since 产品模块版本
*/

#include <jni.h>
#include <string>
#include <malloc.h>

using namespace std;

//定义结构体
struct Flash{
    int age;
    char firstName;
    float speed;
    double weight;
    bool gender;
    string name;
    unsigned char array[3];

}flash;

//赋值
Flash getFlash () {
    flash.age = 23;
    flash.firstName = 'f';
    flash.speed = 233333.2f;
    flash.weight = 58.9;
    flash.gender = true;
    flash.name = "Bary Alen";
    for (int i = 0; i < 3; ++i) {
        //asckII码往上加,值为f g h
        flash.array[i] = i + 'f';
    }
    return flash;
}


extern "C" JNIEXPORT jobject JNICALL
Java_com_helper_jnidemo_MainActivity_getFlash(JNIEnv *env, jobject thiz) {

    //获取结构体数据
    Flash f = getFlash();
    //string转成Java String的时候要转成jstring
    jstring name = env->NewStringUTF(f.name.c_str());
    //初始化一个jchararray用于存放array数据
    jcharArray array = env->NewCharArray(3);
    //开辟一个jchar数组
    jchar *pArry =  (jchar*) malloc(3);
    for (int i = 0; i < 3; i++) {
        //将char[]数组中的内容,先赋值到jchar数组
        *(pArry + i) = f.array[i];
    }
    //然后再付给jchararray
    env->SetCharArrayRegion(array, 0, 3, pArry);
    //获取Java类
    jclass flash = env->FindClass("com/helper/jnidemo/Flash");
    //获取Java类的构造方法,
    // <init>代表类的构造方法,如果是其他方法,就是传方法名
    //第三个参数,sig,分别为Flash类构造方法中各参数的代表值
    //I:int, C:char, F:float, D:double, Z:boolean, [C:char[], Ljava/lang/String;代表String
    jmethodID init = env->GetMethodID(flash, "<init>", "(ICFDZ[CLjava/lang/String;)V");
    //构造Flash对象,注意后最后的数组与String,是取上面装换的内容
    jobject obj = env->NewObject(flash, init, f.age, f.firstName, f.speed, f.weight, f.gender, array, name);

    //释放开辟的内存
    free(pArry);

    return obj;
}

step 2:CMakeLists里面添加名为Hero的库。


#设置编译时CMake的最低需求版本
cmake_minimum_required(VERSION 3.10.2)

# Declares and names the project.
project("jnidemo")

# 这里是将native-lib.cpp转换成SHARED(共享)库,命名为native-lib
add_library(
        # 库名称
        native-lib

        # 库的类型:SHARED表示动态so库,STATIC表示静态a库
        SHARED

        #编译的cpp文件源文件路径
        native-lib.cpp)

# 这里将Hero.cpp文件装换成转换成SHARED库,命名为Hero
add_library(
        # 库名称
        Hero

        # 库的类型:SHARED表示动态so库,STATIC表示静态a库
        SHARED

        #编译的cpp文件源文件路径
        Hero.cpp)

#可以add多个库,继续写 add_library

#寻找想要添加的NDK库名,一般为系统提供的库
find_library( # 自定义名称
        log-lib

        #系统库名称,这边是系统提供的log库
        log)

# 将so库与库文件进行连接,可以链接多个库,类似Android里面的依赖添加
target_link_libraries(
        #
        native-lib

        #
        Hero

        #avcodec

        # log的库名称
        ${log-lib})

step 3:Java层新建一个名为Flash的类。

/**
 * Flash类
 *
 * @author wangqikai5
 * @version 1.0, 2022/1/17
 * @since 产品模块版本
 */
public class Flash {

    private int age;
    private char firstName;
    private float speed;
    private double weight;
    private boolean gender;
    private String name;
    private char[] array;

    public Flash(int age, char firstName, float speed, double weight, boolean gender, char[] array,String name) {
        this.age = age;
        this.firstName = firstName;
        this.speed = speed;
        this. weight = weight;
        this.gender = gender;
        this.array = array;
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public char getFirstName() {
        return firstName;
    }

    public void setFirstName(char firstName) {
        this.firstName = firstName;
    }

    public float getSpeed() {
        return speed;
    }

    public void setSpeed(float speed) {
        this.speed = speed;
    }

    public double getWeight() {
        return weight;
    }

    public void setWeight(double weight) {
        this.weight = weight;
    }

    public boolean isGender() {
        return gender;
    }

    public void setGender(boolean gender) {
        this.gender = gender;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public char[] getArray() {
        return array;
    }

    public void setArray(char[] array) {
        this.array = array;
    }
}

step 4:Java层MainActivity方法调用。

public class MainActivity extends AppCompatActivity {

    /**
     * 加载native库
     */
    static {
        System.loadLibrary("native-lib");
        System.loadLibrary("Hero");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        TextView tv = findViewById(R.id.sample_text);
        tv.setText(JSON.toJSONString(getFlash()));
    }


    public native String stringFromJNI();
    /**
     * 声明native方法
     * @return
     */
    public native Flash getFlash();
}

step 5:结果展示。

 

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值