Android组件化架构 - 8. 多渠道打包

  • 一个apk包也可以发布到多个市场,为什么需要多渠道?

    当哪个渠道需要统计用户多少,用户粘性,需要更加个性化设计时,我们需要在apk中添加渠道信息以区分不同市场;

  • Android的两种签名方式

    1. Android7.0以前,使用V1签名方式,是jar signature,源自于JDK;
    2. Android7.0之后,使用V2签名方式,是Android独有的apk signature;
    • v1方式7.0前后都可用,v2方式7.0以下会安装失败,Android Studio可以同时选择两种签名方式(一个apk中共存,根据手机系统版本自动选择);
  • 多渠道打包的几种实现方式

  1. python脚本
1. 配置python环境
2. git clone https://github.com/GavinCT/AndroidMultiChannelBuildTool.git
3.  info目录下的channel用来存放渠道,多个渠道之间用换行隔开;
    MultiChannelBuildTool.py是多渠道打包的脚本;
    ChannelUtil.java用来解析渠道,直接拷贝到Android工程中使用即可;
- 本质就是修改apk压缩包,将渠道信息写入META_INF中
  1. Android官方(gradle配置)
1. AndroidMainfest.xml中加入渠道区分标识
  <meta-data android:name="channel" android:value="${channel}"/>
2. app module的build.gradle中配置 productFlavors,
    flavorDimensions "default"
    productFlavors {
        qihu360 {
        }
        yingyongbao {
        }
        baidu {
        }
        huawei {
        }
        xiaomi {
        }
    }
    productFlavors.all {
        flavor -> flavor.manifestPlaceholders = [channelName: name]
    }
//但是不得不说这个是真的慢~慢~慢~~
  1. 美团walle
  • github地址: https://github.com/Meituan-Dianping/walle
1. 配置build.gradle
buildscript {
    dependencies {
        classpath 'com.meituan.android.walle:plugin:1.1.7'
    }
}

apply plugin: 'walle'
dependencies {
    compile 'com.meituan.android.walle:library:1.1.7'
}

2. 配置插件
walle {
    // 指定渠道包的输出路径
    apkOutputFolder = new File("${project.buildDir}/outputs/channels");

    // 定制渠道包的APK的文件名称
    apkFileNameFormat = '${appName}-${packageName}-${channel}-${buildType}-v${versionName}-${versionCode}-${buildTime}.apk';
    //     projectName - 项目名字
    //     appName - App模块名字
    //     packageName - applicationId (App包名packageName)
    //     buildType - buildType (release/debug等)
    //     channel - channel名称 (对应渠道打包中的渠道名字)
    //     versionName - versionName (显示用的版本号)
    //     versionCode - versionCode (内部版本号)
    //     buildTime - buildTime (编译构建日期时间)
    //     fileSHA1 - fileSHA1 (最终APK文件的SHA1哈希值)
    //     flavorName - 编译构建 productFlavors 名

    // 渠道配置文件
    channelFile = new File("${project.getProjectDir()}/channel")
}

3. 获取渠道信息
String channel = WalleChannelReader.getChannel(getApplicationContext());
LjyToastUtil.toast(mContext, "当前渠道:" + channel);
  • 组件化中的多渠道

当需要生成用户端和管理端,或者个性化深度定制的VIP app时,又或者某些版本不需要微信支付,分享等功能,也就没有必要嵌入这些模块,
这样可以减少业务量和包容量;

android{
    flavorDimensions "jin"
    productFlavors {
        higher {
            applicationId "com.ljy.publicdemo"
            minSdkVersion 26
            buildConfigField 'boolean', 'isLite', "false"
            resValue "string", "app_name_new", "JinDemo"
            manifestPlaceholders = [
                    app_icon: "@mipmap/ic_launcher_normal",
                    channelName: "higher",
                    verNum:"2"
            ]
        }

        lower {
            applicationId "com.ljy.publicdemo.lite"
            minSdkVersion 17
            buildConfigField 'boolean', 'isLite', "true"
            resValue "string", "app_name_new", "JinDemoLite"
            manifestPlaceholders = [
                    app_icon: "@mipmap/ic_launcher_lite",
                    channelName: "lower",
                    verNum:"1"
            ]
        }
    }

}
dependencies {
    ...
    lowerImplementation project(':lower_setting')
    higherImplementation project(':heigher_setting')
}

通过productFlavors属性来设置多渠道,manifestPlaceholders中可以设置不同渠道中的不同属性,这些属性要在AndroidManifest中声明才能使用;
<!-- 渠道声明-->
<meta-data android:name="channel" android:value="${channelName}"/>
<!-- 版本声明-->
<meta-data android:name="ver" android:value="${verNum}"/>
通过xxxImplementation 来配置不同渠道需要引用的module

//获取meta-data中的渠道号等信息
/**
 * @Author: LiuJinYang
 * 获取meta-data工具类
 */
public class AppMetaUtil {
    public static String channelNum = "";

    /**
     * 获取meta-data值
     * @param context 上下文对象
     * @param metaName metaData key
     * @return metaData值
     */
    public static Object getMetaData(Context context, String metaName) {
        Object obj = null;
        try {
            if (context != null) {
                String pkgName = context.getPackageName();
                ApplicationInfo appInfo = context.getPackageManager()
                        .getApplicationInfo(pkgName, PackageManager.GET_META_DATA);
                obj = appInfo.metaData.get(metaName);
            }
        } catch (PackageManager.NameNotFoundException e) {
            LjyLogUtil.e(e.getMessage());
        }
        return obj;
    }

    /**
     * 获取渠道号
     * @param context 上下文对象
     * @return 渠道号
     */
    public static String getChannelNum(Context context){
        if (TextUtils.isEmpty(channelNum)){
            Object obj=AppMetaUtil.getMetaData(context,"channel");
            if (obj!=null&&obj instanceof String){
                channelNum=(String) obj;
            }
        }
        return channelNum;
    }
}

我是今阳,如果想要进阶和了解更多的干货,欢迎关注公众号”今阳说“接收我的最新文章

猜你喜欢

转载自blog.csdn.net/o118abcdef/article/details/111879871