zoukankan      html  css  js  c++  java
  • 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,将易观形成独立模块,AndroidManifestlibs目录下的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
    来源:掘金
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 相关阅读:
    Oracle工具的探索之旅(一)
    对ODB管理工具(EM,SQL Plus,Net Manager,Net Configuration Assistant,Administration Assistant for Windows,Database Configuration Assistant......)的简单认识
    偶然发现的VS2010的调试Watch查看也有F11的调试功能
    安装和卸载Oracle 10g数据库
    对Oracle的初步了解
    Oracle工具的探索之旅(二)
    对Oracle的初步认识
    [HDL]4/8/16/32/64位乘法器的设计(转)
    用ASP.NET WebForm的FileUpload控件上传文件
    C#图片和byte[]的互相转换
  • 原文地址:https://www.cnblogs.com/lwbqqyumidi/p/10771289.html
Copyright © 2011-2022 走看看