突然好久发现没写JNI相关的代码了,也不清除现在的一个流程了,所以今天特地重新尝试了下so文件的开发以及打包发布aar等流程。
现在AS已经发展到了3.6.3的版本了,我们可以直接新建一个使用JNI的Native C++示例工程,如下图最后一个Native C++的工程模板,一路Next,Finish下去即可创建好该工程了。
新建的工程跟之前的区别不是很大,在main下多了一个 cpp 的文件夹,专门用来存放 .cpp代码 以及 CMakeLists.txt文件 。
直接运行就能看到效果了,但是由于我们要打aar的包,所以我们新建module来做。
直接新建Android Library Module,新建完后我们仿照工程中app module的示例代码来完善。
在hello module的main文件夹下创建cpp文件夹,这个文件夹中需要包含CMakeLists.txt和.cpp的源码文件,然后我们来完善这个文件夹。
我们仿照app module中编写CMakeLists.txt文件:
cmake_minimum_required(VERSION 3.4.1)
add_library( # Sets the name of the library.
#注意这里的library name,下文在java(kotlin)类中需要用到
hello-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
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-lib
# Links the target library to the log library
# included in the NDK.
${log-lib})
可以看到我们在该文件中配置了生成的library名称为:hello-lib,而使用的代码文件是hello.cpp文件。
好了接下来新建.cpp文件,里面是一个示例的hi()方法【为啥要加这个方法进去?因为我在新的module中创建java或者kotlin类后,在类中新建本地方法,结果发现快捷键无法直接生成对应的c++方法。但是只要这个cpp文件有任意一个方法后,在本地方法上使用快捷键就可以直接生成了】:
#include
#include
extern "C"
JNIEXPORT void JNICALL
Java_xxx_hi(JNIEnv *env, jobject thiz) {
// TODO: implement hi()
}
打开hello Module下的build.gradle文件,我们仿照app中的进行修改,其实就两处:
修改完毕后重新构建下项目:
android {
......
defaultConfig{
......
externalNativeBuild {
cmake {
cppFlags ""
}
}
}
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt" //这里就是上文我们在module中编写的hello CMakeLists.txt文件
version "3.10.2"
}
}
}
在hello Module中java文件夹下的包中新建showHello类(kotlin示例)如下:
class ShowHello {
companion object {
init {
System.loadLibrary("hello-lib")
}
}
external fun getHello(): String
}
伴生对象init{}代码块中的就是我们需要加载的library名称,需要和你在CMakeLists.txt中定义Library 名称的一致。
然后我们写本地方法getHello(),此时在getHello()方法上使用快捷键 Alt+Enter ,弹出如下所示:
回车后即可在上文的hello.cpp文件中看到生成的代码了,但是如果在上文.cpp文件中没有配置默认方法的话,这一步就废了无法帮助我们自动生成:
然后记得将生成的代码中的TODO完善,下文中我们就让其返回了一个默认的字符串:
#include
#include
extern "C"
JNIEXPORT void JNICALL
Java_xxx_hi(JNIEnv *env, jobject thiz) {
// TODO: implement hi()
}
extern "C"
JNIEXPORT jstring JNICALL
Java_com_cooloongwu_hello_ShowHello_getHello(JNIEnv *env, jobject thiz) {
// TODO: implement getHello()
return env->NewStringUTF("This is a String from hello module, hello.cpp");
}
让app module直接依赖hello module,然后在MainActivity中直接打印该方法即可,例如最简单的:
Log.e("本地方法测试", ShowHello().getHello())
不出意外的话,可以直接在控制台打印出来信息了,好的,快进。
打包的话其实很简单了,打开AS右侧的Gradle,在hello module下点击Tasks->other->assembleRelease,等待AS构建完即可在 hello模块下的build/outputs/aar文件夹下看到生成的hello-release.aar文件了。
将该文件拷贝出来,我们解压看看里面内容如下,生成的so文件其实在jni目录下:
新建其他Android工程,然后我们直接将上文生成的 hello-release.aar包拷贝到新工程app module的libs目录下,然后更改app module下的build.gradle文件,添加对该aar包的依赖:
dependencies {
...
implementation files('libs/hello-release.aar')
}
然后构建项目。
构建完毕后直接在MainActivity中日志打印调用aar中的ShowHello类的getHello()方法即可测试。
好了,整个打包及使用的过程到这里就结束了。但是每次这样打包下发给其他人去更新去使用的话是不是很麻烦呢,而且也没有个版本号信息什么的,不方便查阅。所以我们可不可以发布这个aar包到公司构件仓库中,然后配置依赖去使用呢,当然可以哈哈。如果对构件仓库还不熟悉的请参考 AndroidStudio加速之–构件仓库Artifactory 这篇文章,下文我们就将aar发布到Artifactory中。
最后说下,我最近写的一些文章知识点基本快串联起来了。下面是相关的文章:
AndroidStudio加速之–(一)构件仓库Artifactory
Android NDK、JNI之–(四)so打包发布aar
AndroidStudio加速之–(三)发布aar到Artifactory
Android 编译插桩之–自定义Gradle插件