最近没什么事,就想将十年前公司eclipse写的jni项目转化到Android Studio工程,并使用新的构建工具CMake。
从eclipse转AS工程很简单,直接用as自带的转换即可。最麻烦的部分就是jni那块,该文章主要介绍CMakeList.txt脚本的编写,以及Android.mk里面命令跟CMakeList.txt命令的对比。
转换项目工程我就不说了,直接选择Import project(Gradle,Eclipse ADT,etc.)。
然后导入你的eclipse工程,等构建完毕后(编译的时候可能不会报错,运行才会提示),这个时候jni还并没有关联上。
第一种你可以直接运行,然后报错的时候as会提示你关联jni。
第二种方式,右键app->Link C++ Project with Gradle,如下图(一定要是右键Module,在Project右键是没有的)
然后会让你选择用哪种构建方式,有两种:
1. CMake:Android studio新的构建方式,Project Path需要选择CMakeList.txt文件路径,jni会按照这个脚本来进行编译,具体脚本的编写看下面。
2. ndk-build:老eclipse的构建方式,也就是Android.mk的形式。
点击ok之后就会开始构建,其实这个选择也就是在gradle里面加一句话而已。
1.设置需要设置构建jni所需的CMake的最低版本
cmake_minimum_required(VERSION 3.4.1)
2.设置生成的so动态库最后输出的路径,如果项目的so库不需要给别人使用,也可以不设置,不设置的话会生成在build里面,如果给别人使用,寻找的话还是比较麻烦,所以指定一下路径更方便。
# 设置生成的so动态库最后输出的路径,set后面两个参数,
# 前面一个是命令,后面是路径。
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/../jniLibs/${ANDROID_ABI})
3.设置头文件搜索路径,如果跟CMakeLists.txt同路径则不需要设置,同路径下文件夹不行。
#设置头文件搜索路径(和此txt同个路径的头文件无需设置),可选
include_directories(Cipher
Core
Core/Common
Core/DB
Core/DG)
对应于Android.mk 下的 LOCAL_C_INCLUDES
4.设置生成so库的名称,并为源文件提供一个相对路径
file(GLOB jni "*.cpp")//设置统配符
file(GLOB Cipher "Cipher/*.cpp")//设置统配符
add_library( # Sets the name of the library. 设置库的名称,也就是生成的so名称,在java代码中加载so库需要与此一致
demo
# Sets the library as a shared library. 将library设置为一个共享库
SHARED
# Provides a relative path to your source file(s).为源文件提供一个相对路径,可以使用通配符,也可以一个一个文件的引入
demo.cpp
${jni}//引用上面设置到通配符
${Cipher}
)
对应于Android.mk
LOCAL_MODULE 设置so库的名称
LOCAL_SRC_FILES 设置源文件
FILE_LIST 设置文件列表,也就是通配符
5.使用本地系统库,在CMake默认的搜索路径就已经包含了系统库,所以直接指定名称就行,CMake会验证库是否存在。
find_library( # Sets the name of the path variable.
设置路径变量的名称,后面会引用到
log-lib //log日志,默认都需要添加
# Specifies the name of the NDK library that 指定NDK库的名称
# you want CMake to locate.
log
)
find_library( # Sets the name of the path variable. 设置路径变量的名称
jnigraphics-lib
# Specifies the name of the NDK library that 指定NDK库的名称
# you want CMake to locate.
jnigraphics
)
对应于Android.mk 下的 LOCAL_LDLIBS
6.加载第三库,比如自己定义的库,或者用的第三方库,.a库等等
//比如添加一个第三方库libpng,这两个需要配合使用
add_library(libpng STATIC IMPORTED)
set_target_properties( libpng
PROPERTIES IMPORTED_LOCATION
......../libpng.a )
使用的时候,只需要修改将两个libpng名称改成你需要的,可以随意取,该名称是后面用来链接使用的,再修改一下对应文件路径就ok。
对应于Android.mk 下的 LOCAL_LDLIBS
7.链接所有的库,比如上面我们添加的第三方库,添加的本地log库
target_link_libraries( # Specifies the target library.指定目标library中。
//通过add_library添加的直接写设置的名字,
//一种是SHARED,一般来说就是我们需要生成的so文件
//二中是STATIC IMPORTED 添加的第三方静态库
demo
libpng
# Links the target library to the log library 将目标library链接到日志库
# included in the NDK.
//链接本地NDK里面的库
${log-lib}
${jnigraphics-lib}
)
8.如何通过CMakeList.txt生成多个so库?针对不同的so库,编写不同的CMakeList.txt,然后在主CMakeList.txt中加载
# 再主CMakeList.txt中加载其他的子CMakeList.txt文件
# 指定子CMakeList.txt文件路径(指定到CMakeList.txt所在文件夹即可)
ADD_SUBDIRECTORY(FrameWork/ThirdParty/a)
ADD_SUBDIRECTORY(b)
9.如果不进行配置,那么默认会生成四种架构的so库文件,如何生成指定的so库文件
externalNativeBuild {
cmake {
cppFlags ""
abiFilters "armeabi-v7a"//需要什么构架的so,就在这边添加即可
}
}
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html
# Sets the minimum version of CMake required to build the native library.
cmake_minimum_required(VERSION 3.4.1)
# 设置生成的so动态库最后输出的路径
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/../jniLibs/${ANDROID_ABI})
#设置头文件搜索路径(和此txt同个路径的头文件无需设置),可选
include_directories(Cipher
Core
Core/Common
Core/DB
Core/DG
)
file(GLOB jni "*.cpp")
file(GLOB Cipher "Cipher/*.cpp")
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK. Gradle
add_library( # Sets the name of the library. 设置库的名称。
demo
# Sets the library as a shared library. 将library设置为一个共享库
SHARED
# Provides a relative path to your source file(s).为源文件提供一个相对路径
demo.cpp
${jni}
${Cipher}
)
# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
find_library( # Sets the name of the path variable. 设置路径变量的名称
log-lib
# Specifies the name of the NDK library that 指定NDK库的名称
# you want CMake to locate.
log
)
find_library( # Sets the name of the path variable. 设置路径变量的名称
jnigraphics-lib
# Specifies the name of the NDK library that 指定NDK库的名称
# you want CMake to locate.
jnigraphics
)
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
add_library(libpng STATIC IMPORTED)
set_target_properties( libpng
PROPERTIES IMPORTED_LOCATION
..../libpng.a )
target_link_libraries( # Specifies the target library.
demo
libpng
# Links the target library to the log library
# included in the NDK.
${log-lib}
${jnigraphics-lib}
)
//加载子CMakeList.txt文件
ADD_SUBDIRECTORY(FrameWork/ThirdParty/a)
ADD_SUBDIRECTORY(b)
sourceSets{
main{
jniLibs.srcDirs = ['libs']
}
}
Demo链接
Android Studio NDK CMake 指定so输出路径以及生成多个so的案例与总结