Android studio下Cmake配置编译开发jni总结

在Android Studio在2.2版本实现了Ndk开发新的编译工具Cmake,比之前ndk-build方式来得更方便快捷,可以直接运行app时就生成了so并打包到apk中,省去了之前开发ndk时出现的很多麻烦。例如没有代码提示,自动填充,开发起来都是一个个手写,出现错误只能是编译打包阶段提示,还必须先生成so再替换原文件运行。现在通过cmake开发起来得到大大提升,下面介绍这段时间ndk jni开发遇到的一些问题以及技巧总结。

基本使用

下载工具Cmake,然后在AS 2.2版本以上新建工程时勾选Include C++ Support,工程新建好之后,发现与常规项目不同的是多了.externalNativeBuild文件夹、cpp文件夹、CMakeLists.txt文件。其他具体细节使用自行百度

cmake基本配置解析

指定cmke版本
cmake_minimum_required(VERSION3.4.1)

add_library()命令用于向CMake添加依赖源文件或库
指令需传入三个参数(函数库名称、库类型、依赖源文件相对路径)
add_library( # 生成函数库的名称,即libnative-lib.so或libnative-lib.a(lib和.so/.a默认缺省)
native-lib
# 生成库类型:动态库为SHARED,静态库为STATIC
SHARED
# 依赖的c/cpp文件(相对路径)
src/main/cpp/native-lib.cpp )

find_library()命令用于定位NDK中的库
需传入两个参数(path变量、ndk库名称)
find_library( # 设置path变量的名称,这里为NDK中的日志库
log-lib
#指定cmake查询库的名称
#即在ndk开发包中查询liblog.so函数库,将其路径赋值给log-lib
log )

target_link_libraries()命令用于指定要关联到的原生库的库
target_link_libraries(# 指定目标库,与上面指定的函数库名一致
native-lib
# 链接的库,根据log-lib变量对应liblog.so函数库
${log-lib} )

cmake优化配置

设置生成的so动态库最后输出的路径,默认编译产出路径在build/intermediates/cmake/debug/obj
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY P R O J E C T S O U R C E D I R / s r c / m a i n / j n i L i b s / {ANDROID_ABI})
可以设置输出在其他路径,但是运行会和默认路径中的重复,在打包运行时会报整合JniLibs时重复资源。

设置囊括编译cpp文件
aux_source_directory(src/main/cpp SRC_LIST)
然后直接引用${SRC_LIST}即可
避免add_library中手动输入每个cpp文件

生成多个so文件,就配置多个add_library 并指定cpp
add_library( * )

手动配置Cmake开发环境

一般默认在创建新项目时,在AS 2.2版本以上新建工程时勾选Include C++ Support就支持了cmake环境配置开发。但是若是针对已存在的项目中module项目,想从Ndk编译环境改成Cmake怎么手动配置?其实很简单:通过查看新建项目下app的build.gradle中android{}中新出现了如下配置:

externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
        }
    }

和项目中多了一个CMakeLists.txt文件以及main下面有cpp文件夹(c/c++源代码),故我们可以在已有的module中直接新增这些配置是不是就可以了。实践证明确实如此,build文件同步之后会去下面cmake库等支持环境配置,同时也在task/other下出现:
这里写图片描述
直接手动运行externalNatvieBuildRelease会在build下生成so库,如下所示:
这里写图片描述

常见异常处理

1、undefined reference to **
编译时候找不到引用 ,主要就是编译时候没有一起参与编译引用,可以通过上述方式配置自动添加或者手动在add_library中增加相关cpp文件

2、java.lang.UnsatisfiedLinkError: No implementation found***
在编译之后,运行时会报本地方法没有实现,这主要是因为AndroidStudio自动生成的底层文件是.cpp的,也就是使用了c++的语法规则,但又jni调用要采用了c方式编译,那么要在so入口的cpp文件中做些修改,在每个函数上方,加一行 extern “C” 即可。
在demo中即是要在native-lib.cpp文件中添加新的方法,必须添加在extern”C” { } 中,或者在每个方法前加extern”C”, 否则会报找不到方法。如果源文件为C,则须将extern“C”部分去掉,因为extern “C”的作用就是告诉编译器以C方式编译,这个时在静态注册下需要如此,在动态注册下可以不需要。

3、JNI DETECTED ERROR IN APPLICATION: use of deleted local reference
在有习惯删除不用引用之后(DeleteLocalRef)很容易出现这样的乌龙,这种错误调试起来比较麻烦,需要一个个去打印日志定位。

SO文件release包

在上述默认配置情况下,在运行编译时会在项目build\intermediates\cmake\目录下生成debug和release包,如下图:
这里写图片描述
其中会发现debug和release下的包都很大(255K左右),比用ndk-build(NDKbuild模式下34k左右)大很多。奇怪的是你会发现此时debug包比release的对应包还小一点。其实release包这么大还是因为编译过程中生成二进制码没有被剥除。故在CMakeLists配置中增加如下配置:

set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -s")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -s")

从字面来看是设置了release模式Flag,重新运行externalNativeBuildRelease Task,会发现release下的包小了很多,和NDKbuild下一样大,而debug下没有变化。如下图:
release下

debug下

猜你喜欢

转载自blog.csdn.net/u010019468/article/details/78271965