JNI概述
JNI,全称为Java Native Interface,即Java本地接口,通过使用 Java本地接口书写程序,可以确保代码在不同的平台上方便移植。
使用Android Studio新建一个项目,选择Native C++
关于module的build.gradle
android {
//省略了其他代码
defaultConfig {
externalNativeBuild {
cmake {
//值为""是因为创建项目选的ToolChain Default
cppFlags ""
}
}
}
externalNativeBuild {
cmake {
//外部构建脚本路径
path "src/main/cpp/CMakeLists.txt"
version "3.10.2"
}
}
}
MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
sample_text.text = stringFromJNI()
}
external fun stringFromJNI(): String
companion object {
init {
System.loadLibrary("native-lib")
}
}
}
我新建的kotlin项目,如果是java项目的话,就不需要使用伴生对象(companion 关键字修饰的对象)和external关键字。在java中使用static和native关键字:
static {
System.loadLibrary("native-lib");
}
public native String stringFromJNI();
native-lib.cpp
#include <jni.h>
#include <string>
extern "C" JNIEXPORT jstring JNICALL
Java_com_phz_myapplication_MainActivity_stringFromJNI(
JNIEnv* env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
分析:“Java_com_phz_myapplication_MainActivity_stringFromJNI”字段是不是很熟。
com.phz.myapplication是包名,MainActivity是当前活动,stringFromJNI是方法名。还有返回了String,都跟Activity对应上了。所以除了so文件,cpp文件也可以直接加载,然后使用他的方法。
CMakeLists.txt
以cpp目录下的CMakeLists.txt为例(去掉了注释)
cmake_minimum_required(VERSION 3.4.1)
add_library( native-lib SHARED native-lib.cpp )
find_library( log-lib log )
target_link_libraries( native-lib ${log-lib} )
关于cmake命令,可以参考文档:cmake-commands
add_library(<name> [STATIC | SHARED | MODULE]
[EXCLUDE_FROM_ALL]
[source1] [source2 ...])
target_link_libraries(<target> ... <item>... ...)
整个调用流程
- Gradle调用外部构建脚本CMklist.txt。
- CMake按照脚本中的命令将C++源文件native-lib.cpp编译成native-lib.so动态库,并把它编译到APK中。
- 运行时首先加载native-lib.so,然后调用so中的stringFromJNI方法,最后把这个方法返回的值显示在TextView上。
关于build之后编译出的so路径
app/build/intermediates/cmake
CMakeLists.txt添加多个依赖和单依赖
关于路径
c语言相关资源一般都是放在cpp文件夹下。记得之前有在module的build.gradle设置cmake的path。(path “src/main/cpp/CMakeLists.txt”)我们先新建一个文件夹haizhuo,添加haizhuo-lib.cpp文件。
之后,我们可以通过修改CMakeLists.txt把haizhuo-lib.cpp加进依赖,有2种方式,可以选择编译成一个库文件还是二个库文件。
1. 把haizhuo-lib.cpp同native-lib.cpp一起编译到到native-lib包里,只需要修改:
add_library(native-lib HARED native-lib.cpp haizhuo/haizhuo-lib.cpp)
2. 编译成2个库文件,不仅需要修改CMakeLists.txt,还需要添加System.loadLibrary(String libname)
cmake_minimum_required(VERSION 3.4.1)
add_library(native-lib SHARED native-lib.cpp)
add_library(haizhuo-lib SHARED haizhuo/haizhuo.cpp)
find_library(log-lib log)
target_link_libraries(native-lib ${log-lib} )
target_link_libraries(haizhuo-lib ${log-lib} )
companion object {
init {
System.loadLibrary("native-lib")
System.loadLibrary("haizhuo-lib")
}
}
补充:关于能添加的源文件类型
//关于源文件,下面的都能加进依赖
.c .C .c++ .cc .cpp .cxx .m .M .mm .h .hh .h++ .hm .hpp .hxx .in .txx