Android + Gradle 代码自动选择编译

需求背景:

因华为市场的邀请,我们App可以获取与其联运的机会,即在华为市场首页的推广页放我们App的下载入口。

前提:

但合作的前提是,我们不能接入其它的第三方支付,必须得使用华为的支付,并且在进行包检测的时候,也不能发现其它的支付依赖包。

可选方案:

1. 切出一个新的分支,单独维护提供安装渠道包
2. 依然维护一个分支,通过gradle脚本进行打包编译干预

方案可行性对比

1. 方案:的确可以快速解决这个问题,给华为单独提供渠道包,并且可以决定哪些应该打入到安装包中,哪些资源不可以打入到其中。而其缺点在于,以后的维护成本特别高,
现在只有一个市场需要这么做,随着业务的推进,我们将会面监着两个分支公共代码的合并更新的问题。再退一步,如果后续有第二个,第三个联运业务时,我们将面临多分支代码的维护问题,因此这个方案实际上是不可行的,后果不可想象。
2. 方案:单独维护一个版本,但是需要编写gradle 脚本用来干预打包以及编译的过程,暂时的实现会比较的复杂,时间成本高一些,但对于后期的维护,一劳永逸。

所以:
方案一 保留==方案二==

最终的输出保证

1. 测试那边可以拿到全功能的打包产出文件,一个功能都不能落下
2. 每一个渠道包,至少可以保证拿到至少三种测试环境:
   ==开发环境,仿真环境,线上环境==
3. 不同的渠道包,我们可以干预其编译过程,可以自定义依赖。  
4. 保证产出的apk,除了一些日志收集,以及api domain不同,主要按测试与线上来区分,其它的任何都是要保持与release上线的一样。

Android的apk生成维度

大家知道,在apk产出构建的时候,有两个维度很重要
1. BuildType
2. Flavor

考虑到当前项目的历史原因

 项目中存在仅项目为release的BuildType时,才会执行热修复以及埋点功能在编译期的代码注入。而其它自定义的BuildType时,产出的apk不带有这种功能。
 所以为了保证产出,交付给测试的apk是全功能版本,BuildType这种路看来已经被堵死

api,以及一些服务器的domain这些都可以根据flavor来进行自动的区分编译,但是支付的代码块呢?依赖呢?

回到项目,这次的升级,改版,就拿支付宝来说吧,华为支付中带有自己的支付宝,而我们原来的项目中,也有自己的支付宝sdk,如何做到,在编译主版本时候,选择打入我们原有的支付宝依赖,而在华为渠道版本时候单独打入华为sdk的支付宝依赖?

当前的项目结构依赖如下

graph BT
libdependency-->libbase
libbase-->bizframework
bizframework-->compModuleA
bizframework-->compModuleB
bizframework-->compModuleC
bizframework-->app
IPay-->bizframework
IPayImplProxy-->IPay
HuaweiPay-->IPayImplProxy
NormalPay-->IPayImplProxy
ali_sdk_1.1.3-->HuaweiPay
ali_sdk_2.0.0-->NormalPay

IPay假如包含的方法:

/**
 支付初始化,以及发起支付接口
**/
public interface IPay{
    void init(Context context);
    void startPay(OrderBean orderInfo,IPayResultCallback callback);
}
/**
* 支付回调接口
**/
public interface IPayResultCallback{
    void onSuccess(PayResult info);
    void onError(int resultCode);
}
/**
支付代理类,上层调用
**/
public class IPayImplProxy implements IPay{
    public void init(Context context){
        
    }
    public void startPay(OrderBean orderInfo,IPayResultCallback callback){
        
    }
}
/**
  *ali_sdk_1.1.3 依赖的实现方案
**/
public class HuaweiPay implements IPay{
    public void init(Context context){
        
    }
    public void startPay(OrderBean orderInfo,IPayResultCallback callback){
        
    }
}

/**
  *ali_sdk_2.0.0 依赖的实现方案
**/
public class NormalPay implements IPay{
    public void init(Context context){
        
    }
    public void startPay(OrderBean orderInfo,IPayResultCallback callback){
        
    }
}

