一、前言:之前用eclipse开发ndk的时候大家是不是很痛苦,要做的事情很多:
//NDK开发流程:
1、在java代码中 声明本地方法(native)
2、通过javah工具完成jni样式的头文件(.h文件)的生成
3、在工程中 创建jni目录,在jni目录中编写 与java本地方法对应的C方法
jstring Java_包名_类名_方法名(){...}
4、编写Android.mk文件,来指定如何编译C代码
5、通过ndk-build工具来完成交叉编译 ,生成Anroid 中可以调用的2进制文件(链接库文件)
6、在Java代码中引用System.loadLibrary("hello-jni");
这个过程是非常的繁琐,运行ndk-build命令还需要装cgwin
但是现在Android Studio集成了ndk开发环境(ndk如何配置就不说了),我们只需要走这么几步就可以了:
二、Android Studio进行ndk开发
1、创建工程的时候需要勾上支持ndk开发
2、默认选择支持标准c++就可以了
C++ Standard:使用下拉列表选择使用哪种 C++ 标准。选择 Toolchain Default 会使用默认的 CMake 设置。
Exceptions Support:如果希望启用对 C++ 异常处理的支持,请选中此复选框。如果启用此复选框,Android Studio 会将 -fexceptions 标 志添加到模块级 build.gradle文件的 cppFlags中,Gradle 会将其传递到 CMake。
Runtime Type Information Support:如果希望支持 RTTI,请选中此复选框。如果启用此复选框,Android Studio 会将 -frtti 标志添加到模 块级 build.gradle文件的 cppFlags中,Gradle 会将其传递到 CMake。
3、创建好的工程
创建好的工程多了cpp目录,这是写c++的包,还多了CMakeLists.txt,这是编译代码,makefile都帮我们写好了,我们用的时候只需要修改里面的代码即可:
看一下build.gradle:
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.jni.jnidemo"
minSdkVersion 26
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
// 默认是 "cppFlags" "" ,如果要修改 Customize C++ Support 部分,可在这里加入cppFlags "-frtti -fexceptions"
cppFlags ""
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
// 指定c++编译代码的路径
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
}
三、总结
进行ndk开发要掌握的步骤:
1、在cpp包下创建自己的.cpp或者.c文件,编写自己的c语言程序
2、在CMakeLists.txt中添加add_library,可以生成多个library,所以add_library可以自己在后面加
在CMakeLists.txt中添加target_link_libraries,它也是一样,可以在后面自己加,不过这个不是必须的
3、在界面中引用一个库:
static {
System.loadLibrary("native-lib");
}
4、把用c/c++写的方法用native来声明:
public native String stringFromJNI();
5、经过以上步骤就可以像普通的方法一样来调用了
四、注意
1、在Activity或者fragment里面新加的native方法如果.cpp文件里面没有就会报错,这时候只需要在native方法上Alt + Enter就会自动在cpp文件里面生成
2、不同厂商的 Android 手机支持的 CPU 架构不同,我们可以这样来限制我们支持的架构
defaultConfig {
applicationId "com.jni.jnidemo"
minSdkVersion 26
targetSdkVersion 28
versionCode 1
versionName "1.0"
externalNativeBuild {
cmake {
cppFlags ""
}
}
ndk {
abiFilters 'armeabi'//,'armeabi-v7a','arm64-v8a','x86','x86_64','mips','mips64'
}
}
3、常用工具类:把Java字符串转化成c语言字符串
// 把Java字符串转化为C语言字符串
char* Jstring2CStr(JNIEnv* env, jstring jstr)
{
char* rtn = NULL;
jclass clsstring = (*env)->FindClass(env,"java/lang/String");
jstring strencode = (*env)->NewStringUTF(env,"GB2312");
jmethodID mid = (*env)->GetMethodID(env,clsstring, "getBytes", "(Ljava/lang/String;)[B");
jbyteArray barr= (jbyteArray)(*env)->CallObjectMethod(env,jstr,mid,strencode); // String .getByte("GB2312");
jsize alen = (*env)->GetArrayLength(env,barr);
jbyte* ba = (*env)->GetByteArrayElements(env,barr,JNI_FALSE);
if(alen > 0)
{
rtn = (char*)malloc(alen+1); //"\0"
memcpy(rtn,ba,alen);
rtn[alen]=0;
}
(*env)->ReleaseByteArrayElements(env,barr,ba,0);
return rtn;
}
4、打log在.c或者.cpp文件的最上面宏定义LOGD, 然后就可以用LOGD("I am log")来打印了
#define LOG_TAG "dongjie" #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)