gradle多渠道打包

E文不好的童鞋,例如我,翻译文章的过程里没有愉悦的感受,只有2行老泪;但最终有一丝成就感也算是安慰了。所以我会去尊重那些翻译IT技术文章的大拿们,他们就是千千万万个亚里士多德和吴启明,他们是E文不好的童鞋的传教士,阿门,当然我不是大拿。


废话少说,先看一篇例子:在 http://ghui.me/post/2015/03/create-several-variants/  。


然后来看这篇翻译,扫清例子中一部分未知的知识。原文在 http://tools.android.com/tech-docs/new-build-system/build-system-concepts 。


构建系统的概念


新的构建系统的目标是:
容易地重用代码和资源
容易地创建一个应用程序的多个变体,要么是多APK发布,要么是不同特性的应用
容易地扩展和配置系统的构建
为了实现这些目标我们介绍一些新概念:


Product Flavors


一个产品特性决定了这个项目一个版本的应用程序。单个项目可以有不同的特性,那么就会产生不同的应用程序。
虽然不同的特性可能会产生非常不同的应用,但是使用库项目也是一个好的用例,并且构建系统仍然支持库项目。
product flavor这个新概念被设计用来帮助区分非常非常细微的差异,例如Google Play的多APK支持(例如这种差异:GL纹理压缩会使用不同的格式)。
“这是同一种的应用吗?”如果答案是是,那么我们很有可能使用库项目这种方式。


product flavors可以定制以下属性:
        minSdkVersion
        targetSdkVersion
        versionCode
        versionName
        包名(覆盖manifest中的值)
        发布签名信息(keystore, key alias, passwords,...)
        构建配置:提供自定义java代码的能力。
        NDK ABI filter(还没有实现)
        测试信息
                package name for test app (可选的, default is <base>.test)
                InstrumentationTestRunner class (可选的)
        此外,product flavor能提供他们自己的source code,resources和manifest。


一个项目的启动是用默认的配置启动的。上面所有的属性都可以设置并且有他自己的source code,resources和manifest。如果一个项目没有创建product flavor,那么该项目构建使用的是默认配置。
如果项目声明使用了product flavor,那么这些product flavors继承扩展main configuration。
The source code of the product flavor is used to the source code of the main configuration (1).
The resources of the product flavor overrides the resources of the main configuration.(覆盖)
The Manifest of the product flavor is merged on top of the Manifest of the main configuration.(合并到顶部)


(1)这允许一些灵活性,但也增加了一些限制:
the main configuration里的类和the product flavors里的类能相互引用。所有的source sets被用来生成单一的output(而不是每一个source set使用一个单向依赖生成自己的output)。
product flavors里暴露的类和被the main configuration中的类引用的类 必须 存在于所有的product flavors里,而且为了所有成功的构建 必须 有相同的API。

当一个Product Flavor被定义了下来,那么the main configuration作为可构建的产品是不可获得的。去创建不只一个产品的话,2个或者多个产品特性必须要创建和定制下来。


注意:AndroidManifest中的属性是通过默认配置据或者特性配置(the default Configuration or the flavor configurations)设置的:
the manifest文件中的属性值被构建配置中的值覆盖。the manifest文件中的所有的属性值都是,除了the package name能被忽略。
The main manifest必须总是要有一个package name。这是用来生成R类的包信息。覆盖重写一个产品特性的包名对R的生成没有影响。这种被应用到只要最终的APK被创建。

Build Types


一个构建类型为了调试或者发布的目的允许配置一个应用程序如何打包。


这个概念的意思不是用来创建同一应用的不同版本,她是正交于Product Flavor的。


一个构建类型为以下属性提供配置:
        manifest debuggable flag
        native compilation debug flag
        proguard enabled + specific rules(还没有实现)
        debug signing flag(例如是否使用debug key 或者 release key)
        package name 后缀(2)
        version name 后缀(里程碑0.3中的更新)
        Buildconfig
        DEBUG flag。基于the manifest debuggable flag的自动配置。
        提供自定义的java代码的能力

构建系统默认提供2种构建类型,debug and release,他俩可以重新被配置。我们可以提供一些上面属性的组合来创建新的构建类型。
例如:用Proguard去制作一种构建类型从而创建一个debuggable apk。


(2)这是附加到the manifest package name后面。这里的目标是允许不同的build types创建不同的apk,而这些apk都能同时被安装。这个是可选的。


像Product Flavors一样,Build Types也能提供他们自己的source code, resources and manifest.
典型的案例如下:
在release and debug2种模式下的不同的MapView key和signing key可以关联(3)
构建debug的时需要额外的权限,例如:ACCESS_MOCK_LOCATION

(3)如果Product Flavors使用不同的key来创建不同的版本构建,那么就用Product Flavor的resources来提供MapView API Key。见以下Build Variants。


Build Types提供的The source code and resources会影响项目的构建,Product Flavors同样也是。


Build Variants


