Android打包(二)

综合技术 2018-05-18 阅读原文

之前我有讲过一篇打包 https://www.jianshu.com/p/cef6dbfb68dc ,但是讲真这也只是大概的了解一个打包的过程和怎样使用美团的框架进行很多个渠道的快速打包。但是真正的实际开发中的多渠道打包情况肯定不会这么简单,如果你的打包仅仅这么简单,那可能说明你的项目有点Low。

一.一些重要的概念

讲之前我想先回顾和补充一些重要的概念,首先上一篇说过buildTypes就是构建的类型,一般有debug和release,我个人是没在这里面定义过除了这两个以外其他的,然后就是productFlavors,这个叫做产品配料的就是放我们的渠道包,也就是说每个渠道包可以称为 flavor

然后还有一个比较重要的概念是 BuildVariant ,平时叫它构建变体,这名字是感觉怪怪的,我个人认为每一个最终产出的包就是一个变体,每个变体称为 Variant ,构建变体就是把配置变成最终包的过程。

比如说我这里自己写的:

buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
        debug{

        }
    }
    productFlavors {
        main {

        }
        baidu {
            applicationId 'com.example.kylin.fristtest.one'
            buildConfigField 'Class','INTENT_TEST','TwoActivity.class'
        }
        ali {
            applicationId 'com.example.kylin.fristtest.two'
            buildConfigField 'Class','INTENT_TEST','AliActivity.class'
        }
    }

(1)flavor有默认的main,还有baidu和ali

(2)变体可以在AS中查看,我这里就产生了6个变体

这样讲或许你就能大概清楚生成渠道包是一个怎样的过程,但除了这些简单的操作之外,还有一个 维度 的概念。

这里就涉及到一个重要的属性**flavorDimensions **,这个属性可以设置维度,例如

flavorDimensions "one", "tow"
    productFlavors {
        main {
            dimension "one"
        }
        baidu {
            applicationId 'com.example.kylin.fristtest.one'
            buildConfigField 'Class','INTENT_TEST','TwoActivity.class'
            dimension "one"
        }
        ali {
            applicationId 'com.example.kylin.fristtest.two'
            buildConfigField 'Class','INTENT_TEST','AliActivity.class'
            dimension "one"
        }
        tengxun{
            dimension "tow"
        }
        xiaomi{
            dimension "tow"
        }
    }

这时看看所有的变体

可以看出两个不同的维度的flavor会合在一起,这样就一共有12个variant,即2type * 3flavorone * 2flavortwo。因为我也没碰到过有使用这种场景的情况,所以我这里只能先介绍,详细的只能等我碰到后再写。

二.个性化定制

在上一篇,我写过,如果两个包有不一样的内容的话怎么办,上一篇我的做法是在Gradle里面用buildConfigField定义一个变量,然后再实际代码中再做判断来设置不同的情况,但是想想,如果包很多,或者每个包之间有很多东西都不同,那你的一个项目中就有很多的判断和所有包的资源全都放到一个包中,这样做就很LOW

所以才有了个性化的定制,要解决上面我说的问题,Gradle就能解决。我们都知道Android的编译是通过Gradle来进行的,也就是说。我们写的代码+gradle的配置最终能得出apk,那想想,我们是不是可以在Gradle中设置编译哪些内容,舍弃哪些内容。

关于gradle的操作,我这里就不说了,过后会单独写文章,这里只需要告诉你,做个性化的定制就可以, 也就是我们可以为每一个包在src文件夹下创建一个与包名相同的文件夹,然后文件夹的目录和main的一样,这样gradle会根据一些规则去构建不同包的应用。

那么是什么规则呢,据我所知是这样的(这里我不能保证是对的,如果有错还望指出):

(1)两个包的manifest清单会进行合并。

(2)res目录资源文件会对原包的进行覆盖

(3)java代码会合并

说了这么多,还是要举个栗子才能说明这个过程,例如我这里想个性化定制两个包baidu和ali。

1.首先在gradle中定义flavors

productFlavors {
        main {
        }
        baidu {
            applicationId 'com.example.kylin.fristtest.one'
        }
        ali {
            applicationId 'com.example.kylin.fristtest.two'
        }
    }

设置不同的applicationId 是为了能同时装上所有包,这里注意一下,要为所有包统一设置版本

2.创建个性化文件夹

上面说了,要为个性化的渠道创建和main目录结构一样的文件夹,我不知道大神们是怎样快速创建的,我自己是复制粘贴,先弄个empty渠道文件

这个文件的结构和main一样,然后复制到src文件夹下,把名字改成渠道的名字。 我的做法是这样的,如果有大神知道更快的创建做法,还望指出。

完成这些操作后文件的目录变成

默认Main文件和两个渠道的文件,然后按照上面说的规则去为每个渠道做个性化的操作。

3.更改包名

我们做个简单的操作,先更改资源文件中的包名,baidu包的给改了,ali包的不动

