Android Gradle从认识到实践

christdp3 7年前
   <p><strong>前言</strong></p>    <p>本文将先从各个gradle文件入手,分析各个文件中,我们可以进行哪些配置,这些配置又可以起到什么作用,如何通过gradle来满足对于构建的自定义需求。</p>    <p><strong>AndroidStudio中Gradle文件</strong></p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/adda7e7fd04561ba47c740bc1cfd7d89.jpg"></p>    <p>我们新建一个Android项目,AndroidStudio会默认为我们生成以下几个文件,Project的构建文件,Module的构建文件,Project配置文件,混淆规则文件等,那么这些文件都具有什么功能,我们又可以进行何种配置呢?</p>    <ul>     <li>settings.gradle</li>    </ul>    <p>include ':app'</p>    <p>新建的工程,默认只有上述一条语句,用于指示 Gradle 在构建应用时应将哪些模块包括在内。对大多数项目而言,该文件可能只有上述一条,但是当我们项目中,引入了其它的功能module,或者业务逻辑module,就需要我们在include语句中添加相应的module。</p>    <ul>     <li>build.gradle</li>    </ul>    <p>build文件有两个,一个是针对我们的Module,一个是针对Project。</p>    <p>在Project中,默认生成如下配置</p>    <pre>  <code class="language-java">// Top-level build file where you can add configuration options common to all sub-projects/modules.      buildscript {       repositories {           jcenter()       }       dependencies {           classpath 'com.android.tools.build:gradle:2.2.3'              // NOTE: Do not place your application dependencies here; they belong in the individual module build.gradle files       }   }    </code></pre>    <p>在Project的build文件中,我们可以来添加一些子module所共有的一些配置,而无需单独在每一个子module中进行配置。可进行依赖仓库是jcenter还是其它依赖仓库等。在module中默认生成的是对于我们的module自身构建的时候进行的一些配置选项。</p>    <ul>     <li>gradle.properties</li>    </ul>    <p>为gradle的配置文件,里面可以定义一些常量供build.gradle使用,如版本号等,当随着我们的业务增长,build文件也会变大,可维护性变差,当我们想修改一些内容的时候,需要逐个去找,但是,当我们将其中的一些配置常量放置在一个单独的文件中,相比之前,可维护性就有所提升。我们可以将构建SDK版本等一些信息添加到该文件中。</p>    <pre>  <code class="language-java">COMPILE_SDK_VERSION = 23BUILD_TOOLS_VERSION = 23.0.1VERSION_CODE = 1   </code></pre>    <p>然后,我们就可以在build文件中进行引用了。引用方式,直接通过变量名就可以。</p>    <p><strong>配置构建</strong></p>    <ul>     <li><strong>构建类型</strong></li>    </ul>    <p>构建类型定义 Gradle 在构建和打包您的应用时使用的某些属性,通常针对开发生命周期的不同阶段进行配置。例如,调试构建类型支持调试选项,使用调试密钥签署 APK;而发布构建类型则可压缩、混淆 APK 以及使用发布密钥签署 APK 进行分发。您必须至少定义一个构建类型才能构建应用——Android Studio 默认情况下会创建调试和发布构建类型。要开始为应用自定义打包设置,请学习如何配置构建类型。</p>    <p>默认构建方式</p>    <pre>  <code class="language-java">defaultConfig {        applicationId "com.chenjensen.gradlelearn"           minSdkVersion 14           targetSdkVersion 24           versionCode 1           versionName "1.0"           testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"}    </code></pre>    <p>我们可以根据自己的需求,比如只针对发布的版本进行混淆等操作,而对于debug版本不进行,我们可以在buildType中进行配置。</p>    <pre>  <code class="language-java">buildTypes {        release {            minifyEnabled false              proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'          }        debug {                        }     }    </code></pre>    <ul>     <li><strong>产品风味</strong></li>    </ul>    <p>产品风味代表您可以发布给用户的不同应用版本,例如免费和付费的应用版本。您可以将产品风味自定义为使用不同的代码和资源,同时对所有应用版本共有的部分加以共享和重复利用。产品风味是可选项,并且您必须手动创建。我们可以在productFlavors {} 代码块中配置我们所需要的的设置。产品风味支持与 defaultConfig 相同的属性,这是因为 defaultConfig 实际上属于 ProductFlavor 类。这意味着,您可以在 defaultConfig {} 代码块中提供所有风味的基本配置,每种风味均可替换任何默认值,例如 applicationId。</p>    <p>ApplicationId用来作为我们的APK的包名,用来对于不同的包的区分,对于manifest中的package字段则是用来命名资源类的包名,最后生成的 R 类文件位于该包下,如果其他包里面的代码需要引用资源时可通过该路径进行调用。</p>    <p>例如</p>    <pre>  <code class="language-java">productFlavors {        demo {            applicationId "com.example.myapp.demo"               versionName "1.0-demo"           }           full {            applicationId "com.example.myapp.full"               versionName "1.0-full"           }       }    </code></pre>    <p>通过对于产品风味的配置,我们可以针对不同的应用市场发布不同的应用包,针对不同的应用包,我们可以进行细致化到具体的SDK版本等的配置。采用的不同的应用市场分发,可以让我们针对不同应市场下发下的下载率的采集。</p>    <ul>     <li><strong>依赖项</strong></li>    </ul>    <p>构建系统管理来自您的本地文件系统以及来自远程存储区的项目依赖项。这样一来,您就不必手动搜索、下载依赖项的二进制文件包以及将它们复制到项目目录内。</p>    <p>Android中有三种添加依赖的方式</p>    <pre>  <code class="language-java">//依赖我们本地的module   compile project(":mylibrary") //远程的二进制依赖项   compile 'com.android.support:appcompat-v7:25.1.0'   //本地二进制依赖方式,将检测我们的本地的libs中的jar文件   compile fileTree(dir: 'libs', include: ['*.jar']) //javaTest依赖   testCompile 'junit:junit:4.12'     //AndroidTest依赖   androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2'    </code></pre>    <p>当我们添加了一个依赖,该依赖还依赖了其它的依赖,而我们想把其中的一个依赖去掉,compile方法,可以接受一个闭包参数,我们可以利用这个闭包来将其中的部分依赖剔出掉。</p>    <pre>  <code class="language-java">androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {           exclude group: 'com.android.support', module: 'support-annotations'       })    </code></pre>    <p>通过compile配置,Gradle 将此配置的依赖项添加到类路径和应用的 APK。除了compile配置,还有apk,provided。</p>    <ul>     <li><strong>apk</strong></li>    </ul>    <p>指定 Gradle 需要将其与应用的 APK 一起打包的仅运行时依赖项。您可以将此配置与 JAR 二进制依赖项一起使用,而不能与其他库模块依赖项或 AAR 二进制依赖项一起使用。</p>    <ul>     <li><strong>provided</strong></li>    </ul>    <p>指定 Gradle 不与应用的 APK 一起打包的编译时依赖项。如果运行时无需此依赖项,这将有助于缩减 APK 的大小。您可以将此配置与 JAR 二进制依赖项一起使用,而不能与其他库模块依赖项或 AAR 二进制依赖项一起使用。</p>    <ul>     <li><strong>签署</strong></li>    </ul>    <p>构建系统可以在构建配置中指定签署设置,并可在构建过程中自动签署您的 APK。构建系统通过使用已知凭据的默认密钥和证书签署调试版本,以避免在构建时提示密码。除非为此构建显式定义签署配置,否则,构建系统不会签署发布版本。如果没有发布密钥,可以按签署应用中所述生成一个。由于调试证书通过构建工具创建并且在设计上不安全,大多数应用商店(包括 Google Play 商店)都不接受使用调试证书签署要发布的 APK。</p>    <p>签署的应用</p>    <p>应用升级:当系统安装应用的更新时,它会比较新版本和现有版本中的证书。如果证书匹配,则系统允许更新。如果使用不同的证书签署新版本,则必须为应用分配另一个软件包名称 - 在此情况下,用户将新版本作为全新应用安装。</p>    <p>应用模块化:Android 允许通过相同证书签署的多个 APK 在同一个进程中运行(如果应用请求这样),以便系统将它们视为单个应用。通过此方式,可以在模块中部署您的应用,且用户可以独立更新每个模块。</p>    <p>在您创建签署配置时,Android Studio 会以纯文本形式将您的签署信息添加到模块的 build.gradle 文件中。如果是团队协作开发或者将您代码开源,那么应当将此敏感信息从构建文件中移出,以免被其他人轻易获取。为此,创建一个单独的属性文件来存储安全信息。然后在本地获取外部文件的配置,然后在发布代码的时候,保留我们的秘钥配置文件。</p>    <ul>     <li>在项目的根目录下创建一个名称为 keystore.properties 的文件。</li>    </ul>    <pre>  <code class="language-java">storePassword=myStorePasswordkeyPassword=mykeyPasswordkeyAlias=myKeyAliasstoreFile=myStoreFileLocation   </code></pre>    <ul>     <li>在模块的 build.gradle 文件中,于 android {} 块的前面添加用于加载 keystore.properties 文件的代码</li>    </ul>    <pre>  <code class="language-java">def keystorePropertiesFile = rootProject.file("keystore.properties")// Initialize a new Properties() object called keystoreProperties.def keystoreProperties = new Properties()// Load your keystore.properties file into the keystoreProperties object.keystoreProperties.load(new FileInputStream(keystorePropertiesFile))   </code></pre>    <ul>     <li>使用语法 keystoreProperties['属性名称'] 引用存储在 keystoreProperties 中的属性。修改模块 build.gradle 文件的 signingConfigs 块,以便使用此语法引用存储在 keystoreProperties 中的签署信息。</li>    </ul>    <pre>  <code class="language-java">android {    signingConfigs {        config {            keyAlias keystoreProperties['keyAlias']               keyPassword keystoreProperties['keyPassword']               storeFile file(keystoreProperties['storeFile'])               storePassword keystoreProperties['storePassword']           }       }       ...     }    </code></pre>    <ul>     <li><strong>ProGuard</strong></li>    </ul>    <p>构建系统让您能够为每个构建变体指定不同的 ProGuard 规则文件。构建系统可在构建过程中运行 ProGuard 对类进行压缩和混淆处理。代码压缩通过 ProGuard 提供,ProGuard 会检测和移除封装应用中未使用的类、字段、方法和属性,包括自带代码库中的未使用项(这使其成为以变通方式解决 64k 引用限制的有用工具)。ProGuard 还可优化字节码,移除未使用的代码指令,以及用短名称混淆其余的类、字段和方法。混淆过的代码可令您的 APK 难以被逆向工程。对于ProGuard更详细的介绍可以参考之前关于项目构建的文章。</p>    <p>开启代码压缩</p>    <p>minifyEnabled true</p>    <p>启用ProGuard规则</p>    <p>proguardFiles getDefaultProguardFile(‘proguard-android.txt'),</p>    <p>'proguard-rules.pro'</p>    <ol>     <li>getDefaultProguardFile(‘proguard-android.txt') 方法可从 Android SDK tools/proguard/ 文件夹获取默认 ProGuard 设置。</li>     <li>proguard-rules.pro 文件用于添加自定义 ProGuard 规则。默认情况下,该文件位于模块根目录</li>    </ol>    <p>每次执行完成ProGuard之后,都会产生如下文件</p>    <ul>     <li>dump.txtAPK 中所有类文件的内部结构。</li>     <li>mapping.txt提供原始与混淆过的类、方法和字段名称之间的转换。</li>    </ul>    <p>seeds.txt</p>    <p>列出未进行混淆的类和成员。</p>    <p>usage.txt</p>    <p>列出从 APK 移除的代码。</p>    <p>这些文件保存在 <module-name>/build/outputs/mapping/release/。</p>    <p>对于其中一些类,我们不想对其进行混淆的,需要我们在ProGuard 配置文件中添加一行 -keep 代码。例如:</p>    <pre>  <code class="language-java">-keep public class MyClass    </code></pre>    <p> </p>    <p>来自:http://mobile.51cto.com/android-534664.htm</p>    <p> </p>