Android-Gradle-productFlavor多风味打包

Posted 普通网友

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android-Gradle-productFlavor多风味打包相关的知识,希望对你有一定的参考价值。

享学课堂诚邀作者:周周

转载请声明出处!

前言

手把手讲解系列文章,是我写给各位看官,也是写给我自己的。
文章可能过分详细,但是这是为了帮助到尽量多的人,毕竟工作5,6年,不能老吸血,也到了回馈开源的时候.
这个系列的文章:
1、用通俗易懂的讲解方式,讲解一门技术的实用价值
2、详细书写源码的追踪,源码截图,绘制类的结构图,尽量详细地解释原理的探索过程
3、提供Github 的 可运行的Demo工程,但是我所提供代码,更多是提供思路,抛砖引玉,请酌情cv
4、集合整理原理探索过程中的一些坑,或者demo的运行过程中的注意事项
5、用gif图,最直观地展示demo运行效果

如果觉得细节太细,直接跳过看结论即可。
本人能力有限,如若发现描述不当之处,欢迎留言批评指正。

学到老活到老,路漫漫其修远兮。与众君共勉 !

正文大纲

1. gradle是什么
2. groovy语言的特性以及它和java的关系
3. 为什么你的apk打包这么慢
4. 如何利用gradle编程解决工作中的实际问题
5. gradle的高级用法(gradle多渠道快速打包插件)

承接上文【android Gradle(1) 概念及基础】https://www.jianshu.com/p/c36cd9aa2724

4. 如何利用gradle编程解决工作中的实际问题

前置知识

前面提到了,gradle可以编写代码逻辑。那么既然是可以自定义逻辑,那么我们在熟悉gradle编程规范之后,能把我们自己的逻辑,嵌入到 gradle的编译打包过程中去。

但是在此之前,有必要了解一下gradle的打包流程


上图中,把gradle的整体编译过程分为了3个阶段:
初始化=>配置=>执行
初始化:执行的是 setting.gradle文件
配置:执行的是 所有的build.gradle文件
执行: 到了这里,系统中就生成了一个有序状态图(taskGraph),系统按照这个taskGraph去执行所有的task,完成打包。
而上图中,还有3个 Hook 钩子,这意味着,我们可以通过gradle编程手段,自己定义3个hook,来干涉编译打包的过程,达成我们自己的目的。钩子同样也会进入到有序状态图(taskGraph),随着打包的过程一起执行。

这里涉及到一个task的概念,它是gradle中的一个重要概念,代表一个任务。
如何查看当前环境有哪些task可用?

两种方式,
图形化界面去查看,你可以直接双击某个task去执行:
命令行去查看:
gradlew tasks 回车

你也可以通过命令行去执行某个task,比如说:
我要 安装一个debug版本的apk到设备上:
gradlew installDebug 回车.
我们加入自己的逻辑,一般都会以task为单位去执行。

要编程,除了要了解语法之外,还需要了解 gradle的api架构层级关系,请到gradle的下载根目录,找到下面的目录:
C:\\Users\\adminstrator\\.gradle\\wrapper\\dists\\gradle-4.4-all\\9br9xq1tocpiv8o6njlyu5op1\\gradle-4.4\\src\\core-api\\org\\gradle\\api
C:\\Users\\adminstrator\\.gradle\\wrapper\\dists\\gradle-5.1.1-all\\97z1ksx6lirer3kbvdnh7jtjg\\gradle-5.1.1\\src\\core-api\\org\\gradle\\api
这里应该包含了我们gradle编程需要用到的所有类。

官方参考文档

除此之外,了解了代码框架之外,我们还需要知道 gradle里面一些配置应该参考的官方文档,这里给出:
http://google.github.io/android-gradle-dsl/current/

上主菜

推荐一种沟通发言说话面试的神级技巧STAR法则,按照 situation 情境 ,task 任务 ,action 行动,result 结果 的顺序来描述一件事,条理清楚,有理有据,说服力强

situation 情境