打开百度包的

然后要讲讲运行,我怎样去run对应的渠道包呢,两种方法,第一种是在gradle中设置sourceSets来指定路径,这个先不说,讲到gradle的时候再讲,第二种就是androidstudio帮我们做好的,在这里选

先运行ali的包

看到名字没变,还是默认包的app_name,再运行baidu的看看

可以看到app_name已经变成我们在baidu包中的res中定义的app_name。

4.为特定包创建新的类

刚才的栗子太简单,不够过瘾,我们在搞一个更骚的栗子。比如说我现在默认情况下不是有个textview嘛,我想在ali包中点textview会跳转到一个AliActivity,这个AliActivity只在阿里包中被定义和注册。然后再baidu包中点击textview就是做默认的操作。

这里先说说一个Android studio帮我们做的一个比较好的操作。

如果你在BuildVariant中选默认包的话

如果选baidu的话

如果选ali的话

我举这个例子的意思是说你想改哪个渠道包的东西,你最好是在BuildVariant中切换到那个渠道再改。

好,讲了这么多,我们在ali渠道创建个AliActivity并注册

然后在main包下的MainActivity中加入代码

一看这样确实没啥问题,但是当我此时切换到baidu渠道时

会发现AliActivity找不到这个类,想想也很正常,因为这个类是我们在ali的渠道的文件夹中创建注册的,baidu这个渠道的文件夹肯定没有。那么我们该怎么办,现在baidu这个包无法编译,没有AliActivity这个类这边编译不通过。

这时的思路肯定是这样,我要怎样才能在ali这个包中是跳转到AliActivity,而在其他包中就是默认的情况。Gradle能帮我们解决这个难题,所有和编译相关的问题都基本可以找Gradle来解决,我们可以在gralde不同的包中定义不同的类,然后至于跳转到哪里,让编译时进行选择

我在buildConfig定义一个class类型的变量INTENT_TEST,然后不同的渠道传入不同的值,最后在跳转中

Intent intent = new Intent(MainActivity.this,BuildConfig.INTENT_TEST);
startActivity(intent);

这样我们就能够实现在特定的渠道跳转到特定的页面,并且其他的渠道不会有这个页面的资源。这个功能还是比较骚的,比较极端,因为一般所有的渠道的页面基本都是不会有差异的,大部分都是一些资源上的差异。但是我举这个例子就是为了说明gradle的强大。

三.总结

首先肯定要理清楚flavor、Variant和多维的情况。

其次这篇文章主要是去写如何进行个性化定制,还为此举了一个很极端的栗子。

其他Gradle相关的内容我已经尽量过滤掉,不然一起讲的话就会很乱。

然后就是说说我最近的一个情况,我应该大概有一个月没有去更新博客了,其实这是因为我前段时间在之前的公司离职了,一直在找工作,之后也会写一篇关于Android的一些面试的知识点,我也不是三年经验的,所以可能写得不会很详细。

然后就是博客的一个更新的问题,我之前是没想过我会有被人关注,虽然相比大神来说这个关注量也不算多,但是既然有人认可我,那我就肯定不能像以前那么吊儿郎当,所以从下周开始我尽量对博客的更新平均在一周两更,毕竟还有工作,所以可能时间紧或者没素材的情况会发生,但是不管怎么样,我保证能做到至少没周一更,再有一点是我会尽量把gayhub给维护起来。还有就是可能我看我以前写的一些文章有时候也会觉得挺垃圾的,有可能会重写,但绝不会敷衍。最后谢谢那些支持我的人,也许很多人关注了也没再看新的,但是不管怎样我都要说声谢谢。本人技术也挺渣的,也希望大神们能多多指点。

简书

责编内容by:简书阅读原文】。感谢您的支持!

您可能感兴趣的

Android动画:这是一份全面 & 详细的动画使用攻略... 前言 动画的使用 是 Android 开发中常用的知识 可是动画的 种类繁多、使用复杂 ,每当需要 采用自定义动画 实现 复杂的动画效果 时,很多开发者就显得束手无策 本文将献上一份 Android 动画的...
告别onActivityResult,用实现AOP方式获取startActivityForResul... 每次我们使用startActivityForResult方法时,如果需要接收返回的结果,总得在onActivityResult中进行处理。如果业务比较复杂,有多个界面携带数据返回到同一界面中,需要在 onActivityResult 方法中...
利用DecorView实现播放视频开灯/关灯效果和仿QQ消息提示框... 写这篇文章前得先来了解一下 activity.getWindow().getDecorView() 获取到的 DecorView 视图 首先我们通过强大的 Android Studio 开发神器,获取我们当前app界面的布局层次(...
Money made easily with the new Google Play Billing... Posted by Neto Marin, Developer Advocate Many developers want to make money through their apps, but it's not always ea...
Gradle doesn’t run because it can’t fi... Today, when I was uploading new version of EasyFlipView library on jCenter , then I found this strange error w...