我的环境:
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文件应该是一样的操作,就语法不同。
cpp文件代码如下:
//
// Created by Leon on 2019/5/7.
//
#include <jni.h>
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文件的
生成后就可以调用了。
比如在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











网友评论