在Android Studio 2.2 之后,工具中增加了CMake的支持,也就是说,Android Studio 2.2 之后有两种选择来编译C/C++代码,一个是上篇ndk-build + Android.mk + Application.mk组合编译,另一个是CMake + CMakeList.txt组合构建项目
1、配置环境
方式一、在工程创建的时候添加
使用AS3.0新建一个NDKDemo工程,注意勾选Include C++ support
创建成功后,可以看到和普通的Android有以下4个不同:
app/build.gradle下多了如下配置:
android {
...
defaultConfig {
...
externalNativeBuild {
cmake {
//主要填写CMake的命令参数
cppFlags ""
}
}
...
}
...
externalNativeBuild {
cmake {
path "CMakeLists.txt"// cmake配置文件路径
}
}
}
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).
# 资源文件,可以多个
# 资源路径时相对路径,相对于本CMakeList.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源文件写好了,根据函数名可以知道,函数的native申明在MainActivity中
#include
#include
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_jin_ende_1test_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
再看看MainActivity文件,与以前的jni调用方式完全一样
public class MainActivity extends AppCompatActivity {
// Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("native-lib");//加载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());//jni调用
}
/**
* A native method that is implemented by the 'native-lib' native library,
* which is packaged with this application.
*/
public native String stringFromJNI();//native申明
}
现在我们在MainActivity中再申明一个native方法,光标放在函数名上,然后alt + enter
选择创建jni方法的选项,确认后会发现再native-lib.cpp中发现对应的本地代码框架已经写好
extern "C"
JNIEXPORT jstring JNICALL
Java_com_example_jin_ende_1test_MainActivity_getStringFromJNI(JNIEnv *env, jobject instance) {
// TODO
return env->NewStringUTF(returnValue);
}
方式二:在项目开发过程中添加
有时候,我们的项目已经在进行中或者维护中,突然需要使用jni调用咋办?Android Studio也提供了相应的方法。
首先在app/src/main/jni下创建native-lib.c文件:
然后在app目录下新建一个CMakeLists.txt:
接着配置模块支持jni调用,项目模块右键:
点击ok后,系统开始编译,编译成功后build.gradle发生如下变化:
然后我们新建一个java调用本地代码的工具类JNIUtils.class,加载库,申明本地方法,选中方法alt+enter
发现自动在native-lib.c中为我们创建了本地代码的框架:
我们完善native-lib.c代码内容如下:
#include
JNIEXPORT jstring JNICALL
Java_com_example_jin_jnidemo2_JNIUtils_getStringFromJNI(JNIEnv *env, jobject instance) {
return (*env)->NewStringUTF(env, "Hello from C++");
}
上述两种方式中,实现JNI方法的区别在于,一个是用C++来实现,一个是用C来实现,它们的区别主要集中在对 env 的操作上,其他都是类似的,如下所示:
C++: env->NewStringUTF("Hello from C++");
C: (*env)->NewStringUTF(env,"Hello from C++");