我们见识了Product Flavors 和 Build Types这两者是如何配置一个项目的output的。
实际上,一个项目的输出只能是the Build Type和the Product Flavor的交叉产品。这是叫build variant.
如果product flavors被定义了下来,就不可能忽略了它们。
如果一个项目没有定制Build Type 或者 Product Flavor,那么可用的build variants是debug 和 release这2个版本的变体,他俩作为默认的配置。
然而,如果一个项目声明了2个特性,例如:free和forpay,那么可用的Build Variants有以下:
                  Debug                        Release
  Free        Free-Debug              Free-Release
  ForPay  ForPay-Debug          ForPay-Release
 
从上面我们可以看出Build Types 和 Product Flavors提供的source code 和 resources是怎样继承和覆盖the main configuration的。当我们实际构建一个app时,
Build Type 和 Product Flavor都适用于以下规则:
所有的源文件夹被用来一起(default config, build type, product flavor, and generated source code(4))去创建一个单一的输出。
意思就是上面提到的相同的限制,还有另外Build Types 和 Product Flavors不能提供同一个类的不同版本。


(4)生成的源代码是资源的编译(R.java),aidl和渲染脚本的编译,还有像被BuildType影响的构建配置。这些每个构建变体都会不同。


资源的组合用下面的优先级(低序号高优先级并且覆盖高序号):
        1.build type
        2.flavor
        3.main configuration

Assets包和java资源当碰到重复时遵循相似的优先级:
        1.Build Type
        2.Product Flavor
        3.default configuration
        Note: Not implemented yet.


Sourcesets


由于Build Types 和 Product Flavors都提供他们自己的sources, resources 和 manifest,所以项目的结构需要从根级别改变了。


而构建系统会移动到一个顶级文件夹src下面,包括除了默认配置之外也有每种build types和每种flavors的文件夹,还有每种flavors的测试。那些每一个子文件夹表
现出的元素是独立的,还有包含的manifest, java source code, resources, 等等......


一个典型的项目会有以下文件夹结构:
src/
        main/
                java/
                jni/
                resources/ -- this is java resources
                aidl/
                rs/
                res/ -- this is Android resources
                assets/
                AndroidManifest.xml
        debug/
                Java, jni, res, AndroidManifest.xml, etc... (same as main)
        release/
                Java, jni, res, AndroidManifest.xml, etc... (same as main)
        flavor1/
                Java, jni, res, AndroidManifest.xml, etc... (same as main)
        flavor2/
                Java, jni, res, AndroidManifest.xml, etc... (same as main)

当前的gen文件夹将会移动到项目输出下,它实际上有多少个(移动多少次),这取决于构建变体(the build variant)伴随着移动的还有生成的resources和生成(合并)
的Manifest。


Testing


在当前的构建系统里,测试应用程序是被不同的标记成“test project”的项目创建而成的。这些个项目引用main project是为了可以获取main project的classpath上的类。


对于可能的多个Product Flavors,测试他们是重要的。


现在,这些测试项目是the main projects的一部分。源代码集合(Sourcesets)包含一些为了默认配置(the default configuration)和每一个特性(each flavors)的
测试,这些源代码集合(Sourcesets)被自动地使用,并且为每一个变体生成一个测试应用程序。


例如一个项目(或者称构建系统)含有几个特性(flavors),它的源文件夹的结构看起来像下面这样:
src/
        main/
        test/ -- this is the code to test “main”
        debug/
        release/
        flavor1/
        testFlavor1/ -- this is the code to test “flavor1”
        flavor2/
        testFlavor2/ -- this is the code to test “flavor2”


测试应用程序的manifest文件总是相同的。然而由于特性(flavors)能够自定义程序的包名,所以测试的manifest文件匹配包名是重要的。为了这个事,测试的manifest文件
总是要被生成出来。


构建库项目(Building Library Projects)


库项目的构建以非常类似的方式去规定项目:(~晕头的翻译~)
不能有Product Flavor
有debug 和 release 2种 build types,但是这2种使用起来有轻微的不同。

测试库是重要的并且是通过项目的测试组件测试的。然而,不像普通项目一样,这个组件不会从它仅有的source set生成一个单独的应用程序。相反它毫无保留地引用它自己的库并且打包成属于它自己的apk。
这种构建总是一个debug的构建。
当库项目被构建和打包成一个分配团(distribution blob ~莫名其妙~),这时这种构建总是一个release的构建。
库能被打包成二进制捆(binary bundle)。这些可以被上传到在线仓库(Maven or Ivy)去被其他项目重用。
他们也能被multi-project组作为一部分使用。


第一次发表长文,第一次翻译,请大家斧正。转载请说明本网址。