国内android大环境大家心里都有数,各大厂家各自为政,经常互掐,应用市场也是门派林立,各自有各自的要求。于是,老板要求,我们开发的app能够快速打出 对应的应用市场的apk,发布到对应的应用市场,并且,老板还想玩点骚操作,经常给app换点主题颜色什么的,今天红色, 下个月白色…虽然心里MMP,但是脸上还是要笑嘻嘻的去跟老板说“包在我身上”…

task 任务

上面的情境中,我们分析出老板的2个核心需求,app代码开发完毕之后,我们要在打包的时候设定特殊的参数,让app在不同的应用市场下的表现有所差异,达到该应用市场的要求。老板的骚操作??? 换主题?同样,给定特殊参数,打包的时候自主选择,打出特定主题颜色的apk.

action行动

定下了目标,那么自然需要我们付诸行动。现在祭出 干货:满足多渠道,多主题混合打包的**androidStudio Demo工程**
关键部分解读:

1.新建 flavor.gradle 文件,内容编辑如下:

android 

    //定义多渠道配置
    flavorDimensions "channel", "theme"  // 我要求有两种维度,一个是 渠道,一个是 主题

    file("./channel.txt").readLines().each 
        channel ->
            println(channel)
            productFlavors.create(channel, 
                dimension 'channel'
                manifestPlaceholders = [channelName: channel]
            )
    


    file("./theme.txt").readLines().each 
        theme ->
            println(theme)
            productFlavors.create(theme, 
                dimension 'theme'
                manifestPlaceholders = [themeName: theme]
            )
    

同时,建立2个txtchannel.txt配置 渠道theme.txt配置 主题


疑难解答

这部分涉及 核心gradle代码,有必要讲解一下:

android : android工程的下gradle代码的"根目录", 与android打包直接相关的配置,必须放在android的闭包里。

flavorDimensions “channel”, “theme” flavor == “风味”,dimensions="维度"复数
声明所有的 flavor “风味维度”, 先声明,而后再进行配置。这一句的意思是:下面的配置,会涉及到2个维度的打包风味,一个维度是channel,一个维度是theme,如果channel维度下有4个配置,theme维度下有3个配置,那么 打包风味的总数就是 3x4=12

file("./channel.txt").readLines().each 这是gradle里面的文件IO流的写法,语法简单易懂,逐行读取channel.txt文件,然后each遍历 … 里面的闭包写法不需要我再解释了吧…

println(channel) gradle的打印,这个打印会在android的run栏目里面看到

productFlavors.create(theme,
dimension ‘theme’
manifestPlaceholders = [theme: theme]
)

productFlavors 这是gradle官方提供的专门解决多风味打包的库。
它的create方法有2个参数,一个是风味的名字,一个是闭包,闭包里面可以自行编辑该风味下的特性。
dimension ‘theme’ 当前风味所处的维度是 theme维度,表示主题风格.
manifestPlaceholders = [themeName: theme] manifestPlaceholders是定义 android工程中manifest.xml的占位符对应的具体值.
(占位符?请继续观下文)。

2. AndroidManifest.xml 中定义meta-data

<application ...>
        ...
        <!-- 预定义一些可变参数,打包的时候会根据配置,有所变化 -->
        <meta-data
            android:name="CHANNEL"
            android:value="$channelName" />
        <meta-data
            android:name="THEME"
            android:value="$themeName" />
    </application>

3. 在android的java代码中,取得meta-data的具体值,并且将它用到业务代码中去,让app在打不同包的时候,产生不同的特性(UI特性,业务特性).

public class MainActivity extends AppCompatActivity 

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        TextView tvCurTheme = findViewById(R.id.curTheme);
        TextView tvCurChannel = findViewById(R.id.curChannel);

        getMetaData();

        tvCurTheme.setText(theme);
        tvCurChannel.setText(channel);

    

    String channel;
    String theme;


    /**
     * 从manifest中读取出metadata
     */
    private void getMetaData() 
        PackageManager pm = getPackageManager();
        try 
            ApplicationInfo appInfo = pm.getApplicationInfo(BuildConfig.APPLICATION_ID, PackageManager.GET_META_DATA);
            Bundle bd = appInfo.metaData;
            channel = bd.getString("CHANNEL");
            theme = bd.getString("THEME");
         catch (PackageManager.NameNotFoundException e) 
            e.printStackTrace();
        
    

