JNI学习-在现有工程进行JNI开发

我的环境:

Mac+AndroidStudio3.2.1
GradleVersion 4.6
com.android.tools.build:gradle:3.2.1
compileSdkVersion 28
buildToolsVersion 28.0.3

配置

我是在现有工程下进行JNI开发,并没有进行过多的配置支持,可能是一开始就已经添加了NDK支持(Plugin中的Android Ndk Support),直接就添加cpp文件。我没有采用终端命令去编译出class文件、头文件的办法,直接手写cpp文件,具体步骤如下:

一、创建与cpp文件桥接的java类

我的包名是com.demo,我在demo下新建一个jni文件夹,在该文件夹下新建类JNI,具体路径就是com.demo.jni.JNI,这个路径后面需要使用到。

public class JNI {
    static {
        System.loadLibrary("jni_demo");//加载桥接的cpp文件名
    }

    public native int getInt(int i);//cpp中对应的方法
}

写完后是红线提示错误的,因为没找到对应的cpp文件。

二、添加cpp文件

切换到Project视图模式,在src/main/下面新建一个cpp文件夹,文件里新建一个jni_demo.cpp。这里的文件名与System.loadLibrary("jni_demo");中的文件名一直。
这里我只试了.cpp文件,.c文件应该是一样的操作,就语法不同。

JNI学习-在现有工程进行JNI开发_第1张图片

cpp文件代码如下:

//
// Created by Leon on 2019/5/7.
//
#include 

extern "C"

JNIEXPORT jint JNICALL

Java_com_demo_jni_JNI_getInt(JNIEnv *env, jobject jobj,jint i) {

    return i+333;

}

这是一个简单的有输入参数和返回参数的方法,就是把输入的参数加上333再返回。这里的方法名必须按一定规则来写,

JNIEXPORT JNICALL是固定关键字
第一个jint是返回int值,
主体方法名Java_com_demo_jni_JNI_getInt中的com_demo_jni_JNI对应上面的桥接类路径com.demo.jni.JNI;getInt是与桥接类中的方法名一致。
JNIEnv *env, jobject jobj,是固定参数,保留不变
jint i就是桥接类中的实际入参了

三、手动添加CMakeLists.txt

在app路径下添加CMakeLists.txt,其中绝大多数都是注释,有效内容不多。其中jni_demo是要与上面你自己创建的cpp文件一直。具体内容如下

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html
# Sets the minimum version of CMake required to build the native library.
cmake_minimum_required(VERSION 3.4.1)
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
add_library( # Sets the name of the library.
        jni_demo
        # Sets the library as a shared library.
        SHARED
        # Provides a relative path to your source file(s).
        src/main/cpp/jni_demo.cpp)
# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
find_library( # Sets the name of the path variable.
        log-lib
        # Specifies the name of the NDK library that
        # you want CMake to locate.
        log)
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
        jni_demo
        # Links the target library to the log library
        # included in the NDK.
        ${log-lib})

四、设置Gradle支持

在Gradle添加对CMake的支持

android {

    defaultConfig {

        ndk {
            abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
        }

        externalNativeBuild {
            cmake {
                cppFlags ""
            }
        }
    }

    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
        }
    }
}

同步,rebuild project,没报错就可以调用了。

五、验证桥接成功

rebuild成功后,会在指定位置生成so文件的


JNI学习-在现有工程进行JNI开发_第2张图片

生成后就可以调用了。
比如在MainActivity里添加如下代码

        JNI jni =new JNI();
        Log.i(TAG,"jni getInt is : "+ jni.getInt(111));

成功打印出444。

另一种方法、用终端命令来编译生成.cpp文件

具体可参见 android JNI 开发之第一个 JNI 实例
第1步:在Java中先声明一个native方法
第2步:编译Java源文件javac得到.class文件
第3步:通过javah -jni命令导出JNI的.h头文件
第4步:使用Java需要交互的本地代码,实现在Java中声明的Native方法(如果Java需要与C++交互,那么就用C++实现Java的Native方法。)
第5步:将本地代码编译成动态库(Windows系统下是.dll文件,如果是Linux系统下是.so文件,如果是Mac系统下是.jnilib)
第6步:通过Java命令执行Java程序,最终实现Java调用本地代码。

参考
Android Studio生成so文件的几种方式(主要参照第三个方法)
Android JNI(一)——NDK与JNI基础

六、 动态注册方法

上面采用的是静态注册,靠java桥接类的加载、声明空方法,并保证cpp中有指定规则的方法体来实现桥接。
而动态注册就不需要按指定规则命名函数,在jni侧进行方法注册绑定,详见 https://blog.csdn.net/cloverjf/article/details/78878814

你可能感兴趣的:(JNI学习-在现有工程进行JNI开发)