Android Gradle基于参数化配置实现差异化构建
一、背景:
项目中有一些特殊的需求,如个别渠道集成腾讯bugly,个别渠道集成易观统计,不同的渠道集成不同的推送策略(如Oppo渠道优先Opush推送),不同的渠道拥有不同的第三方登录集成等等。这些需求本身,往往都与外部集成进来的功能有关,且需求上,功能与渠道本身,有一定的映射关系,对于此类需求,具体项目构建时可以有如下几种策略:
1,不同的分支管理,以对应不同的差异化实现;
2,通过变体,实现不同的差异化构建;
3,通过Android Gradle参数化配置,实现差异化构建。
二、方案利弊分析:
1,基于不同的分支管理,差异部分的代码直接在特殊分支中,每次需要与主分支进行合并并解决可能的合并冲突。同时,针对特殊的渠道逻辑,如果代码通过分支隔离,往往开发个体都是基于主分支开发,渠道的差异性逻辑处理部分容易忽略,有时候造成不必要的bug等情形,维护成本较大。
2,基于变体的差异化构建,直接使用Gradle变体方案,优势在于变体目录及对应的构建流程已经自动包含。对应的,不太优雅的地方在于此类需求一旦繁杂,变体的种类及对应的目录层次相对增多,变体类型会随着产品风味的增加而成倍数增长,在具体构建时,构建任务也会相对繁杂,且对应在build等目录下的输出的目录层次也相对复杂。
3,基于Gradle的参数化配置,依据具体的需求详情,主动配置并处理对应的差异化构建逻辑,如渠道的映射关系,不同的外部依赖,以及对应的代码占位等,以此在保持原有变体不变和构建任务不变的情况下,只需通过参数化的配置,即可完成对应的差异化部分构建。
本文主要讨论“通过参数化配置实现差异化构建”实现方案。
下面通过个别渠道集成bugly和易观统计详细讨论具体的实现过程。
三,实例
1,个别渠道的bugly集成
主工程如果要集成bugly,相对非常简单,主要包括build.gradle
中引入bugly依赖,适当位置(如Application
中)初始化bugly,proguard.cfg
中进行bugly的混淆配置。但本例中,bugly集成不是针主工程本身,而是针对特定的渠道。具体的参数化配置实现差异化构建过程如下:
a,项目主工程中新建ext.gradle
文件,实现对渠道的逻辑映射:
ext.gradle
--------------------------
ext {
channel = project.hasProperty('channel') ? channel : 'feature'
addBugly = {
def buglyChannelList = ["huawei"]
def result = buglyChannelList.contains(channel)
println ">>> channel:${channel}, bugly added:${result}"
if(result) {
return true
}
return false
}
}
android {
sourceSets {
main{
java {
if(addBugly()) {
srcDirs "src/ext/bugly/java"
} else {
srcDirs "src/mock/bugly/java"
}
}
}
}
}
dependencies {
if (addBugly()) {
api 'com.tencent.bugly:crashreport:latest.release'
api 'com.tencent.bugly:nativecrashreport:latest.release'
}
}
复制代码
具体的逻辑映射包括:
1.1,渠道值(channel
)的接收和逻辑判断addBugly
;
1.2,对应逻辑确认下(addBugly
)的bugly依赖引入;
1.3,对应逻辑确认下的源集指定。
b,项目主工程中引入ext.gradle
apply from: '../ext.gradle'
复制代码
c,项目对应模块中,处理对应的源集逻辑(base模块为例)
base/src/main/java/com/mycorn ---默认工程源码
base/src/ext/bugly/com/mycorn ---bugly逻辑确认下的额外源集源码目录
base/src/mock/bugly/com/mycorn ---通常情况下的额外源集源码目录
base/src/ext/bugly/com/mycorn
---------------------------------
package com.mycorn;
import android.app.Application;
import android.util.Log;
public class BuglyHelper {
public static final String TAG = "BuglyHelper";
public static void initBugly(Application context) {
Log.d(TAG, "bugly init...";
// 初始化腾讯bugly 第三个参数表示是否处于调试模式
com.tencent.bugly.crashreport.CrashReport.initCrashReport(context, "bbccdd123456", false);
}
}
base/src/mock/bugly/com/mycorn
---------------------------------
package com.mycorn;
import android.app.Application;
import android.util.Log;
public class BuglyHelper {
public static final String TAG = "BuglyHelper";
public static void initBugly(Application context) {
Log.d(TAG, "bugly init...mock");
// 实际上是空方法,主要是用于占位
}
}
复制代码
d,项目主工程下,在对应初始化bugly的地方直接写上通用性的bugly初始化占位逻辑
....
....
com.mycorn.BuglyHelper.initBugly(context);
....
....
复制代码
e,proguard.cfg
配置项,由于只是进行代码混淆的配置,此处可以直接放到对应模块的proguard.cfg
文件中
....
....
# 腾讯bugly
-dontwarn com.tencent.bugly.**
-keep public class com.tencent.bugly.**{*;}
....
....
复制代码
至此,基于参数化配置实现腾讯bugly引入的差异化构建,得以完成。
其中关键点,在于对应的“占位”逻辑的处理。
2,个别渠道的易观统计集成 总体上与上述的腾讯bugly集成类似,特别之处在于易观统计的接入项目中是直接引入的jar
文件,并在对应的AndroidManifest.xml
文件中配置了不少的如<service>
、<receiver>
及其他元数据等配置项。
Android Gradle项目构建时,对于同一模块,可以通过sourceSets
增加如源码及资源目录等,但却不能增加AndroidManifest
文件,形如manifest.srcFile
的写法当前只能是对AndroidManifest
文件的重新设定。但如果是独立模块,或已经是独立的外部aar
等依赖引入,Android Gradle
构建时会自动实现对应的AndroidManifest
文件合并。因此,为了能够将易观统计中的AndroidManifest
配置项进行单独隔离,需要在上例中的基础上将易观统计单独隔离成独立模块,或对应的aar
文件等(本例在于阐述具体解法,对于最新的易观统计如果已经支持依赖引入,则不在讨论范围内)。
a,将易观形成独立模块,AndroidManifest
,libs
目录下的jar
包,proguard.cfg
文件等,实现独自配置;
b,参照上例bugly的集成,处理对应的易观逻辑关系
ext {
channel = project.hasProperty('channel') ? channel : 'feature'
addBugly = {
def buglyChannelList = ["huawei"]
def result = buglyChannelList.contains(channel)
println ">>> channel:${channel}, bugly added:${result}"
if(result) {
return true
}
return false
}
addEguan = {
def eguanChannelList = ["baidu"]
def result = eguanChannelList.contains(channel)
println ">>> channel:${channel}, eguan added:${result}"
if(result) {
return true
}
return false
}
}
android {
sourceSets {
main{
java {
if (addBugly()) {
srcDirs "src/ext/bugly/java"
} else {
srcDirs "src/mock/bugly/java"
}
if (addEguan()) {
srcDirs "src/ext/eguan/java"
} else {
srcDirs "src/mock/eguan/java"
}
}
}
}
}
dependencies {
if (addBugly()) {
api 'com.tencent.bugly:crashreport:latest.release'
api 'com.tencent.bugly:nativecrashreport:latest.release'
}
if (addEguan()) {
api project(':eguan')
}
}
复制代码
c,同样的对应的目录下形成易观的源集逻辑,并在需要初始化的地方,改成通用的逻辑占位写法。
base/src/ext/eguan/com/mycorn
---------------------------------
package com.mycorn;
import android.content.Context;
import android.util.Log;
import com.eguan.monitor.EguanMonitorAgent;
public class EguanHelper {
public static final String TAG = "EguanHelper";
public static void initEguan(Context context) {
Log.d(TAG, "eguan init...");
try {
EguanMonitorAgent.getInstance().initEguan(context, "111222333", "baidu");
} catch (Exception e) {
Log.d(TAG, "eguan init exception...");
}
}
}
base/src/mock/eguan/com/mycorn
---------------------------------
package com.mycorn;
import android.content.Context;
import android.util.Log;
public class EguanHelper {
public static final String TAG = "EguanHelper";
public static void initEguan(Context context) {
Log.d(TAG, "eguan init...mock");
// 实际上是空方法,主要是用于占位
}
}
复制代码
....
....
EguanHelper.initEguan(this);
....
....
复制代码
至此,完成基于参数化配置,实现特定渠道下的易观集成的差异化构建。
四,结语
基于参数化配置实现差异化构建,需要依据实际的需求背景,分析具体的差异部分,以考虑简便易行,同时兼顾易维护性为主,实现具体的配置过程。
作者:HappyCorn
链接:https://juejin.im/post/5cc152f0e51d456e403772e9
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
Android Gradle基于参数化配置实现差异化构建的更多相关文章
- Gradle 差异化构建
Compile 默认的依赖方式,任何情况下都会依赖. Provided 只提供编译时依赖,打包时不会添加进去. Apk 只在打包Apk包时依赖,这个应该是比较少用到的. TestCompile 只在测 ...
- Android Gradle Plugin指南(六)——高级构建定制
原文地址:http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Advanced-Build-Customization ...
- 基于tomcat与Spring的实现差异化配置方案
起因 在实际开发过程中经常需要加载各种各样的配置文件..比如数据库的用户名密码,要加载的组件,bean等等..但是这种配置在各个环境中经常是不一样的....比如开发环境和测试环境,真实的生产环境.. ...
- Gradle系列之Android Gradle基础配置
原文发于微信公众号 jzman-blog,欢迎关注交流. 通过前面几篇文章学习了 Gradle 基础知识以及 Gradle 插件相关的知识,关于 Gradle 及其插件相关知识请先阅读下面几篇文章: ...
- Android Gradle使用总结
转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/77678577 本文出自[赵彦军的博客] 其他 Groovy 使用完全解析 http ...
- 读书笔记--Android Gradle权威指南(下)
前言 最近看了一本书<Android Gradle 权威指南>,收获挺多,就想着来记录一些读书笔记,方便后续查阅. 本篇内容是基于上一篇:读书笔记--Android Gradle权威指南( ...
- 【Gradle】Android Gradle 插件
Android Gradle 插件 Android Gradle 插件简介 从Gradle角度来看,Android其实是Gradle的一个第三方插件,它是由Google的Android团队开发的.但从 ...
- Gradle系列之Android Gradle插件
原文发于微信公众号 jzman-blog,欢迎关注交流. 通过前面几篇文章学习了 Gradle 基础知识以及 Gradle 插件相关的知识,关于 Gradle 及其插件相关知识请先阅读下面几篇文章: ...
- Android studio下gradle Robolectric单元测试配置
android studio下gradle Robolectric单元测试配置 1.Robolectric Robolectric是一个基于junit之上的单元测试框架.它并不依赖于Android提供 ...
随机推荐
- Windows 2003 Server 标准版启动问题解决(资源转贴)
维护的系统之一是部署在windows2003 Server标准版的服务器上,可能是由于某个应用问题,导致远程重启失败,害得我在机房呆了一早晨,可算是够折腾的.最后按照官方文档解决,刚放文档地址是:ht ...
- Python 30分钟入门指南
Python 30分钟入门指南 为什么 OIer 要学 Python? Python 语言特性简洁明了,使用 Python 写测试数据生成器和对拍器,比编写 C++ 事半功倍. Python 学习成本 ...
- Dubbo分布式服务框架入门使用
概念: Provider 暴露服务方称之为"服务提供者". Consumer 调用远程服务方称之为"服务消费者". Registry 服务注册与发现的中心目录服 ...
- D3中的each() 以及svg defs元素 clipPath的使用
each() 方法允许我们定制对选择集中DOM元素的处理行为: selection . each ( func ) 参数 func 是调用者定义的函数,在d3中被称为 访问器/accessor . d ...
- Django入门四之数据库相关
1. 数据库设置 在settings.py中配置数据库 我首先使用的是sqlite3,所以配置如下 2. 数据库的数据结构定义 #blog/models.py #定义了一个表(Student),表里两 ...
- Tomcat和JavaWeb目录和流程
Tomcat主要目录结构 bin 二进制可执行文件,包含启动和关闭tomcat文件 conf 配置文件,其中包含了server.xml.context.xml.web.xml等 webapps 存 ...
- This 在构造函数中的固定用法
class Person{ String name; int age; char gender; public Person (String name){ this.name = name; } pu ...
- 第一章 初识数据库Mysql
初识数据库Mysql(my) 在企业中 percona: 一.数据库基础知识 Mysql是一个开放源代码的数据库管理系统(DBMS),它是由Mysql AB公司开发.发布并支持的.Mysql是一个 ...
- python 匿名函数与三元运算
匿名函数 匿名函数就是不需要显示式的指定函数名 首先看一行代码: def calc(x,y): return x*y print(calc(2,3)) # 换成匿名函数 calc = lambda x ...
- Linux集群服务 LVS
linux虚拟服务器(LVS)项目在linux操作系统上提供了最常见的负载均衡软件. 集群定义: 集群(cluster)技术是一种较新的技术,通过集群技术,可以在付出较低成本的情况下获得在性能.可靠性 ...