做安卓半年了,用的都是java,目前老大分配了一个任务,在现有项目上添加图片的滤镜功能,使用滤镜一般计算量比较大,需要用到NDK,也就是C相关的知识,虽然之前学过C/C++,但还没用到过项目中,尤其还要用到安卓中,这一篇算是为NDK学习开个头。
如何使得现有项目支持NDK呢?
首先就是要下载NDK相关的工具链,然后加入C文件。
1、首先我们在MainActivity中假如一个getNdkText
的native方法,并且在onCreate
方法中调用
public native String getNdkText();
然后就要在c文件中实现这个方法了
2、工程目录切到project,在app模块下新建一个cpp文件夹,用于放置C文件
3、然后在cpp文件夹下面新建自己的c文件,命名为hello.cpp
hello.cpp内容如下:
#include <jni.h>
#include <string>
extern "C" JNIEXPORT jstring JNICALL
Java_cn_hzw_ndk_1learn_MainActivity_getNdkText(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
在这里就实现了getNdkText方法了,但是为什么名称发生了改变?这是因为要使得MainActivity中的getNdkText方法要唯一的对应到上面c中的函数,具体的对应方法就是Java+类包名+方法名,其中包名不是以.
分割的,而是下划线_
,另外如果原始包名中如果有下划线的话,那么就会把下划线转化成数字,我写的这个例子原始包名为cn.hzw.ndk_learn.MainActivity
一般来说可以使用代码提示自动生成c函数,但是在第一次加入时是没有提示的,需要手动写。
4、加入CMakeLists.txt文件,在模块目录下面,这里就是在app目录下加入这个文件
cmake_minimum_required(VERSION 3.4.1)
add_library( # Sets the name of the library.设置库的名称
hello
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).包含需要编译的文件
src/main/cpp/hello.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 )
target_link_libraries( # Specifies the target library.
hello
# Links the target library to the log library
# included in the NDK.
${log-lib} )
5、在build.gradle文件中加入支持ndk编译的选项,在android的defaultConfig节区下面加入
externalNativeBuild {
cmake {
cppFlags ""
}
}
在android节区下面加入
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
6、加载so库,因为编译出来的so库是不会随JVM自动加入的,而是要我们手动加载,并且是在调用native方法之前加载,因此就在MainActivity最前面的static语句块中载入:
static {
System.loadLibrary("hello");
}
到此,就应该可以运行起来了。
最后解释一下jni函数的声明含义
extern "C" JNIEXPORT jstring JNICALL
extern “C”的含义是这个函数使用C编译器的方式去编译,因为C和C++在对函数编译时会采取不一样的方式,使用C编译器编译,得到最终的so库中的函数表中的名称就是源代码中的名称,但是因为C++支持重载,因此C++在链接函数的时候使用的是函数签名,最终so库中的名称就会和源代码中的不一样,那么外部在链接的时候,可能就会出现找不到的情况,因此使用这么一个字符串,使得C和C++可以使用同一套代码。
JNIEXPORT 和 JNICALL都是给编译器看的,前者和生成动态库有关,后者和调用约定有关系,因为在不同的平台函数参数的顺序可能会不一样,具体可参考https://blog.csdn.net/shulianghan/article/details/104072587
这篇文章。
jstring是c层对应的java层字符串的一个类型表示,具体后面再讲。
来源:CSDN
作者:whoami_I
链接:https://blog.csdn.net/whoami_I/article/details/104266578