Android工程中共主线差异化打包方案说明/差异化打包/多渠道打包

背景

理由很简单: 有这样一个需求,一个维护很久了的项目,不断更新迭代,突然有一天产品说我们要做产品的换肤,但是旧版本还接着用,. 产品的一句话,内心真是一百万草泥马呼啸而过,. 根据我多年的偷懒和采坑经验,接到需求的我立马意识到后期至少要有以下几个问题(坑):
坑一 : 新版本可能不是单纯的改改xml或者切图文件就能完成换肤的,估计会有小的逻辑改动.甚至大的,
坑二 : 新旧两个版本后期可能会同步更新,如果采用版本工具新建分支,岂不是要维护两套代码太恶心了
坑三 : 如果出现多渠道打包 , 如果新 旧版本更新功能不同步, 对于日里万行(不要问我李万航是谁)代码的程序员们来说, 用不了多久,新旧两个项目就已经忘了 上个版本改了几个地方实现的某个变态的需求了.

废话太多了直接开始.

开始

等等 开始之前先介绍一下多渠道打包

多渠道打包 顾名思义 ,就是一套代码放在多个推广渠道上,但是在统计的时候,要知道哪个渠道推广效果好 ,所以这就需要对不同的APK 加上不同的标识. 大家最常用的可能就是友盟统计,当然你也可以自己撸,不拦着, 这里已友盟统计来做举例,简单介绍一下::

1.注册友盟账号, 创建应用,下载SDK,配置项目

这些就不赘述了,直接去找友盟开发文档就OK了

2. Manifest配置

在友盟的使用时 有一条是 Manifest的配置, 为了区分渠道我们会配置不同的Value 然后分别打包

        <meta-data
            android:name="UMENG_CHANNEL"
            android:value="wandoujia" />
3. Manifest配置(升级)

俗话说: 不会偷懒的程序员不是好的CV搬运工 所以我们会借助gradle 方式来进行多渠道配置,然后一次性打包多个不同渠道的APK

        <meta-data
            android:name="UMENG_CHANNEL"
            android:value="${CHANNEL}" />
// 多渠道打包 
 flavorDimensions "company" 
 productFlavors { 
      wandoujia {
          manifestPlaceholders = [CHANNEL: "wandoujia"]
      }
      baidu {
          manifestPlaceholders = [CHANNEL: "baidu"]
      } 
      c360 {
          manifestPlaceholders = [CHANNEL: "c360"]
      } 
      uc {
          manifestPlaceholders = [CHANNEL: "uc"]
      } 
  }
4. 差异化开发

思考: 既然一套代码,通过多渠道方式能打包出,不同UMENG_CHANNEL 友盟标记的APK ,那可不可以通过这种方式做更多代码的区分呢
答案: 可以 ,要不 我还说个毛啊
方案: 与多渠道打包方式相似,也许gradle 的配合 (gradle 这是个好东西啊)

4.1 gradle 配置

借助 gradle 配置两个不同的渠道(productFlavors 风味风情 ) A和B, 在不同渠道配置 应用名(app_name) , 进程ID( applicationId ) ,软件版本 (versionName ) 和 渠道标识(CHANNEL )

 flavorDimensions "company" 
 productFlavors { 
      productA{
          dimension "company"
                resValue "string", "app_name", "channel_A"
                applicationId "com.example.a"
                versionName "1.0.0.1"
                manifestPlaceholders = [CHANNEL : "productA",
                                        app_icon: "@mipmap/ic_laun"]
      }
      bproductB {
          dimension "company"
                resValue "string", "app_name", "channel_A"
                applicationId "com.example.a"
                versionName "1.0.0.1"
                manifestPlaceholders = [CHANNEL : "productA",
                                        app_icon: "@mipmap/ic_laun"]
      } 
  }
4.2 AndroidManifest 配置

说明 label 不采用引用的方式 也可以生效, 读者可以亲测下

  <application
        android:icon="${app_icon}"
        android:label="@string/app_name"
        <activity android:name="----" />
        <meta-data
            android:name="UMENG_CHANNEL"
            android:value="${CHANNEL}" />
    </application>
4.3 创建渠道包 (重点)

