Android JNI 开发环境配置
Android JNI 开发环境配置的3种方式
1. Android.mk 和Application.mk
编译Android系统源码驱动源码, 老式的Android JNI项目
2.根据ndk提供的工具生成独立运行的工具链, 独立编译so库
针对一下老的或者对Android平台还没有适配的开源库, 这些库一般用configure或automake来检测平台或者手动编写makefile来管理源码
3. gradle和CMakeLists.txt配置(推荐)
- 可以安装 独立运行的gradle和cmake编译
- 使用gradlewrapper 和ndk内置的cmake编译
gradle工程脚本
gradle是 groovy 语言编写的工程管理和构建脚本
groovy的特点
groovy是运行在 JVM 上的语言, 她会先编译成class文件后再运行,本质上,她可以使用反射调用的Java代码
groovy代码里可以使用Java的类库
groovy定义的一切类,属性,方法都是反射的,编译是不检查,但是运行时如果方法或属性不存在就会崩溃
groovy方法调用可以不写
()
, 类似shell 脚本的写法如:A.fun1 a,b,c //等效于 A.fun1(a,b,c)
groovy 的独立函数叫 Closure , 相当于java的lamda表达式或者函数接口类, 定义如下:
{int a,String B -> //TODO body }
或者没有参数或只有一个参数时,可以不写参数
{ //TODO body }
闭包有一个
delegate 对象,闭包内地可以使用
delegate` 对象的任何方法或属性不加任何说明,默认情况下为闭包定义处的那个对象访问一个对象的属性可以应
[]
, 如A["abc"] = 1 //等效于 A.abc = 1
字符串单,双,三引号都行,内部填参数用
${}
,如int a=12 String b = 'hello,world' String x = "show: ${a}, ${b}" String y = ''' new line new str '''
函数调用可以不按顺序或者全部写参数,但要指定参数定义是的名称.用
:
分隔,如def fun1={ int x, String y -> } // fun1(y:"hello",x:10) fun1(y:"hello")
- -
cmake语言的特点
cmake 是跨平台的 c, c++ 代码工程管理工具,她先将工程脚本编译成makefile, 或者微软的VirsualStudio或者XCode的工程文件后再编译
设置变量
set(变量名 变量值)
注意:cmake里有时字符串可以不加引号,如文件路径
设置选项, 作用和变量一样,不同是选项可以在图形界面的cmake或者help中显示
option(变量名 "提示说明文字" 默认值)
显示信息
message(STATUS "文字") #相当于 print message(FATAL_ERROR "文字") #相当于 print, 并停止编译
添加头文件
include_directories(目录1 目录2 ...)
编译成库
add_library(库名 SHARED|STATIC #SHARED=动态库,STATIC=静态库 源码文件列表 ... )
编译可执行程序
add_executable(库名 SHARED|STATIC #SHARED=动态库,STATIC=静态库 源码文件列表 ... )
指定库链接依赖关系
target_link_libraries(目标库或程序 依赖的库名列表 ... )
指定编译的依赖关系(编译的先后顺序)
add_dependencies(目标库或程序 依赖的库名列表 ...) # 依赖的库先被编译后,再编译目标库或程序
条件语句
if(条件) # 执行语句 elseif(另一个条件) # 执行语句 else() # 执行语句 endif()
常见的条件有:
变量为bool值或不存在, ON,YES,TRUE表示真, OFF,NO,FALSE表示假
字符串比较,匹配,如
"" STREQUAL "" # "abc" MATCHES "ab*"
NOT
运算其他cmake函数的返回值
循环语句
foreach(元素变量名 元素列表) # 执行体 endforeach()
定义cmake宏,宏是一段可重复调用的代码
macros(宏名 参数1 参数2 ...) # 隐藏的参数 ARGN 表示所有上面没有列出的参数组成的列表 # 执行语句 endmacros()
定义cmake函数,功能和宏一样,但是可以往外传参数
function(宏名 参数1 参数2 ...) # 隐藏的参数 ARGN 表示所有上面没有列出的参数组成的列表 # 执行语句 # 通过 set 语句返回 set(返回变量 返回值) endfunction()
定义C,C++的宏
# add_definitions(-D宏) add_definitions(-D宏=值) # remove_definitions(-D宏)
常用的系统全局变量
APPLE
,LINUX
,WIN32
: 编译平台是否是指定的系统CMAKE_CURRENT_LIST_DIR
,CMAKE_BINARY_DIR
:CMAKE_C_COMPILER
,CMAKE_CXX_COMPILER
,CMAKE_C_FLAGS
,CMAKE_CXX_FLAGS
:- 4.
查找库
find_library(结果变量 库名)
查找文件
find_file(结果变量 NAMES 文件名列表)
字符串处理
string(REPLACE 匹配 代替 输出 输入)
列表
list(APPEND 列表变量 插入值)
引进一个包含CMakelists.txt的子工程
add_subdirectory(路径 [别名]) #
批量引进源码文件
aux_source_directory(目录 结果变量) #将目录下的所有.c,.cpp文件生成一个列表
自定义任务
add_custom_target(目标名 COMMAND 命令行 # WORKING_DIRECTORY # COMMENT "打印的提示信息" DEPENDS 依赖列表 # #SOURCES 加入工程的源文件 ) add_custom_command(TARGET|OUTPUT 目标名称 #OUTPUT一般用于文件 PRE_BUILD | PRE_LINK| POST_BUILD #PRE_BUILD - 命令将会在其他依赖项执行前执行 #PRE_LINK - 命令将会在其他依赖项执行完后执行 #POST_BUILD - 命令将会在目标构建完后执行。 COMMAND 命令行 # WORKING_DIRECTORY # COMMENT "打印的提示信息" )
自定义属性
set_property([GLOBAL] DIRECTORY [dir] TARGET 列表 #SOURCE #TEST #CACHE [APPEND] "APPEND_STRING" PROPERTY 属性名称 [值列表])
abc
详细的cmake语法可参考一下文件
Android gradle工程
Android gradle工程目录结构
根目录
- build.gradle
//定义gradle插件的来源 buildscript { ext.kotlin_version = '1.2.40' repositories { google() jcenter() } dependencies { classpath 'com.android.tools.build:gradle:3.1.3' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } //对所有子工程起作用 allprojects { repositories { google() jcenter() maven { url "https://jitpack.io" } } }
注意: 这里的
repositories
,dependencies
不是类或对象定义, 而是函数调用,{}
是一个闭包,是前面函数的参数- local.properties:
sdk.dir=xxx ndk.dir=xxx
- gradle
放gradlewrapper(一个可独立运行的gradle)的jar和配置文件,可调gradle环境的版本
.gradle:
gradlew, gradle.bat: gradlewrapper的在Unix和Windows系统的启动脚本
gradle.properties:
设置总工程的全局属性, Java虚拟机的属性
- settings.gradle
子工程的列表
include ":ABC" //当前目录下的子工程 //添加不在当前目录下的子工程 include ":XYZ" project(":XYZ").projectDir=new File("pathxxxx")
子工程目录
仅有build.gradle
apply plugin: 'com.android.library' // === apply(plugin:'com.android.library') //这里仅展示与JNI相关的调用 android { //cmake工程文件的路径 externalNativeBuild { cmake { path "CMakeLists.txt" } } // defaultConfig { //运行cmake的配置 externalNativeBuild { cmake { arguments("-Dxyz=xyz", ...) //gradle 传给 cmake的变量 //传给CMAKE_CXX_FLAGS的变量, 其实也可以在CMakeLists.txt内部在设置 cppFlags("-std=c++11", ... ) // } } // ndk { //注意: 对于多构架来说, cmake 会每个构架运行一遍, 每次运行时 ANDROID_ABI 变量都不一样 abiFilters('armeabi-v7a', ...) //设置编译成的 so 库构架 'arm64-v8a', 'x86', 'x86_64' stl 'gnustl_static' // } } // // sourceSets { main { //要打包进aar里的so文件目录 jniLibs.srcDirs("${projectDir}/libs/jniLibs", ... ) } } }
Android JNI中的CMakeLists.txt
语法和全局变量与标准cmake相似, 但是多了一些特殊的全局变量和函数, 具体定义可以查看 android SDK 目录下的 cmake –> androidtoolchain.cmake
与Android相关的全局变量
ANDROID_NDK
ANDROID_TOOLCHAIN
ANDROID_ABI
ANDROID_PLATFORM
ANDROID_STL
STL库的类型,默认为portstlANDROID_PIE
ANDROID_CPP_FEATURES
ANDROID_ALLOW_UNDEFINED_SYMBOLS
ANDROID_ARM_MODE
ANDROID_ARM_NEON
ANDROID_DISABLE_NO_EXECUTE
ANDROID_DISABLE_RELRO
ANDROID_DISABLE_FORMAT_STRING_CHECKS
ANDROID_CCACHE
引进Android标准库
find_library(结果变量 库名称) # 如果没找到库, 变量 库名称_NOTFOUND 为 TRUE
常用的标准库有
- log:
- GLESv2:
- 3.
引进本地库
add_library(库名称 SHARED IMPORTED) # 设置库文件的本地路径 set_target_properties(库名称 PROPERTIES IMPORTED_LOCATION 库文件的本地路径)
Demo
主cmake文件
cmake_minimum_required(VERSION 3.0) # 支持高级的语法
include_directories(src/main/cpp
src/main/cpp/usbdevice
)
add_definitions(-D__android=1 -D__DEBUG=1)
## 定义引进本地so库的宏
set(ALG_DEP)
macro(add_alg_libs ROOT_DIR1)
foreach(one ${ARGN})
message(STATUS "Add ${one}")
add_library(${one} SHARED IMPORTED)
set_target_properties(${one} PROPERTIES IMPORTED_LOCATION ${ROOT_DIR1}/${ANDROID_ABI}/lib${one}.so )
#
list(APPEND ALG_DEP ${one})
endforeach(one)
endmacro()
## 引进Android内置的库
find_library(log-lib log)
find_library(glv2-lib GLESv2)
add_alg_libs(${CMAKE_CURRENT_LIST_DIR}/libs
ImiCamera iminect)
# 定义引进一个外部cmake的宏
set(ALL_TEST_LIB)
macro(ADD_TEST_LIB DIR)
include_directories(${DIR})
add_subdirectory(${DIR} test)
list(APPEND ALL_TEST_LIB ${ARGN})
endmacro()
## 引进一个外部的cmake
ADD_TEST_LIB(src/main/cpp/demo demo)
## 添加主库
add_library(testsuit_jni SHARED
src/main/cpp/testsuit_jni.cpp
src/main/cpp/testsuit_framework.cpp
)
target_link_libraries(testsuit_jni ${log-lib} ${glv2-lib} ${ALG_DEP} ${ALL_TEST_LIB})
外部cmake文件
cmake_minimum_required(VERSION 3.0)
add_library(demo
test_list.cpp
my_test.cpp)