本页内容版权归属为原作者,如有侵犯您的权益,请通知我们删除。
前言 本文主要讲解Telephony中Phone相关的知识,主要想讲明白三件事情: Phone是什么? Phone从哪里来? Phone有什么作用? 1. Phone是什么 1.1 Phone是一个接口 Phone.java (frameworks\opt\telephony\src\java\com\android\internal\telephony) public interface Phone { //包含了大量的register/unregister的方法。(监听能力) void registe

Android混淆心得 - 2016-07-23 14:07:36

最近在做Android应用的混淆,踩了一些坑,这里记录分享下个人的心得。 混淆介绍 首先先简单说一下什么是混淆和混淆的作用,其实这个搜索下可以找到一堆官方的说法等等,这里简单口语叙述一下,混淆就是把代码替换成a、b、c基本字母组成的代码,比如一个方法名为:function(),混淆后可能会被替换成a()。 混淆的好处: 代码混淆后阅读性降低,反编译后破译程序难度提高 混淆后字节数减少,减少了应用了体积 前者只能说有一点作用,后者则需要看代码的数量 当然不能忽视混淆的缺点: 混淆后,测试不充分可能导致某些功
[编写高质量iOS代码的52个有效方法](二)对象 参考书籍:《Effective Objective-C 2.0》 【英】 Matt Galloway 先睹为快 6.理解“属性”这一概念 7.在对象内部尽量直接访问实例变量 8.理解“对象等同性”这一概念 9.以“类簇模式”隐藏实现细节 10.在既有类中使用关联对象存放自定义数据 目录 编写高质量iOS代码的52个有效方法二对象 先睹为快 目录 第6条理解属性这一概念 第7条在对象内部尽量直接访问实例变量 第8条理解对象等同性这一概念 第9条以类簇模式隐
插件其实是Apk安装包,如果要使用必须先要安装和解析,以便知道插件Apk的相关信息。而从Demo中我们知道插件的安装和卸载是通过调用PluginManager的installPackage()和deletePackage()来实现的。就先从PluginManager.installPackage()开始分析插件Apk的安装过程。 第一步:PluginManager. getInstance().installPackage(apkPath,flag); 此函数中只是调用了mPluginManager.in
分享截屏已经是很多游戏应用必备的功能了,找到了一个国内的插件,虽然用起来还行,但是,还是想吐槽下,跟老外的插件比,真的有差距啊有差距啊有差距啊,啊啊啊。 ShareSDK的官方网站:http://www.mob.com/,使用插件需要注册账号获得key,不过,至少现在是免费的。 我的Unity版本是5.3,xcode版本是7.2,ShareSDK版本是2.7.4 Unity sdk下载地址:https://github.com/MobClub/New-Unity-For-ShareSDK 新建一个简单的工
正常情况下启动一个Activity,首先需要在AndroidManifest文件中声明,其次需要把该应用安装到手机系统中。 而插件apk是没有正在安装到手机系统中的,也就按照正常的启动流程插件Activity是不能启动的。另外插件apk的类需要加载进来是需要指定ClassLoader。前面的文章也大概讲过,当启动一个插件Activity时,先是用预定义的代理Activity替换目标Activity(及插件Activity)去启动,当AMS处理完回调到应用空间时(及回到运行Activity的进程空间时)再用
从DroidPlugin的官方文档中我们知道。 2 在AndroidManifest.xml中使用插件的com.morgoo.droidplugin.PluginApplication: 或者在自定义的Application的onCreate()函数中,调用PluginHelper.getInstance().applicationOnCreate(getBaseContext()); 在Application的attachBaseContext()函数中,调用 PluginHelper.getInsta

字母雨的实现 - 2016-07-23 14:07:06

有段时间没写博文了,前段时间比较忙,这几天闲下来,想着写点东西,脑袋一下就闪过以前学习Android的时候见到的别人实现的黑客帝国的字母雨效果,当时对于小菜鸟的自己,那叫一个膜拜啊,时隔几年,自己实现一下,算是对以前的自己一个交代吧。 先看效果: 一、实现原理 在实现过程中,主要考虑整个界面由若干个字母组成的子母线条组成,这样的话把固定数量的字母封装成一个字母线条,而每个字母又封装成一个对象,这样的话,就形成了如下组成效果: 字母对象--》字母线条对象--》界面效果 每个字母都应该知道自己的位置坐标,自己

DroidPlugin源码分析Hook过程 - 2016-07-23 14:07:06

插件运行环境初始化过程中我们知道,Hook的初始化是在PluginHelper的initPlugin函数中通过调用PluginProcessManager.installHook来实现的。而在分析DroidPlugin Hook过程之前需要先简单了解一下Java的动态代理。 Java动态代理与之相关的一个类Proxy,一个接口InvocationHandler,一个函数invoke他们之间的关系。就通过DroidPlugin 的BinderHook类的部分代码来解释一下他们的关系; abstract cl
大概半年之前,看过鸿洋大神的一篇博客 Android 自定义控件玩转字体变色 打造炫酷ViewPager指示器 他说大概想了32秒就知道了实现思路,这深深的刺痛了我。最近又看了一遍,决定做点什么 我要自定义的控件是一个盖世英雄, 它不仅仅是一个 Loading控件 ,同时还支持 进度条 (ProgressBar) 功能 。 它会在你需要的时候出现, 它支持 left , top , right , bottom 四个方向加载(变色),最重要的是,它可以是 文字 ,也可以是 图片 ,能够满足开发者一切需求。