用AS 在你新建项目的时候 ,AS会帮我们创建三个不同的工程, main工程 androidTest工程 和test工程 . 我们进行单元测试的时候会发现 , main工程的方法我们是可以调用的, 所以

  • 首先,跟这个三个工程 同级目录再新建两个目录 即: productA 和productB ,这里名称必须与gradle内 productFlavors 的渠道名相同 ,
  • 然后,在 productA 和 productB 是可以有自己的 java 目录 res目录 甚至 AndroidManifest.xml的, 然后开始创建这些目录就可以了
  • 接着: 在 productA 和 productB 两个工程 的java目录里创建包名 例如 com.example, 记住两个工程的包名要相同但与main包名不同
  • 接着: 在 productA 和 productB 的包名下再创建相同名的activity(也可以不同,因为我的需求是换肤,所以是activity要相同,xml不同即可) ,

文字描述太苍白直接上图
在这里插入图片描述

再次强调

  1. productA 和productB 工程名必须与gradle内 productFlavors 的渠道名相同
  2. productA 和productB 与main 工程目录是同级的
  3. productA 和productB 必须至少有一个相同的包名
  4. productA 和productB 相同包名下 必须至少有一个相同的类, 目的显而易见,就是给main工程一个相同的入口,不同的实现
    5 productA 和 productB 不能与main的 四大组件和res资源 的名称相同 否自会报错
  • 继续 不同皮肤的页面在两个项目里 做不同的实现 例如上图的 两个 TwoActivity
package com.example;

import android.util.Log;
import android.view.View;
import android.widget.Toast;

import com.zhf.lib_statusbar.BaseBarBlackActivity;
import com.zhf.module_channel.R;
// productA 工程代码 
public class TwoActivity extends BaseBarBlackActivity {

    @Override
    protected int setContentResouceId() {
        return R.layout.activity_two;
    }

    @Override
    protected void initView() {
        super.initView();
        tvCentre.setText("A/OneActivity");
        findViewById(R.id.textView).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        super.onClick(v);
        Log.i(">>>>>>>", "我来自分支A");
        Toast.makeText(mContext, "我来自分支A", Toast.LENGTH_SHORT).show();
    }
}
package com.example;

import android.util.Log;
import android.view.View;
import android.widget.Toast;

import com.zhf.lib_statusbar.BaseBarBlackActivity;
import com.zhf.module_channel.R;
// productB 工程代码 
public class TwoActivity extends BaseBarBlackActivity {

    @Override
    protected int setContentResouceId() {
        return R.layout.activity_two;
    }

    @Override
    protected void initView() {
        super.initView();
        tvCentre.setText("B/OneActivity");
        findViewById(R.id.textView).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        super.onClick(v);
        Log.i(">>>>>>>", "我来自分支B");
        Toast.makeText(mContext, "我来自分支B", Toast.LENGTH_SHORT).show();
    }
}

  • 继续 在main项目中打开 TwoActivity 下面代码特别把 导包也贴上了, 发现 可以直接导包就行了 import com.example.TwoActivity; 而且在代码里不用做区分 A或者B .
package com.zhf.module_channel;

import android.content.Intent;
import android.view.View;

import com.alibaba.android.arouter.facade.annotation.Route;
import com.example.TwoActivity;
import com.zhf.lib_statusbar.BaseBarBlackActivity;

@Route(path = "/channel/ChannelActivity")
public class ChannelActivity extends BaseBarBlackActivity {
    @Override
    protected int setContentResouceId() {
        return R.layout.activity_channel;
    }

    @Override
    protected void initView() {
        super.initView();
        tvCentre.setText("/channel/ChannelActivity");
        findViewById(R.id.tv_text).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        super.onClick(v);
        if (v.getId() == R.id.tv_text) {
            Intent intent = new Intent();
            intent.setClass(this, TwoActivity.class);
            startActivity(intent);
        }
    }
}

  • 最后 直接运行打包就可以了

补充 : 如果想单独调试 productA 直接在gradle 注释掉其他的只留productA就行了, productB 同理

参考文献:
https://www.jianshu.com/p/552c8f5ce203
https://www.cnblogs.com/charles04/p/9017501.html
https://blog.csdn.net/mingtiannihao0522/article/details/78390365

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值