【记录】需要完成一些NDK的简单开发工作,平时不常接触这部分知识,记录下CMAKE的简单使用和JNI的基础
1. 配置
AS的2.2及以上版本可以使用CMAKE,相对于之前使用ndk-build,要简单很多。
1)下载NDK,设置gradle
可以通过AS下载CMake,LLDB以及NDK
NDK也可以自己从官网下载,然后在local.properties文件中设置ndk的路径,例如
ndk.dir=D\:\\ndk\\android-ndk-r16b
2)创建新项目
在创建项目的向导中,我们可以选择支持c++的选项。在后面的编译中就会,项目会生成对应的CMakeLists.txt配置模块gradle文件并生成一个示例的native-lib.cpp文件和对应的MainActivity(其中声明了native方法)。
//模块的gradle文件
android {
compileSdkVersion 27
defaultConfig {
applicationId "com.hik.face.sdk"
minSdkVersion 19
targetSdkVersion 27
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
//cmake相关
externalNativeBuild {
cmake {
cppFlags ""
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
//cmake相关
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
}
借用下别人的图,生成的native-lib.cpp
//MainActivity.java
// Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("native-lib");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Example of a call to a native method
TextView tv = (TextView) findViewById(R.id.sample_text);
tv.setText(stringFromJNI());
}
/**
* A native method that is implemented by the 'native-lib' native library,
* which is packaged with this application.
*/
public native String stringFromJNI();
到这里,就可以跑起来一个简单的demo了。但是实际开发中,库的名字,文件名等内容,都需要修改,或者会创建新的文件,生成新的库。
2. DEMO
默认生成的cmakelists.txt文件中的内容
# 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.
# 配置so库信息
add_library( # Sets the name of the library.
# 生成的so库名称,此处生成的so文件名称是libnative-lib.so
native-lib
# Sets the library as a shared library.
# STATIC:静态库,是目标文件的归档文件,在链接其它目标的时候使用
# SHARED:动态库,会被动态链接,在运行时被加载
# MODULE:模块库,是不会被链接到其它目标中的插件,但是可能会在运行时使用dlopen-系列的函数动态链接
SHARED
# Provides a relative path to your source file(s).
# 资源文件,可以多个,
# 资源路径是相对路径,相对于本CMakeLists.txt所在目录
src/main/cpp/native-lib.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.
# android系统每个类型的库会存放一个特定的位置,而log库存放在log-lib中
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
# android系统在c环境下打log到logcat的库
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.
# 目标库
native-lib
# Links the target library to the log library
# included in the NDK.
# 依赖于
${log-lib} )
如果我们要创建新的文件,可以参照上面的再配置下(这里把native-lib.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.
# 新的库名字叫detect
detect
# Sets the library as a shared library.
# 还是共享库
SHARED
# Provides a relative path to your source file(s).
# 关联路径下的detect.cpp文件
src/main/cpp/detect.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.
# 这里没变,还是使用log-lib作为log的名称
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.
# 为了后面detect库打日志,这里也关联上
target_link_libraries( # Specifies the target library.
detect
# Links the target library to the log library
# included in the NDK.
${log-lib} )
创建Detect.java文件,生命native方法
public class Detect {
static {
System.loadLibrary("detect");
}
public native String getStrContent();
}
然后在cpp下创建detect.cpp文件。这里如果通过alt+enter提示的方式生成对应的代码,as会在/main/jni下面生成一个.c文件,那么就和上面修改的配置不相符了。这里可以选择手动生成文件写代码,或者修改上面的cmake配置后,通过alt+enter的方式生成方法。
#include <jni.h>
#include <string>
extern "C" JNIEXPORT jstring
JNICALL
//com_xxx_xxx_xxx是包名,Detect是Java类名,getStrContent是方法名
Java_com_xxx_xxx_xxx_Detect_getStrContent(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from myc++";
return env->NewStringUTF(hello.c_str());
}
最后,稍微修改下MainActivity就可以运行了
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Detect detector = new Detect();
// Example of a call to a native method
TextView tv = (TextView) findViewById(R.id.sample_text);
tv.setText(detector.getStrContent());
}
这只是非常简单的demo,不能满足真正的需求,边学习便补充。
参考
https://blog.csdn.net/quwei3930921/article/details/78820991
https://developer.android.google.cn/studio/projects/add-native-code