前言涉及到一些算法或者底层驱动的时候,往往需要使用jni来开发。关于NDK和JNI如果还不了解,请查看我的另一篇博文《Android NDK与JNI的区别有何不同?》进行科普。 本篇博文主要是教学两种.so库的打包,稳文中有详细的图文指导,跟着一步步操作就能学会.so文件的打包,对于NDK开发学习请阅读我的《NDK开发系列》文章。 关于.so文件的生成有两种方式可以提供给大家参考,一种是CMake自动生成法,另一种是传统打包法。 1. 什么是.so库NDK为了方便使用,提供了一些脚本,使得更容易的编译C/C++代码,这个编译文件为.so文件,它就C/C++库,类似java库.jar文件一样。so是shared object的缩写,见名思义就是共享的对象,机器可以直接运行的二进制代码。大到操作系统,小到一个专用软件,都离不开.so,.so主要存在于Unix和Linux系统中。 在Android开发中它的生成是需要使用JNI将C/C++文件打包成so库的,当然在其他开发软件中,由其他工具将其打包成so库。 .so文件在程序运行时就会加载,所以想使用Java调用.so文件,必有某个Java类运行时load了native库,并通过JNI调用了它的方法。 2. cmake生成.so方案使用该种方案生成.so文件,需要先创建一个支持Cmake的 C++ Project,如果不会创建项目请阅读我的博文《Android Studio 4.0.+NDK项目开发详细教学》 1. 创建项目 2. 创建native函数 3. 测试JNI函数 public class MainActivity extends AppCompatActivity { 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 = findViewById(R.id.sample_text); tv.setText(new MyNdkTest().getData()); } } 运行结果可见,JNI函数已被成功调用 4. 获取.so文件 5. 生成多类型.so文件 android { ....... defaultConfig { ........... testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" externalNativeBuild { cmake { cppFlags "" } } ndk { // 设置支持的 SO 库构架,注意这里要根据你的实际情况来设置 abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64' } } externalNativeBuild { cmake { path "src/main/cpp/CMakeLists.txt" version "3.6.0" } } } 6 .so文件测试
7. 小结
OK,自动生成.so库的方法就讲到这了,Android Studio帮我们自动化做了很多东西,所以so easy。 下面讲讲传统的.so库生成方案。 3. 传统生成.so方案使用该种方案生成.so文件一定要先配置好NDK,如果不清楚如何配置NDK,请阅读一篇关于配置NDK的博文《Android Studio 4.0.+NDK项目开发详细教学》。其打包.so文件的基本流程如下所述 1. 在Java类中声明一个本地方法 public class NDKTest { private native int count(); } 2. 执行指令javah获得C声明的.h文件 javah -encoding utf-8 -d ../jni -jni com.xuanyuan.ndktest.NdKTest // javah:生成头文件指令 // -encoding utf-8:编码格式 utf-8 // -d ../jni:生成的文件放到与java目录同级的jni文件中,jni文件若不存在会自动创建 // -jni:当前目录下生成.h文件,当前目录是cd进入的目录,这里是\app\src\main\java // com.xuanyuan.ndktest.NdKTest:包名+类名 指命令后会在…\app\src\main\jni目录下生成一个com_xuanyuan_ndktest_NdKTest.h文件 /* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_xuanyuan_ndktest_NdKTest */ #ifndef _Included_com_xuanyuan_ndktest_NdKTest #define _Included_com_xuanyuan_ndktest_NdKTest #ifdef __cplusplus extern "C" { #endif /* * Class: com_xuanyuan_ndktest_NdKTest * Method: test * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_xuanyuan_ndktest_NdKTest_test (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif 另一种方式是使用External tools工具,使用其javah指令,该指令需要我们自行配置,后面会单独讲解。 3. 获得.c文件并实现本地方法 4. 创建Android.mk和Application.mk //Android.mk 参数 //设置工作目录,它用于在开发tree中查找源文件。宏my-dir由Build System提供,会返回Android.mk文件所在的目录 LOCAL_PATH := $(call my-dir) //CLEAR_VARS变量由Build System提供。指向一个指定的GNU Makefile,由它负责清理LOCAL_xxx类型文件,但不是清理LOCAL_PATH //所有的编译控制文件由同一个GNU Make解析和执行,其变量是全局的。所以清理后才能便面相互影响,这一操作必须有 include $(CLEAR_VARS) // LOCAL_MODULE模块必须定义,以表示Android.mk中的每一个模块,名字必须唯一且不包含空格 //Build System 会自动添加适当的前缀和后缀。例如,demo,要生成动态库,则生成libdemo.so。但请注意:如果模块名字被定义为libabd,则生成libabc.so。不再添加前缀。 LOCAL_MODULE := DEMO // 指定参与模块编译的C/C++源文件名。不必列出头文件,build System 会自动帮我们找出依赖文件。缺省的C++ 源码的扩展名为.cpp。 LOCAL_SRC_FILES := demo.c // BUILD_SHARED_LIBRARY是Build System提供的一个变量,指向一个GUN Makefile Script。它负责收集自从上次调用include $(CLEAR_VARS)后的所有LOCAL_xxxxinx。并决定编译什么类型 //1. BUILD_STATIC_LIBRARY:编译为静态库 //2. BUILD_SHARED_LIBRARY:编译为动态库 //3. BUILD_EXECUTABLE:编译为Native C 可执行程序 //4. BUILD_PREBUILT:该模块已经预先编译 include $(BUILD_SHARED_LIBRARY) ************************************************** #Application.mk 参数 // 默认生成支持的多种类型.so APP_ABI := all //APP_PLATFORM := android-16不配置,打包.so会出错 APP_PLATFORM := android-16 如果我们需要进行多个C++文件一起编译或者已有的.so参与编译,这里给出配置示例 # Android.mk // 示例1:单个c++文件参与编译 include $(CLEAR_VARS) // 编译出来的文件名 LOCAL_MODULE := DEMO LOCAL_SRC_FILES := demo.c // 多个c++文件参与编译 include $(CLEAR_VARS) // 编译出来的文件名 LOCAL_MODULE := DEMO LOCAL_SRC_FILES := test1.cpp test/ftest2.cpp test3.c // 示例2:.so文件参与模块编译 include $(CLEAR_VARS) // 编译出来的文件名 LOCAL_MODULE := DEMO2 LOCAL_SRC_FILES := test/DEMO.so // 设置可被依赖 include $(PREBUILT_SHARED_LIBRARY) 5. 打包.so库
6. 测试.so库 4. external tools配置在上面制作.h文件和.so文件中要在cmd或者terminal中输入javah、ndk-build命令比较麻烦,我们可以在external tools中进行配置,一次配置,终生幸福! //javah.exe的地址 Program:$JDKPath$\bin\javah //生成.h文件的路径指定在jni文件中,$FileClass$为源.java文件 Arguments:-encoding UTF-8 -d ../jni -jni $FileClass$ //进行编译成.h文件的源.java文件目录 Working directory:$ProjectFileDir$\app\src\main\java 2. ndk-build配置 //ndk-build.cmd路径 Program:$ModuleSdkPath$/ndk/21.3.6528147/ndk-build.cmd //生成的.so文件存放位置 Arguments:NDK_LIBS_OUT=$ProjectFileDir$\app\libs //编译源文件的目录 Working directory:$ProjectFileDir$\app\src\main 总结本篇博文主要讲解了两种.so库打包生成的方式,对于NDK开发的其他知识点学习请继续阅读我的系列文章。
android { compileSdkVersion 30 buildToolsVersion "30.0.2" ... sourceSets { main { jniLibs.srcDirs = ['libs'] } } } |
|
来自: 新用户3681NOyY > 《待分类》