Android NDK提供的组件:
Android NDK并不是一个单独的工具, 他是一个包含API、交叉编译器、链接程序、调试器、构建工具、文档和实例应用程序的综合工具集
主要的组件:
ARM、x86和MIPS交叉编译器
构建系统
Java原生接口头文件
C库
Math库
POSIX线程
最小的C++库
ZLib压缩库
动态链接库
Android日志库
Android像素缓冲区库
Android原生应用的APIS
OpenGL ES 3D图形库
OpenSL ES 原生音频库
OpenMAX AL 最小支持
Android NDK的结构:
ndk-build:该shell脚本是AndroidNDK构建系统的起始点
ndk-gdb:该shell脚本允许使用GUN调试器调试原生组件
ndk-stack:该shell脚本可以帮助分析原生组件崩溃时的堆栈追踪
build:该目录包括了Android NDK构建系统的所有模块
platforms:该目录包含了支持不同Android目标版本的头尾件和库文件,NDK构建系统会根据具体的Android版本自动的引用这些文档
samples:该目录包含了示例程序
sources:该目录包含了可供开发人员导入到现有的Android NDK项目中的一些共享模块
toolchains:该目录包含目前Android NDK支持的不同目标机体系结构的交叉编译器,目前支持ARM,X86, MIPS
构建系统(老方法)
构建系统是基于GUN Make的,该构件系统主要目的是使开发人员使用短的构建文档来描述Android应用 该构建系统处理了处理工具链,指定平台,CPU, ABI等细节 该构建系统是由多种GUN Makefile片段构成的 该系统的两个依赖文件:Android.mk , Application.mk
Android.mk文件:
Android.mk文件是一个向Android NDK构建系统描述NDK项目的GUN Makefile片段,是一个NDK项目的必备组件,在JNI目录中:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE:= native-lib
LOCAL_SRC_FILES := native-lib.cpp
LOCAL_LDLIBS := -fpic -fPIE -pie
include $(BUILD_SHARED_LIBRARY)
命名规范: 变量名要大写 Android.mk文档必须要以LOCAL_PATH开头,使用这个变量来定位源文件
Application.mk文件:
Application.mk文件是Android NDK构建系统可选构建文件,他的目的是描述应用程序需要哪些模块,他也定义所有模块的通用变量
APP_STL := c++_static
APP_GNUSTL_FORCE_CPP_FEATURES := exceptions rtti
APP_ABI := armeabi-v7a
APP_STL:默认情况下NDK构建系统使用的最小的STL运行库 APP_GNUSTL_FORCE_CPP_FEATURES :该变量表明所有模块都依赖具体的C++特性 APP_ABI:默认情况下,NDK构建你系统为armeabi ABI生成二进制文件
使用Android studio创建NDK项目
配置流程请参照上篇博客
使用默认的Cmake编译:
使用ndk-build编译:
首先在JNI目录下创建 Android.mk和Application.mk
Android.mk:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE:= native-lib
LOCAL_SRC_FILES := native-lib.cpp
LOCAL_LDLIBS := -fpic -fPIE -pie
include $(BUILD_SHARED_LIBRARY)
Application.mk:
APP_STL := c++_static
APP_GNUSTL_FORCE_CPP_FEATURES := exceptions rtti
APP_ABI := armeabi-v7a
修改app下的build.gradle文件:
externalNativeBuild {
// cmake {
// cppFlags ""
// }
ndk {
moduleName "native-lib"
abiFilters "armeabi-v7a"
}
}
externalNativeBuild {
// cmake {
// path "src/main/cpp/CMakeLists.txt"
// version "3.10.2"
// }
ndkBuild {
path "src/main/jni/Android.mk"
}
}
编译执行即可
Java调用C方法:
首先在MainActivity中可以看到一个public native String stringFromJNI();方法,该方法是MainActivity.java 关联 so 库中方法, 它会默认去查找一个以Java包名+方法名的方法 就会去查找Java_com_wjx_android_ndksummary_MainActivity_stringFromJNI方法,而这个方法我们去native-lib.cpp文件中可以看到
C调用Java方法:
首先在MainActivity中声明以下方法:
String a = "w";
String b = "j";
String c = "x";
public String addStr(String a, String b, String c){
return a + b + c;
}
public native String myAddStringFrom();
在JNI中声明:
/*
* Class: com_wjx_android_ndksummary_MainActivity
* Method: myAddStringFrom
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_wjx_android_ndksummary_MainActivity_myAddStringFrom
(JNIEnv *, jobject);
在native-lib中加入:
extern "C"
JNIEXPORT jstring JNICALL
Java_com_wjx_android_ndksummary_MainActivity_myAddStringFrom(JNIEnv *env, jobject instance) {
// TODO
jclass clazz = (env)->GetObjectClass(instance);
//获取java中a字段的Id
jfieldID s_a_id= (env)->GetFieldID(clazz, "a", "java/lang/String");
//获取a字段对应的值
jobject s_a = (env)->GetObjectField(instance, s_a_id);
//获取java中b字段的Id
jfieldID s_b_id= (env)->GetFieldID(clazz, "b", "java/lang/String");
//获取b字段对应的值
jobject s_b = (env)->GetObjectField(instance, s_b_id);
//获取java中c字段的Id
jfieldID s_c_id= (env)->GetFieldID(clazz, "c", "java/lang/String");
//获取c字段对应的值
jobject s_c = (env)->GetObjectField(instance, s_c_id);
//获取java中字符串相加的方法的ID, 后面的部分为参数的个数和返回类型
jmethodID jmethodID1 = (env)->GetMethodID(clazz, "addStr",
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
//将返回结果接受并进行强制转换
jstring result = static_cast<jstring>((env)->CallObjectMethod(instance, jmethodID1, s_a, s_b, s_c));
return result;
}