如何脱离AndroidStudio使用gradle构建java项目多个工程生成so动态库

1251人阅读
jni c/c++(1)
Android Studio 可以配置build.gradle , main/jni文件夹中的c/c++文件会自动打包成so,但是如果有不同模块的文件,要编译出多个so文件,就不知道在gradle文件中咋配置了(可能也可以配置),这时就可以用原来eclipse的写法;&
main/jni文件夹按照原来eclipse的方法去写Android.mk和Application.mk,然后在main目录下执行ndk-build命令,该目录下会创建libs目录,里边就是生成的so,将项目配置的jniLibs.srcDirs指向src/main/libs就行;
这时有几个问题,一个是AS会自动重复编译jni中的文件,打包后会多一个没用的so,还有如果用了第三方的so文件会和自己项目的so文件冲突,因为每次ndk-build后都会删除原来文件夹中的其他so文件.
先去掉 defaultConfig中的ndk配置,然后配置 :
sourceSets{
//指定so库的位置,前边的是自己项目的,后边的是第三方的so
jniLibs.srcDirs=['src/main/libs','libs']
//禁止 android studio 自动编译
jni.srcDirs=[]
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:26286次
排名:千里之外
原创:40篇
评论:26条
(1)(1)(2)(4)(5)(8)(2)(1)(1)(3)(6)(2)(3)(4)(1)10762人阅读
AndroidStudio(2)
Android学习(36)
之前的文章中写了怎么打包so库,我这里说的是第三方库带的so文件。这两天看了下android gradle插件的更新日志,发现0.7.2版已经可以支持打包so文件了,把AndroidStudio更新到最新后,就可以使用了。
android gradle插件的0.7.2版更新日志中有这么一句:
那么就是说,我们可以在build.gradle的sourceSets.main中增加一个值,即:
jniLibs.srcDirs = ['xxx']&//这里xxx代表一个目录。
1·如果你没有引用libraryRroject,或者你引用的libraryProject中没有so文件,那么你可以将xxx写成libs,即你的工程中so文件目录。
2·如果你引用的libraryRroject中包含so文件,那么就需要多写几行代码。
主要思想就是把libraryRroject和你自己的so文件先拷贝到一个指定目录,然后把这个目录交给jniLibs.srcDirs,就ok了。
我在讲有如何拷贝libraryProject的so文件,参考一下。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:402484次
积分:3517
积分:3517
排名:第7674名
原创:52篇
转载:18篇
评论:249条
(2)(3)(4)(2)(1)(2)(1)(1)(1)(3)(3)(1)(2)(2)(1)(2)(1)(5)(5)(1)(9)(6)(1)(3)(6)(4)Android项目中如何用好构建神器Gradle?
发表于 10:36|
作者贾吉鑫
摘要:本文作者贾吉鑫为大众点评Android工程师,在进行团队并行开发时,分库遇到的问题很多都要通过Gradle脚本解决。Gradle虽为构建神器,但学习曲线比较陡峭,要想在Android项目中用好Gradle必须要做到三点。
Android Gradle实战
下面讲讲在Android Gradle实战中遇到的一些问题和经验,感觉还是蛮多干货的。
productFlavors
这个东西基本上已经烂大街了,gradle的项目一般都会使用Product Flavor,看完美团的文章,你应该就懂了。
buildTypes
很多App有内测版和正式版,怎么让他们同时安装在一个手机上?同时安装在一个手机上,要求packageName不同的,用productFlavors可以解决,但可能不够优雅,alpha版本还要来个debug和release版本岂不是很蛋疼?可以用buildTypes来解决,淘宝资深架构师朱鸿的有比较详细的讲解,但有些内容可能有些过时了,需要更改脚本。
项目依赖的远程包如果有更新,会有提醒或者自动更新吗? 不会的,需要你手动设置changing标记为true,这样gradle会每24小时检查更新,通过更改resolutionStrategy可以修改检查周期。
configurations.all {
// check for updates every build
resolutionStrategy.cacheChangingModulesFor 0, 'seconds'
dependencies {
compile group: "group", name: "projectA", version: "1.1-SNAPSHOT", changing: true
之前上传aar同一版本到maven仓库,但依赖却没有更新,该怎么办呢?可以直接删除本地缓存,缓存在~/.gradle/caches目录下,删除缓存后,下次运行就会自动重新下载远程依赖了。
上传aar到Maven仓库
在工程的build.gradle中添加如下脚本:
apply plugin: 'maven'
uploadArchives {
repositories {
mavenDeployer {
pom.groupId = GROUP_ID
pom.artifactId = ARTIFACT_ID
pom.version = VERSION
repository(url: RELEASE_REPOSITORY_URL) {
authentication(userName: USERNAME, password: PASSWORD)
在build.gradle同目录下添加gradle.properties文件,配置如下:
GROUP_ID=dianping.android.nova.thirdparty
ARTIFACT_ID=zxing
VERSION=1.0
RELEASE_REPOSITORY_URL=/nova
USERNAME=hello
PASSWORD=hello
gradle.properties的属性会被build.gradle读取用来上传aar,最后执行./gradlew :Zxing:uploadArchives即可。
更多配置,可参考。
项目构建过程中那么多任务,有些test相关的任务可能根本不需要,可以直接关掉,在build.gradle中加入如下脚本:
tasks.whenTaskAdded { task -&
if (task.name.contains('AndroidTest')) {
task.enabled = false
tasks会获取当前project中所有的task,enabled属性控制任务开关,whenTaskAdded后面的闭包会在gradle配置阶段完成。
任务可以取消了,但还不尽兴啊,想加入任务怎么搞?前面讲了dependsOn的方法,那就拿过来用啊,但是原有任务的依赖关系你又不是很清楚,甚至任务名称都不知道,怎么搞?
比如我想在执行dex打包之前,加入一个hello任务,可以这么写:
afterEvaluate {
android.applicationVariants.each { variant -&
def dx = tasks.findByName("dex${variant.name.capitalize()}")
def hello = "hello${variant.name.capitalize()}"
task(hello) && {
println "hello"
tasks.findByName(hello).dependsOn dx.taskDependencies.getDependencies(dx)
dx.dependsOn tasks.findByName(hello)
afterEvaluate是什么鸟?你可以理解为在配置阶段要结束,项目评估完会走到这一步。
variant呢?variant = productFlavors+ buildTypes,所以dex打包的任务可能就是dexCommonDebug。
你怎么知道dex任务的具体名称?Android Studio中的Gradle Console在执行gradle任务的时候会有输出,可以仔细观察一下。
hello任务定义的这么复杂干啥?我直接就叫hello不行吗?不行,each就是遍历variants,如果每个都叫hello,多个variant都一样,岂不是傻傻分不清楚,加上variant的name做后缀,才有任务的区分。
关键来了,dx.taskDependencies.getDependencies(dx)会获取dx任务的所有依赖,让hello任务依赖dx任务的所有依赖,再让dx任务依赖hello任务,这样就可以加入某个任务到构建流程了,是不是感觉非常灵活。
我突然想到,用doFirst的方式加入一个action到dx任务中,应该也可以达到上面效果。
gradle加速
gradle加速可以看看这位朋友写的,我就不多嘴了。并行编译,常驻内存,还有离线模式这些思路对gradle的加速感觉还是比较有限。
想要更快,可以尝试下Facebook出品的,可以看一下Vine团队适配Buck的,我们的架构师也有适配Buck,加速效果在10倍左右,但有两个缺点,不支持Windows系统,不支持远程依赖。
你想知道每个执行任务的运行时间吗?你想知道每个执行任务都是干嘛的吗?把下面这段脚本加入build.gradle中即可:
class TimingsListener implements TaskExecutionListener, BuildListener {
private Clock clock
private timings = []
void beforeExecute(Task task) {
clock = new org.gradle.util.Clock()
void afterExecute(Task task, TaskState taskState) {
def ms = clock.timeInMs
timings.add([ms, task.path])
task.project.logger.warn "${task.path} took ${ms}ms"
void buildFinished(BuildResult result) {
println "Task timings:"
for (timing in timings) {
if (timing[0] &= 50) {
printf "%7sms
%s\n", timing
void buildStarted(Gradle gradle) {}
void projectsEvaluated(Gradle gradle) {}
void projectsLoaded(Gradle gradle) {}
void settingsEvaluated(Settings settings) {}
gradle.addListener new TimingsListener()
上面是对每个任务计时的一个例子,想要了解每个任务的作用,你可以修改上面的脚本,打印出每个任务的inputs和outputs。比如assembleDebug那么多依赖任务,每个都是干什么的,一会compile,一会generate,有什么区别?看到每个task的输入输出,就可以大体看出它的作用。如果对assemble的每个任务监听,你会发现改一行代码build的时间主要花费在了dex上,buck牛逼的地方就是对这个地方进行了优化,大大减少了增量编译运行的时间。
buildscript方法
Android项目中,根工程默认的build.gradle应该是这样的:
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
dependencies {
classpath 'com.android.tools.build:gradle:1.2.3'
allprojects {
repositories {
一会一个jcenter()这是在干什么?buildscript方法的作用是配置脚本的依赖,而我们平常用的compile是配置project的依赖。repositories的意思就是需要包的时候到哥这里来找,然后你以为com.android.tools.build:gradle:1.2.3会从jcenter那里下载了是吧,图样图森破,不信加入下面这段脚本看看输出:
buildscript {
repositories {
repositories.each {
println it.getUrl()
dependencies {
classpath 'com.android.tools.build:gradle:1.2.3'
结果是这样的:file:/Applications/Android%20Studio.app/Contents/gradle/m2repository/ /
我靠,仓库竟然直接在Android Studio应用内部,所以说你去掉buildscript的jcenter()完全没有关系啊,下面还有更爽的,我们知道有依赖传递,上面classpath
中的gradle依赖gradle-core,gradle-core依赖lint,lint依赖lint-checks,lint-checks最后依赖到了asm,并且这个根目录中的依赖配置会传到所有工程的配置文件,所以如果你要引用asm相关的类,不用设置classpath,直接import就可以了。你怎么知道前面的依赖关系的?看上面m2repository目录中对应的pom文件就可以了。
为什么讲到ASM呢?又是个比较刁的东西,可以直接用来操纵Java字节码,达到动态更改class文件的效果。可以用ASM,达到解耦效果。中提到的class依赖分析和R常量替换的脚本都可以用ASM来搞。
脚本写多了,都挤在一个build.gradle里也不好,人长大了总要自己出去住,那可以把部分脚本抽出去吗?当然可以,新建一个other.gradle把脚本抽离,然后在build.gradle中添加apply from 'other.gradle'即可,抽出去以后你会发现本来可以直接import的asm包找不到了,怎么回事?根工程中配置的buildscript会传递到所有工程,但只会传到build.gradle脚本中,其他脚本可不管,所以你要在other.gradle中重新配置buildscript,并且other.gradle中的repositories不再包含m2repository目录,自己配置jcenter()又会导致依赖重新下载到~/.gradle/caches目录。如果不想额外下载,也可以在other.gradle中这么搞:
buildscript {
repositories {
url rootProject.buildscript.repositories[0].getUrl()
dependencies {
classpath 'com.android.tools.build:gradle:1.2.3'
获取AndroidManifest文件
提到,gradle中的applicationid用来区分应用,manifest中packageName用来指定R文件包名,并且各个productFlavor
的manifest中的packageName应该一致。applicationid只是gradle脚本中的定义,其实最后生成的apk中的manifest文件的packageName还是会被applicationid替换掉。
那获取R文件的包名怎么搞?要获取AndroidManifest中package属性,并且这个manifest要是起始的文件,因为最终文件中的package属性会被applicationid冲掉,由于各个manifest中的package属性一样,并且非主manifest可以没有package属性,所以只有获取主manifest的package属性才是最准确的。
def manifestFile = android.sourceSets.main.manifest.srcFile
def packageName = new XmlParser().parse(manifestFile).attribute('package')
无用的资源就不要打包进APK了。
之前在创业公司,用
做持续继承,遇到一个让我很纠结的问题。在Travis上执行构建脚本如下:
./gradlew clean
./gradlew assembleXR
最后生成的APK在运行的时候报错,提示找不到某个.so文件,解压发现APK中果然缺少某个库工程的.so文件,但在本地运行的时候却是没有问题,纠结了好久,后来研究发现Android
Studio中执行Clean Project的时候,会执行generateSources的任务,把它加入构建脚本后才打包正确。最近发现,这原来是个,并且已经在android gradle1.3被修复了。
匆匆忙忙间,写了很多东西。读完此文,希望你能感受到构建神器的魅力,感受到它的灵活强大,当然也希望能让你使用Gradle更加得心应手。作者简介:贾吉鑫(),大众点评Android工程师,开发经验丰富,乌云白帽子,关注网络安全,个人博客:。
将于10月15-16日在北京新云南皇冠假日酒店召开。大会特设五大技术专场:平台与技术iOS、平台与技术Android、产品与设计、游戏开发、企业移动化。此外,大会更是首次举办国内极具权威影响力的IoT技术峰会,特设硬件开发技术与虚拟现实两大专场。大会将聚集国内最具实力的产品技术团队,与开发者一道进行最前沿的探讨与交流。
第一时间掌握最新移动开发相关信息和技术,请关注mobilehub公众微信号(ID: mobilehub)。&
推荐阅读相关主题:
CSDN官方微信
扫描二维码,向CSDN吐槽
微信号:CSDNnews
相关热门文章Android Studio NDK开发同时加载多个SO文件时该如何配置_android开发吧_百度贴吧
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&签到排名:今日本吧第个签到,本吧因你更精彩,明天继续来努力!
本吧签到人数:0成为超级会员,使用一键签到本月漏签0次!成为超级会员,赠送8张补签卡连续签到:天&&累计签到:天超级会员单次开通12个月以上,赠送连续签到卡3张
关注:112,079贴子:
Android Studio NDK开发同时加载多个SO文件时该如何配置收藏
使用AS学习NDK开发时,当DEMO中只用到一个SO文件,开发、调试均正常。AS在开发NDK时是不需要手动编写Android.mk和Application.mk的,而通过配置build.gradle文件,可以自动在build目录下生成Android.mk,但是在配置build.gradle文件时,发现在ndk{...}中,只能配置一个moduleName,而这个moduleName正是编译后生成的SO文件名,请问现在需要加载多个SO文件时,这个build.gradle文件该如何配置?build.gradle文件:defaultConfig {
moduleName &hello_jni&
ldLibs &log&, &z&, &m&
abiFilters &armeabi&, &armeabi-v7a&, &x86&
android开发,就业薪资高,发展前景好,零基础入学,120天入门到精通.名师面授-线上线下任你选,先就业后付款,学员尊享-名企入职通道.先就业后付款!
为什么要删我的贴啊?菜鸟着急求救啊
求救啊~~~
有没有大神啊~~
你不是已经写好了么,打包就行
NDK只能有一个so
楼主,请问这个问题解决了吗 遇到了相同的问题 看了好多网上的资料都没有解决
同问同问,我现在在上层同时要调用到串口和GPIO,ndk编译分别生成两个.so没问题,但怎样能同时生成两个.so?
登录百度帐号推荐应用
为兴趣而生,贴吧更懂你。或

我要回帖

更多关于 gradle 多项目构建 的文章

 

随机推荐