关键代码就是 getMetaData()方法.
核心代码简单解读:

PackageManager : 与android打包相关的东西,基本上都被管理在PackageManager里面,它是一个跨进程的AIDL函数调用:

    @Override
    public PackageManager getPackageManager() 
        if (mPackageManager != null) 
            return mPackageManager;
        

        IPackageManager pm = ActivityThread.getPackageManager();
        if (pm != null) 
            // Doesn't matter if we make more than one instance.
            return (mPackageManager = new ApplicationPackageManager(this, pm));
        

        return null;
    

ApplicationInfo appInfo = pm.getApplicationInfo(…) 拿到了pm之后,用这个函数来获得当前app的应用信息,也就是 androidManifest.xml中application标签内的所有信息,包括我们定义的meta-data.
Bundle bd = appInfo.metaData; metaData是一个android 中实现了 Parcelable 接口的键值对的封装,其取值方式也是bd.getString("CHANNEL");
三步走之后,我们编译同步一下gradle.
踩坑教训:gradle编程,在androidStudio上非常别扭,有时候没有代码提示,有时候代码提示不全,有时候提示的是错的,总之,不要太相信as… 如果发现编译报错,要从错误日志去查找可能原因。
这也是我如此详尽解释每一句代码的原因,对于初学者而言,任何一个低级错误都有可能让你抓狂好一阵子,网上太多这种不明不白的博客,让人看了不如不看,更有好多都是错误的,所以我给出了可运行的Demo地址:androidStudio Demo工程 供读者调试研究。

result 结果

一顿操作猛如虎,现在来验证我们的劳动成果了:
两种方式,命令行方式 或者 图形界面方式。

先说命令行

gradlew tasks 查看当前可以使用的所有task

gradlew assembleHuaweiBlack

生成了这两个包,一个debug,一个realease(如果只需要release,可以用gradlew assembleHuaweiBlackRelease)
adb install -r C:\\Users\\adminstrator\\AndroidStudioProjects\\GradleStudy1021\\app\\build\\outputs\\apk\\huaweiBlack
\\debug\\app-huawei-black-debug.apk
安装刚才生成的debug包,装好之后打开一看:

还记得刚才打包的是什么吗?huawei的黑色风格!

再说图形界面

(一看就懂,不用我多BB了。。):

如果我双击这个:


duang!

打完收工!

事后总结

上文展示了 gradle在实际工作中 如何去解决 多风味打包的问题,但是这个仅仅是开端,实际工作比我们想的要更加复杂。gradle的学习,as的环境并不友好,但是毕竟as是主流,临时换一个ide又不划算。所以必须找到有效的学习方式,才能够保证学习效率。 最直接的,就是官方文档,http://google.github.io/android-gradle-dsl/current/ ,它可以让你对android工程中所有的gradle配置有完整的了解,并且随时查阅。

结语

本文比较基础,下一篇来点更刺激的,你们一定发现了,本文攻略虽然可以解决变态老板的多渠道,多主题打包的要求,但是,每一次打包,都会走一次完整的apk编译打包流程,如果1个包,要5分钟,那么10个包就将近一个小时了,而且,如果老板需要 多渠道,多主题,多语言…3个维度打包,那么耗费的时间将会成几何级数增长。我们作为android 高级开(码)发(农)要善于利用技术手段解决实际问题,下一篇文章将详解如何优雅,快速的打出我想要的 "风味"包!
请期待: Android Gradle(3) gradle插件V1签名多风味打包

线程、数据库、算法、JVM、分布式、微服务、框架、Spring相关知识

一线互联网P7面试集锦+各种大厂面试集锦

资料领取方式:戳这里

学习笔记以及面试真题解析

radle插件V1签名多风味打包

线程、数据库、算法、JVM、分布式、微服务、框架、Spring相关知识

[外链图片转存中…(img-Bea2WEyw-1623555802774)]

一线互联网P7面试集锦+各种大厂面试集锦

[外链图片转存中…(img-DR9HqQXk-1623555802775)]

资料领取方式:戳这里

学习笔记以及面试真题解析

以上是关于Android-Gradle-productFlavor多风味打包的主要内容,如果未能解决你的问题,请参考以下文章