Android Gradle基于参数化配置实现差异化构建

简介: Android Gradle基于参数化配置实现差异化构建一、背景:项目中有一些特殊的需求,如个别渠道继承腾讯bugly,个别渠道集成易观统计,不同的渠道集成不同的推送策略(如Oppo渠道优先Opush推送),不同的渠道拥有不同的第三方登录集成等等。

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.mymoney;

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.mymoney.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文件中配置了不少的如、及其他元数据等配置项。
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, "4909454903452702a", "feidee");
    } 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
来源:掘金

相关文章
|
4天前
|
JavaScript Java Maven
云效产品使用常见问题之android sdk 构建出aar后,上传到私有maven仓库失败如何解决
云效作为一款全面覆盖研发全生命周期管理的云端效能平台,致力于帮助企业实现高效协同、敏捷研发和持续交付。本合集收集整理了用户在使用云效过程中遇到的常见问题,问题涉及项目创建与管理、需求规划与迭代、代码托管与版本控制、自动化测试、持续集成与发布等方面。
|
22天前
|
移动开发 Java Android开发
构建高效Android应用:探究Kotlin与Java的性能差异
【4月更文挑战第3天】在移动开发领域,性能优化一直是开发者关注的焦点。随着Kotlin的兴起,其在Android开发中的地位逐渐上升,但关于其与Java在性能方面的对比,尚无明确共识。本文通过深入分析并结合实际测试数据,探讨了Kotlin与Java在Android平台上的性能表现,揭示了在不同场景下两者的差异及其对应用性能的潜在影响,为开发者在选择编程语言时提供参考依据。
|
23天前
|
数据库 Android开发 开发者
构建高效Android应用:Kotlin协程的实践指南
【4月更文挑战第2天】随着移动应用开发的不断进步,开发者们寻求更流畅、高效的用户体验。在Android平台上,Kotlin语言凭借其简洁性和功能性赢得了开发社区的广泛支持。特别是Kotlin协程,作为一种轻量级的并发处理方案,使得异步编程变得更加简单和直观。本文将深入探讨Kotlin协程的核心概念、使用场景以及如何将其应用于Android开发中,以提高应用性能和响应能力。通过实际案例分析,我们将展示协程如何简化复杂任务,优化资源管理,并为最终用户提供更加流畅的体验。
|
24天前
|
Java Android开发 开发者
构建高效Android应用:Kotlin协程的实践与优化
在响应式编程范式日益盛行的今天,Kotlin协程作为一种轻量级的线程管理解决方案,为Android开发带来了性能和效率的双重提升。本文旨在探讨Kotlin协程的核心概念、实践方法及其在Android应用中的优化策略,帮助开发者构建更加流畅和高效的应用程序。通过深入分析协程的原理与应用场景,结合实际案例,本文将指导读者如何优雅地解决异步任务处理,避免阻塞UI线程,从而优化用户体验。
|
1天前
|
数据库 Android开发 开发者
安卓应用开发:构建高效用户界面的策略
【4月更文挑战第24天】 在竞争激烈的移动应用市场中,一个流畅且响应迅速的用户界面(UI)是吸引和保留用户的关键。针对安卓平台,开发者面临着多样化的设备和系统版本,这增加了构建高效UI的复杂性。本文将深入分析安卓平台上构建高效用户界面的最佳实践,包括布局优化、资源管理和绘制性能的考量,旨在为开发者提供实用的技术指南,帮助他们创建更流畅的用户体验。
|
1天前
|
移动开发 Java Android开发
构建高效Android应用:采用Kotlin协程优化网络请求
【4月更文挑战第24天】 在移动开发领域,尤其是对于Android平台而言,网络请求是一个不可或缺的功能。然而,随着用户对应用响应速度和稳定性要求的不断提高,传统的异步处理方式如回调地狱和RxJava已逐渐显示出局限性。本文将探讨如何利用Kotlin协程来简化异步代码,提升网络请求的效率和可读性。我们将深入分析协程的原理,并通过一个实际案例展示如何在Android应用中集成和优化网络请求。
|
1天前
|
调度 Android开发 开发者
构建高效Android应用:探究Kotlin协程的优势与实践
【4月更文挑战第24天】随着移动开发技术的不断演进,提升应用性能和用户体验已成为开发者的核心任务。在Android平台上,Kotlin语言凭借其简洁性和功能性成为主流选择之一。特别是Kotlin的协程功能,它为异步编程提供了一种轻量级的解决方案,使得处理并发任务更加高效和简洁。本文将深入探讨Kotlin协程在Android开发中的应用,通过实际案例分析协程如何优化应用性能,以及如何在项目中实现协程。
|
2天前
|
Android开发
Android构建系统:Android.mk(2)函数详解
Android构建系统:Android.mk(2)函数详解
11 1
|
2天前
|
运维 网络协议 Linux
Android 双网卡配置为连接到Android主机的PC提供外网访问(1)
Android 双网卡配置为连接到Android主机的PC提供外网访问(1)
14 0
|
3天前
|
Android开发
Android 动态修改参数配置
Android 动态修改参数配置
11 0