Android多渠道打包(定制化马甲包)

1、为什么要进行多渠道打包?

安卓应用商店(一个商店也叫做一个渠道,如豌豆荚,360手机助手,应用宝)众多,大大小小几百个,每当我们发新版本时,需要将Android客户端分发到各个应用市场,为了统计这些市场的效果(下载量、活跃数等),需要有一种方法来唯一标识它们,所以才有了多渠道打包。

2、如何统计各个渠道的下载量、活跃数?

现在有比较成熟的第三方应用帮我们实现统计功能(比如友盟),统计的本质就是收集用户信息传输到后台,后台生成报表,帮助我们跟踪分析并完善app。通过android系统的方法已经可以获取到引用版本号,版本名称,系统版本,机型等各种信息,唯独应用商店(渠道)的信息我们是没有办法从系统获取到的,所以我们就人为的在apk里面添加渠道信息(其实就用一个字段进行标识,如wandoujia360yingyongbao),我们只要把这些信息打包到apk文件并将信息传输到后台,后台根据这个标识,可以统计各个渠道的下载量了。
多渠道打包只需要关注两件事情:

    1. 将渠道信息写入apk文件
    1. 将apk中的渠道信息传输到统计后台

3、使用Gradle进行多渠道批量打包**

  1. 通常都是在在AndroidManifest.xml中加入渠道区分标识写入一个meta标签:

    <meta-data   
       android:name="channel"    
       android:value="${channel}" 
    />
    
  2. 在app目录下在build.gradle中配置productFlavors添加如下代码:

    productFlavors {
        qihu360 {} // 360手机助手
        yingyongbao {} // 腾讯应用宝
        wandoujia {} // 豌豆荚
        baidu {} // 百度手机助手
        miui {} // 小米
        flyme {} // 魅族
        lenovo {} // 联想-乐商店
        oppo {} // Oppo-可可软件商店
        huawei {} // 华为
        vivo {} // vivo
        hiapk {} // 安卓市场
        sj91 {} // 91手机助手
        sogou {} // 搜狗手机市场
        sohu {} // 搜狐应用中心
        taobao {} // 淘宝手机助手
        gfan {} // 机锋
        appchina {} // 应用汇
        mumayi {} // 木蚂蚁
        wangyi163 {} // 网易应用
        nduoa {} // N多市场
        mm10086 {} // MM商城-中国移动
        wostore {} // WO商店
        youyi {} // 优异
        uc {} // UC+开发平台
        anzhi {} // 安智市场
        google {} // google play
        amazon {} // 亚马逊
    }
    productFlavors.all {
        flavor -> flavor.manifestPlaceholders = [channel: name]
    }
    

    AndroidStudio的Build -> Generate signed apk打签名包时即可选择设置渠道:

    Paste_Image.png

  3. 在代码中获取渠道信息:

public static String getFlavorChannel(Context context) {
        try {
            PackageManager pm = context.getPackageManager();
            ApplicationInfo appInfo = pm.getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA);
            return appInfo.metaData.getString("channel");
        } catch (PackageManager.NameNotFoundException ignored) {
        }
        return "";
    }
  1. 在android studio中测试不同渠道的apk。
Paste_Image.png

4.APP定制渠道包(马甲包)

在App的开发过程中,经常会遇到产品或者运营的同事提出要制作马甲包的需求;马甲包简单来说就是原APP的小号,与原APP包除了包名,应用名称、图标等给用户加以区分的东西,其他功能基本不变亦或者只采用原App的部分功能的APP包。

  1. ApplicationId,版本号
    Android 应用都有自己的包名。包名是设备上每个应用程序的唯一标识,同样也是在各个下载平台的唯一标识。就是说,假如你已经使用某个包名来发布应用,就不能再去改变应用的包名,因为这样做会导致你的应用被视为一个全新的应用,你现有的用户也不会收到应用的更新通知。
    随着渠道越来越多,不同渠道对应用的要求也不尽相同。有时候我们需要发布不同的版本,例如 prohd 版本,支持用户可以下载安装不同的版本。那么我们需要设置不同的ApplicationId和对应的版本号, 同时要与 PackageName 解耦合。
  • 代码中引用的 R 类要保持不变;
  • 在构建不同版本的应用时,对应的(引用了 R 的) .java 源文件也不能改动。

