美文网首页
Android端学习JNI入门篇(附demo)

Android端学习JNI入门篇(附demo)

作者: 30eb7fe7eef0 | 来源:发表于2020-12-21 10:19 被阅读0次

这篇内容适合哪些人:

1、Android研发有一定的安卓基础并且想要学习JNI编程的人员

文章最后附Demo

工程目录结构:

image.png

本章内容概要
1、基于CMake ,NDK
2、配置CMake
3、定义JNI 接口类(用于交互jni)
4、编写JNI层的被调用方法
5、JNI 生成 so 库
6、编译运行

一、CMake 下载:

image.png

二、CMake配置

1、在build.gradle 文件下指定CMakeLists.txt 的路径

    //指定你的CMakeLists文件的位置
    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
        }
    }

2、指定生成的so库类型(按需配置)


        externalNativeBuild {
            cmake {
                cppFlags ""
                abiFilters 'armeabi-v7a'
            }
        }

三、定义JNI 接口类(用于交互jni)

jni接口类定义

四、编写JNI层的被调用方法

目标:实现一个简单的jni函数sum(int a, int b),返回a+b的结果。一个稍微复杂点的jni函数twoSum(int nums[], int target),实现的是leetcode上的一个题目TwoSum,内容是给定数组及目标数字,返回符合目标数字的2个数的下标(数组类型)

1、首先建立一个demo.h
该文件作为c++的头文件,声明要实现的函数

#ifndef JNIDEMO_DEMO_H
#define JNIDEMO_DEMO_H


#endif //JNIDEMO_DEMO_H

class Demo{
public:
    Demo();

    int sum(int a,int b);

    int *twoSum(int nums[],int target);
};

2、建立demo.cpp文件实现算法。
该文件实现头文件声明的函数。

#include <cstring>
#include "demo.h"

Demo::Demo() {
}

int Demo::sum(int a, int b) {
    return a + b;
}

int* Demo::twoSum(int nums[], int target) {
    int length = sizeof(nums);
    if (length < 2){
        return nullptr;
    }
    int *result = nullptr;
    for (int i = 0; i < length; i++){
        for (int j = i + 1; j < length; j++){
            if (nums[i] + nums[j] == target){
                result = new int[2];
                result[0] = i;
                result[1] = j;
                break;
            }
        }
    }
    return result;
}

3、创建demo-lib.cpp文件
这个文件里面放的是我们的jni代码,暂时还不用写先,因为现在不想手动写jni函数名,至于为什么叫demo-lib(.cpp文件名加-lib),一句话,官方推荐命名格式以及样例也是这样命名的。

4、修改CMakeLists.txt
跟之前native-lib文件一样,新加的库使用add_library指令。我们直接复制native-lib的add_library添加到下面,将native-lib改成我们的demo-lib.cpp(即第3点创建的jni代码文件)。
a、先添加库,用add_library(...)


添加自定义库

b、将我们新增的库依赖进去


增加依赖

c、配置一个so库输出的路径
在CMakeLists.txt内

#设置生成的so动态库最后输出的路径
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/libs/${ANDROID_ABI})

至此,CMakeLists.txt的修改就完成了,下面我们来编写jni层的代码。
在demo.cpp文件内编写被调用的方法:
注意点:
1、jni方法的命名
2、c++中的twoSum函数需要传递一个数组,而java的数组是不能直接作为参数传递给c++函数的,因此需要Jni作一层转换
最终实现:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
#include <cstring>
#include <malloc.h>
#include "demo.cpp"
/* Header for class com_albert_demo_util_NativeMethodSum */

#ifndef _Included_com_albert_demo_util_NativeMethodSum
#define _Included_com_albert_demo_util_NativeMethodSum
#ifdef __cplusplus
extern "C" {
#endif


/****
 *
 * 将Java数组转化成C++ 指针数组
 */

jint * getIntArrayFromJava(JNIEnv *env,jintArray j_array){
    jint *c_array;
    jint arr_len;
    arr_len = (*env).GetArrayLength(j_array);
    c_array = (jint*)malloc(sizeof(jint) * arr_len);
    //初始化
    memset(c_array,0,sizeof(jint)*arr_len);
    //获取数组
    c_array = (*env).GetIntArrayElements(j_array,NULL);
    return c_array;
}



/*
 * Class:     com_albert_demo_util_NativeMethodSum
 * Method:    sum
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_albert_demo_util_NativeMethodSum_sum
  (JNIEnv *, jclass, jint a, jint b){
  Demo demo = Demo();
  jint result = demo.sum(a,b);
  return result;
}

/*
 * Class:     com_albert_demo_util_NativeMethodSum
 * Method:    twoSum
 * Signature: ([II)I
 */
JNIEXPORT jintArray JNICALL Java_com_albert_demo_util_NativeMethodSum_twoSum
  (JNIEnv *env, jobject, jintArray nums, jint target){
    Demo demo = Demo();
    jint *result = demo.twoSum(getIntArrayFromJava(env,nums),target);
    if (result == nullptr){
        return nullptr;
    }
    // C++返回的数组为指针形式,也不能直接返回给java,所以通过Jni复制一个jintArray数组返回给java
    jintArray array = (*env).NewIntArray(2);
    (*env).SetIntArrayRegion(array,0,2,result);
    return array;
}

#ifdef __cplusplus
}
#endif
#endif

五、JNI 生成 so 库

工程clean、build 即可生成so库

六、编译运行

编译运行方法使用

完整Demo点此下载

本文参考:
疯一样的雨博主的Android Jni开发-基础配置篇(CMake)
疯一样的雨博主的Android Jni开发-实战篇(CMake)

相关文章

网友评论

      本文标题:Android端学习JNI入门篇(附demo)

      本文链接:https://www.haomeiwen.com/subject/htnzgktx.html