????????很多开发者在开发过程中经常遇到有人问你JNI或者NDK的问题,而且JNI和NDK是非JAVA语言,需要C++来完成。C++在处理多媒体文件具有一定的有事,所以Java也提供了一个方法就是对NDK的支持。
很多人可能还在迷茫如何去编译如何去调用,下面我将讲解一下如何如入门
如果我们通过AndroidStudio来开发,那么只要设置了ndk.dirs=""即可。
1.Java环境:正常的classpath和javahome的配置
2.ndk:在androidstudio中配置好了ndk环境
上面是开发环境的配置,接下来就是关于编译的配置
在defaultConfig节点新增:
externalNativeBuild {
cmake {
cppFlags ""
}
}
ndk {
abiFilters 'x86_64', 'armeabi-v7a', 'arm64-v8a'
}
主要配置编译环境和nkd的输出
我们采用的是cmake进行编译了,所以在android{}节点下配置编译即可
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
version "3.22.1"
}
}
path:需要执行的cmake地址,正常在main下面cpp文件下,用来编译链接cpp文件的
上面讲解了编译配置,那么我们开始做编译类的工作了。正常我们会在main下新建一个cpp文件夹,用来专门放cpp文件和cmake编译脚本的。
随便在包下新增一个类作为测试:
public class TestJni {
static {
System.loadLibrary("test_jni");
}
public native String getMessage();
}
Java和kotlin有所区别,kotlin的native不是native,是external。
找到目标文件所在的根目录,
jni> javac .\TestJni.java,执行完会生成一个class文件
通过javah -jni 类,这个命令是对刚才编译完的class导出为jni文件。这个命令要回到src节点下
在src节点下,在终端通过命令来编译:javah -jni packagename.className
一定要输入完整的包名和类名,如果Test在包com.jni.test下,那么就是javah -jni com.jni.test.Test
会在src下面生成一个.h的c文件,这个文件就是我们要用到的jni信息文件。这个文件名一般是就是包名和类型的组合
通过上面我们基本完成了jni的前期准备,接下来就是cpp文件的创建,jni是通过c++来创建的,刚才的c文件其实是一个没有函数体的函数声明,我们需要自己通过c++文件来实现函数体
正常编译一个cpp需要至少一个cmake和cpp。h文件可以有可以没有,如果你是通过jni生成的,需要导入。
#include "com_love_lovestudy_testdemo_jni_TestJni.h"
JNIEXPORT jstring JNICALL Java_com_love_lovestudy_testdemo_jni_TestJni_getMessage
(JNIEnv* env, jobject cls){
const char a[]="ssssss";
return env->NewStringUTF(a);
}
我在test-jni中实现了h文件的函数体,返回了一个字符串。
我们是直接通过cmake编译,不需要mk文件参与,所以所有的配置信息都在这里面,配置的核心就是:
#so库的输出路径
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY
${CMAKE_CURRENT_SOURCE_DIR}/../jniLibs/${ANDROID_ABI})
我们配置了输出在cpp文件统计目录的jnilibs文件夹中
#1. 添加自己的so库test-lib,设置一个名字,输出就是这个名字
add_library( # Sets the name of the library.
test_jni
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
test_jni.cpp)
test_jni就是文件名,这个文件名和连接需要用到,test_jni.cpp是我们需要编译的目标cpp
参考2,其实这两个就是导入和设置一个文件名,输出的so文件就是这个名字
target_link_libraries( # Specifies the target library.
test_jni
# Links the target library to the log library
# included in the NDK.
${log-lib})
连接的test_jni就是上面3的文件连接别名,这两个一定要一致,否则无法生成。
通过这个四部我们基本能生成自己的so文件了,一个cmake只能链接一个cpp文件,只能生成一个so文件,所以cmake与cpp是1v1的关系,后面会讲解多个cmake管理。
#so库的输出路径
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY
${CMAKE_CURRENT_SOURCE_DIR}/../jniLibs/${ANDROID_ABI})
#版本
cmake_minimum_required(VERSION 3.4.1)
#1. 添加自己的so库test-lib,设置一个名字,输出就是这个名字
add_library( # Sets the name of the library.
test_jni
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
test_jni.cpp)
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 )
#add 库的名字和target的要一致,因为target链接add的文件
target_link_libraries( # Specifies the target library.
test_jni
# Links the target library to the log library
# included in the NDK.
${log-lib})
生成so文件需要把cmakelist插入build.gradle文件。
通过build->make project或者rebuild project。执行完会生成如下
生成的so文件名:一般都是lib+你自己定义的名字
static {
System.loadLibrary("test_jni");
}
注意:我们生成的so文件名为libtest_jni.so,但是我们不需要lib这个前缀,只需要把我们在cmake中配置的名字加载进去即可。
testJni=new TestJni();
textView.setText(testJni.getMessage());
????????通过以上步骤,我们已完成了JNI/NDK的搭建与配置完毕,大家可以很清楚的看到so文件的生成整个过程。已基本掌握的JNI的编译与生成整个流程,包括问题的处理基本都有。可以很直观的定义自己的JNI文件