那么我们只需要在productFlavors对应的渠道中指定applicationIdversionCodeversionName,例我们指定GooglePlayapplicationId:

 productFlavors {
        GooglePlay {
            //指定这个渠道的版本号
            versionCode 2
            versionName "1.2"
            //指定区别于其他渠道的 applicationId
            applicationId "com.liujc.androidtools.hd"
        } 
        yingyongbao {} // 腾讯应用宝
        wandoujia {} // 豌豆荚
        baidu {} // 百度手机助手
        miui {} // 小米
        //其他...
    }
  1. BuildConfig
    Gradle会在generateSources阶段为flavor生成一个BuildConfig.java文件。BuildConfig类默认提供了一些常量字段,比如应用的版本名(VERSION_NAME),应用的包名(PACKAGE_NAME)等。更强大的是,开发者还可以添加自定义的一些字段。下面的示例假设debug版开启LOG功能,使用debug的api,而release版则使用不开启LOG和使用release时的api:
    buildTypes {
        debug {
            // debug模式下,显示log
            buildConfigField("boolean", "LOG_DEBUG", "true")
            buildConfigField ("String", "API_HOST", "\"http://api.test.com\"")//debug API Host
        }
        release {
            // release模式下,不显示log
            buildConfigField("boolean", "LOG_DEBUG", "false")
            buildConfigField("String", "API_HOST", "\"http://api.release.com\"")//release API Host
        }
    }
    
    那么代码中就可以使用 BuildConfig.LOG_DEBUG 和 BuildConfig.API_HOST 了。
    备注: 这里简单介绍下buildConfigField 方法,可以发现其有三个参数:
    /**
     * Adds a new field to the generated BuildConfig class.
     *
     * <p>The field is generated as: {@code <type> <name> = <value>;}
     *
     * <p>This means each of these must have valid Java content. If the type is a String, then the
     * value should include quotes.
     *
     * @param type the type of the field
     * @param name the name of the field
     * @param value the value of the field
     */
    public void buildConfigField(
            @NonNull String type,
            @NonNull String name,
            @NonNull String value)
    
    String type 要创建的字段类型 如上面的String与boolean
    String name 要创建的字段名 如上面的API_HOST与LOG_DEBUG
    String value 创建此字段的值 如上面的"\"http://api.release.com\""与"true"
    但这里要注意一点就是,当创建的类型为String时,定义value的时候要注意加上字符串不能缺少的双引号"",由于参数本身要传入的类型也是String,所以我们在添加的时候加上转义字符
  1. 控制是否自动更新
    一般应用在启动时都会默认检查客户端是否有更新,如果有更新就会提示用户下载。但是有些渠道和应用市场不允许这种默认行为,所以在适配这些渠道时需要禁止自动更新功能。
    解决的思路是提供一个配置字段,应用启动的时候检查该字段的值以决定是否开启自动更新功能。使用flavor可以完美的解决这类问题。甚至可以在productFlavors对应的渠道号进行区别,例如豌豆荚版默认禁止版本自动更新:

    android {
        defaultConfig {
            buildConfigField "boolean", "AUTO_UPDATES", "true"
        }
        productFlavors {
           wandoujia {
                buildConfigField "boolean", "AUTO_UPDATES", "false"
           }        
        }
    }
    
  2. 多渠道资源文件定制
      客户端经常会和一些应用分发市场合作,需要在应用的启动界面中加上第三方市场的Logo,类似这类适配形式还有很多。通常对于不同渠道,我们会区别不同的资源。例如我们一款应用需要在360发布,而应用图标和欢迎界面要一个360标志的图或者应用名称和其他渠道不同,那么这个时候就需要按渠道打包对应的应用图标和欢迎图片以及应用名称了了。
      Gradle在构建应用时,会优先使用flavor所属dataSet中的同名资源。所以,在flavor的dataSet中添加同名的字符串资源,以覆盖默认的资源。上面我们已经有针对360的渠道了,就是qihu360,我们只需要在app/src/目录下添加渠道对应的文件夹qihu360,然后覆盖对应要覆盖的内容。下面是定制应用图标的步骤:

  • 添加qihu360文件夹,那么在 app/src/目录下面就有 main , androidTest , qihu360,test这四个文件夹了。main 目录是通用正常渠道包目录,qihu360是我们需要定制资源的渠道包目录。如下图:
    Paste_Image.png
  • 并添加如下应用名字符串资源src/qihu360/res/values/strings.xml:
      <resources>    
      <string name="app_name">360MultiChannelBuild</string>
      </resources>
    
    默认的应用名字符串资源如下(src/main/res/values/strings.xml):
    <resources>    
      <string name="app_name">MultiChannelBuild</string>
    </resources>
    
    最后运行360版本的app即应用名称显示成360MultiChannelBuild。
    通过以上例也可以定制其他资源,包括drawablestyles.xml甚至AndroidManifest.xml也都是可以的。即可实现不同渠道不同的应用显示。
  1. 使用第三方SDK
    某些渠道会要求客户端嵌入第三方SDK来满足特定的适配需求。问题的难点在于如何只为特定的渠道添加SDK,其他渠道不引入该SDK。使用flavor可以很好的解决这个问题,下面以为qihu360flavor引入com.qihoo360.union.sdk:union:1.0
    SDK为例进行说明:
android {
    productFlavors {
        qihu360 {
        }
    }
}
...
dependencies {
    //参与编译但不参与打包
    provided 'com.qihoo360.union.sdk:union:1.0'
    //指定qihu360这个渠道可以打包这个库
    qihu360Compile 'com.qihoo360.union.sdk:union:1.0'
}

上例添加了名为qihu360的flavor,并且指定编译和运行时都依赖com.qihoo360.union.sdk:union:1.0。而其他渠道只是在构建的时候依赖该SDK,打包的时候并不会添加它。
接下来,需要在代码中使用反射技术判断应用程序是否添加了该SDK,从而决定是否要显示360 SDK提供的精品应用。部分代码如下:

class MyActivity extends Activity {
    private boolean useQihuSdk;

    @override
    public void onCreate(Bundle savedInstanceState) {
        try {
            Class.forName("com.qihoo360.union.sdk.UnionManager");
            useQihuSdk = true;
        } catch (ClassNotFoundException ignored) {

        }
    }
}

最后打包运行即可生成包含360精品应用模块的渠道包了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260

推荐阅读更多精彩内容