IPayImplProxy 这个代理类,在后面将会成为我们一个重要的部份。实际上对于上层的调用方来说,它们只关心的是我通过个代理,能初始化支付,发起支付,能知道支付的结果就行了。

回过头来,我们不得不介绍gradle上面的一个强大的功能,可以根据flavor来选择决定哪个文件夹下面的代码需添加到编译过程中。也就是sourceSet会因为flavor的变化而被自动的扩展。

我们正常的项目src目录如下
[图片上传失败...(image-7a776b-1542550505269)]

那么对于华为渠道来说,我们可以根据flavor,假设flavor的名称为huawei,于是我们可以如下方式添加华为渠道包的单独代码文件

[图片上传失败...(image-870e6b-1542550505269)]

对的,就是在src下面,创建我们的代码文件夹,区分我们的实现代码。同理也可以创建一个normal代码文件夹用来实现正常的大渠道包支付实现。这样不同渠道的支付代码做了隔离,打包时候根据flavor也进行了隔离。

但是,我们并没有解决sdk的依赖包的隔离,我们更想要的是不同的flavor也可以对依赖包进行选择,如:我们打huawei flavor时候,会选择ali_sdk_1.1.3;但是打normal时候,会选择ali_sdk_2.0.0进行依赖

这个怎么实现呢?那就是

1. app build.gradle 下面添加两个flavor ,huawei,normal 
2. 通过修改bizframework下面的build.gradle

app build.gradle 下面添加两个flavor ,huawei,normal

android{
    productFlavors{
       huawei{
           
       }
       normal{
           
       }
    }
}

通过修改bizframework下面的build.gradle
[图片上传失败...(image-feebb4-1542550505269)]

dependencies{
    huaweiApi('com.alibaba.pay:core-pay:1.1.3')
    normalApi('com.alibaba.pay:core-pay:2.0.0') 
}

最终实现的结构即如下所示:
在bizframework src文件夹下面分别创建huawei,normal 两个存放隔离的代码文件夹其中

huawei实现如下

/**
支付代理类,上层调用
**/
public class IPayImplProxy implements IPay{
    private HuaweiPay huaweiPay;
    public void init(Context context){
        huaweiPay=new HuaweiPay();
        huaweiPay.init(context);
    }
    public void startPay(OrderBean orderInfo,IPayResultCallback callback){
        if(huaweiPay!=null){
            huaweiPay.startPay(orderInfo,callback);
        }else{
            //提示需要初始化
        }
    }
}
/**
  *ali_sdk_1.1.3 依赖的实现方案
**/
public class HuaweiPay implements IPay{
    public void init(Context context){
        
    }
    public void startPay(OrderBean orderInfo,IPayResultCallback callback){
        
    }
}

normal实现如下

/**
支付代理类,上层调用
**/
public class IPayImplProxy implements IPay{
    private NormalPay normalPay;
    public void init(Context context){
        normalPay=new NormalPay();
        normalPay.init(context);
    }
    public void startPay(OrderBean orderInfo,IPayResultCallback callback){
        if(normalPay!=null){
           normalPay.startPay(orderInfo,callback);
        }else{
            //提示需要初始化
        }
    }
}
/**
  *ali_sdk_2.0.0 依赖的实现方案
**/
public class NormalPay implements IPay{
    public void init(Context context){
        
    }
    public void startPay(OrderBean orderInfo,IPayResultCallback callback){
        
    }
}

Application 中初始化支付sdk大致代码如下

public class CoreApplication extends Application{
    private IPayImplProxy payProxy;
    private void initPaySdk(){
        payProxy=new IPayImplProxy();
        payProxy.init(this);
    }
}

当你完成了上诉的流程构建,很高兴的告诉你,你实现了不同flavor的代码构建隔离,包括依赖包的隔离。

思考

1. 每新增一个flavor,我们还需要在src下面为其单独创建一份独立代码即使与当前normal文件夹下面代码一致
2. 如果这些差分代码需要调整,flavor较多情况,我们需要同时修改差分文件夹下面的好几份.(后续考虑解决)
3. gitbub 后续补充代码,今天尝试....

你可能感兴趣的:(Android + Gradle 代码自动选择编译)