Gradle构建系统

Gradle是什么?

Android Studio 基于 Gradle 构建系统,并通过 Android Gradle 插件提供更多面向 Android 的功能

Gradle 和 Android 插件独立于 Android Studio 运行。这意味着,您可以在 Android Studio 内、使用计算机上的命令行工具或在未安装 Android Studio 的计算机(例如持续性集成服务器)上构建 Android 应用。如果您不使用 Android Studio,可以学习如何从命令行构建和运行您的应用。无论您是从命令行、在远程计算机上还是使用 Android Studio 构建项目,构建的输出都相同。

Gradle与Android项目相关的文件

Gradle 设置文件 —— settings.gradle

setting.gradle.png

顶级构建文件 —— build.gradle

build.gradle(project).png

模块级构建文件 —— build.gradle

模块级 build.gradle 文件位于每个 <project>/<module>/ 目录

apply plugin: 'com.android.application'

/**
 *  android {}块配置所有Android特定的构建选项
 */

android {

  /**
   * compileSdkVersion指定Gradle应该使用的Android API级别
   * 编译您的应用程序。 这意味着您的应用可以使用的API等于
   * 或低于这个API。
   *
   * buildToolsVersion指定SDK构建工具的版本,命令行
   * 以及Gradle用来构建应用程序的编译器。 你需要
   * 使用SDK管理器下载构建工具。
   */

  compileSdkVersion 25
  buildToolsVersion "25.0.0"

  /**
   * defaultConfig {}块封装了所有构建variants的默认设置,
   * 并可以覆盖AndroidManifest.xml中的某些属性例如包名、
   * minSdkVersion 、versionCode扥
   */

  defaultConfig {

    /**
     * applicationId唯一,等同于AndroidManifest.xml文件中的package属性。
     */

    applicationId 'com.example.myapp'

    // 最小API版本
    minSdkVersion 15

    // 项目测试运行的版本
    targetSdkVersion 25

    // 版本号
    versionCode 1

    // 在app中显示的版本名称
    versionName "1.0"
  }

  /**
   * buildTypes {}块可以配置多个构建类型。
   * 默认情况下,构建系统定义了两种构建类型:debug和release。 
   */

  buildTypes {

    /**
     * 默认情况下,Android Studio会配置发布版本类型以启用缩减
     * 代码,使用minifyEnabled,并指定Proguard设置文件。
     */

    release {
        minifyEnabled true // 启用缩减代码
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
  }

  /**
   * productFlavors {}块是您可以配置不同定制的产品,例如免费和付费
   */

  productFlavors {
    free {
      applicationId 'com.example.myapp.free'
    }

    paid {
      applicationId 'com.example.myapp.paid'
    }
  }

  /**
   * split {}块中配置不同的APK版本,用于分包
   */

  splits {
    // Screen density split settings
    density {

      // 启用或禁用密度分割机制
      enable false

      // 不包含以下密度
      exclude "ldpi", "tvdpi", "xxxhdpi", "400dpi", "560dpi"
    }
  }
}

/**
 * dependencies {}块指定模块需要添加的依赖
 */

dependencies {
    compile project(":lib")
    compile 'com.android.support:appcompat-v7:25.1.0'
    compile fileTree(dir: 'libs', include: ['*.jar'])
}

gradle.properties

您可以在其中配置项目范围 Gradle 设置,例如 Gradle 后台进程的最大堆大小。如需了解详细信息,请参阅构建环境

local.properties

为构建系统配置本地环境属性,例如 SDK 安装路径。由于该文件的内容由 Android Studio 自动生成并且专用于本地开发者环境,因此您不应手动修改该文件,或将其纳入版本控制

:由于 Gradle 和 Android 插件独立于 Android Studio 运行,您需要单独更新构建工具。请阅读版本说明,了解如何更新 Gradle 和 Android 插件

Gradle可以做什么?

  • 自定义、配置和扩展构建流程。
  • 使用相同的项目和模块为您的应用创建多个具有不同功能的 APK。
  • 在不同源代码集中重复使用代码和资源。

Gradle如何构建APK?

build-process.png

如图所示,典型 Android 应用模块的构建流程通常依循下列步骤:

  1. 编译器将您的源代码转换成 DEX(Dalvik Executable) 文件(其中包括运行在 Android 设备上的字节码),将所有其他内容转换成已编译资源。
  2. APK 打包器将 DEX 文件和已编译资源合并成单个 APK。不过,必须先签名,才能将应用安装并部署到 Android 设备上。
  3. APK 打包器使用调试或发布密钥签名:
  • 如果您构建的是调试版本的应用(即专用于测试和分析的应用),打包器会使用调试密钥库签名。Android Studio 自动使用调试密钥配置新项目。
  • 如果您构建的是打算向外发布的发布版本应用,打包器会使用发布密钥签名。要创建发布密钥,请阅读在 Android Studio 中签名
  1. 在生成最终 APK 之前,打包器会使用 zipalign 工具对应用进行优化,减少其在设备上运行时的内存占用。

构建流程结束时,您将获得可用来进行部署、测试的调试 APK,或者可用来发布给外部用户的发布 APK。

如何配置不同构建类型?

您必须至少定义一个构建类型才能构建应用——Android Studio 默认情况下会创建调试和发布构建类型。尽管调试构建类型不会出现在构建配置文件中,Android Studio 会将其配置为 debuggable true
。要开始为应用自定义打包设置,请学习如何配置构建类型

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

        debug {
            applicationIdSuffix ".amy"
            versionNameSuffix ".amy"
        }

        /**
         * The 'initWith' property allows you to copy configurations from other build types,
         * so you don't have to configure one from the beginning. You can then configure
         * just the settings you want to change. The following line initializes
         * 'jnidebug' using the debug build type, and changes only the
         * applicationIdSuffix and versionNameSuffix settings.
         */

        jnidebug {

            // This copies the debuggable attribute and debug signing configurations.
            initWith debug

            applicationIdSuffix ".jnidebug"
            jniDebuggable true
        }
    }

我们现在设置了debug构建类型的applicationIdSuffix属性和versionNameSuffix属性,那么如何验证app的debug版本的包名和版本名改变了呢?

这里我们就需要用到aapt(Android Asset Packaging Tool)了,我们可以在..\sdk\build-tools[sdk version(例如我的电脑里面是23.0.2)]目录下找到该工具,然后将之前打包的app-debug.apk文件复制到该目录下,然后在命令行中使用如下命令:

D:\Users\Administrator\AppData\Local\Android\sdk\build-tools\23.0.2>aapt dump ba
dging app-debug.apk

可以得到以下输出:

package: name='mylibrary.zero.com.customview.jmy' 
versionCode='1' 
versionName='1
.0.jmy' 
platformBuildVersionName=''
sdkVersion:'17'
targetSdkVersion:'24'

从上面的输出可以看到package和versionName的后缀都多了 .jmy

如需详细了解对于构建类型可以配置的所有属性,请阅读构建类型 DSL 参考

如何发布不同版本的应用?

productFlavors代表您可以发布给用户的不同应用版本,例如免费和付费的应用版本。您可以将productFlavors自定义为使用不同的代码和资源,同时对所有应用版本共有的部分加以共享和重复利用。productFlavors是可选项,并且您必须手动创建。要开始创建不同的应用版本,请学习如何配置productFlavors

defaultConfig实际上属于 ProductFlavor 类。这意味着,您可以在 defaultConfig {}代码块中提供所有ProductFlavor的基本配置,例如 applicationId

:您仍需在清单文件中使用 package 属性指定程序包名称。这样,您可以使用 applicationId为每个productFlavors分配一个唯一的 ID,这样就可以在不更改您的源代码的情况下打包和分发。

:要利用 Google Play 中的多 APK 支持分发您的应用,请为所有Variant分配相同的 applicationId值并为每个Variant分配一个不同的 versionCode。要在 Google Play 中以独立应用的形式分发应用的不同Variant,您需要为每个Variant分配一个不同的 applicationId。

manifestPlaceholders

如果您需要将变量插入到您的build.gradle文件中定义的AndroidManifest.xml文件中,则可以使用manifestPlaceholders属性。
build.gradle:

android {
    defaultConfig {
        manifestPlaceholders = [hostName:"www.example.com"]
    }
    ...
}

manifest :

<intent-filter ... >
    <data android:scheme="http" android:host="${hostName}" ... />
    ...
</intent-filter>

默认情况下,构建工具还会在$ {applicationId}占位符中提供应用程序的应用程序ID。例如,如果您的build.gradle文件如下所示:

android {
    defaultConfig {
        applicationId "com.example.myapp"
    }
    productFlavors {
        free {
            applicationIdSuffix ".free"
        }
        pro {
            applicationIdSuffix ".pro"
        }
    }
}

manifest:

<intent-filter ... >
    <action android:name="${applicationId}.TRANSMOGRIFY" />
    ...
</intent-filter>

当你构建“free”product flavor时,manifest结果如下:

<intent-filter ... >
   <action android:name="com.example.myapp.free.TRANSMOGRIFY" />
    ...
</intent-filter>

如果想发布不同版本例如debug、release、demo等,那么组织项目文件?

默认的app模块的build.gradle文件如下:

...
android {
    compileSdkVersion 24
    buildToolsVersion "24.0.2"
    defaultConfig {
        applicationId "mylibrary.zero.com.customview"
        minSdkVersion 17
        targetSdkVersion 24
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}
...

Android Plugin for Gradle 提供了一项有用的 Gradle 任务,可向您展示如何针对每种构建类型、产品风味和构建变体组织您的文件:

  1. 点击 IDE 窗口右侧的 Gradle
  2. 导航至 MyApplication > Tasks > android 并双击 sourceSets
  3. 要查看报告,请单击 IDE 窗口底部的 Gradle Console

用上面的代码执行Gradle任务后得到的报告如下:

------------------------------------------------------------
Project :app
------------------------------------------------------------

androidTest
-----------
Compile configuration: androidTestCompile
build.gradle name: android.sourceSets.androidTest
Java sources: [app\src\androidTest\java]
Manifest file: app\src\androidTest\AndroidManifest.xml
Android resources: [app\src\androidTest\res]
Assets: [app\src\androidTest\assets]
AIDL sources: [app\src\androidTest\aidl]
RenderScript sources: [app\src\androidTest\rs]
JNI sources: [app\src\androidTest\jni]
JNI libraries: [app\src\androidTest\jniLibs]
Java-style resources: [app\src\androidTest\resources]

debug
-----
......

main
----
......

release
-------
......

test
----
Compile configuration: testCompile
build.gradle name: android.sourceSets.test
Java sources: [app\src\test\java]
Java-style resources: [app\src\test\resources]

testDebug
---------
......

testRelease
-----------
......

而当我们增加构建类型、productFlavors或构建vriant,则会增加对应的输出,例如我们添加productFlavors:

...
android {
    ...
    productFlavors{
        demo{
            applicationId "mylibrary.zero.com.customview.demo"
            versionName "1.0.demo"
        }
    }
}
...

执行Gradle任务后则增加了和demo对应的报告:

androidTestDemo
---------------
Compile configuration: androidTestDemoCompile
build.gradle name: android.sourceSets.androidTestDemo
Java sources: [app\src\androidTestDemo\java]
Manifest file: app\src\androidTestDemo\AndroidManifest.xml
Android resources: [app\src\androidTestDemo\res]
Assets: [app\src\androidTestDemo\assets]
AIDL sources: [app\src\androidTestDemo\aidl]
RenderScript sources: [app\src\androidTestDemo\rs]
JNI sources: [app\src\androidTestDemo\jni]
JNI libraries: [app\src\androidTestDemo\jniLibs]
Java-style resources: [app\src\androidTestDemo\resources]

demo
----
......

demoDebug
---------
......

demoRelease
-----------
......

testDemo
--------
Compile configuration: testDemoCompile
build.gradle name: android.sourceSets.testDemo
Java sources: [app\src\testDemo\java]
Java-style resources: [app\src\testDemo\resources]

testDemoDebug
-------------
......

testDemoRelease
---------------
......

根据报告,知道项目文件应该如何组织,那么如何创建文件呢?

  1. 在该** Project 窗格中,右键点击 src 目录并选择 New > XML > Values XML File **。
  2. 为 XML 文件输入名称或保留默认名称。
  3. 从** Target Source Set 旁边的下拉菜单中,选择 debug**。
  4. 点击** Finish**。
debug-directories.png

打包时,Gradle要如何构建呢?

Gradle查找目录的优先级顺序

  1. src/demoDebug/ (构建variant源集)
  2. src/debug/ (构建类型源集)
  3. src/demo/ (productFlavors源集)
  4. src/main/ (主源集)
  5. library (依赖库)

Gradle构建规则

Java 类合并

集中编译 java/ 目录中的所有源代码以生成单一的输出

注:对于给定的构建变体,如果找到两个或两个以上定义同一 Java 类的源集目录,Gradle 就会引发一个构建错误。例如,在构建调试 APK 时,您不能同时定义 src/debug/Utility.java and src/main/Utility.java。这是因为 Gradle 会在构建过程中检查这两个目录并引发“duplicate class”错误。如果您需要针对不同的构建类型构建不同版本的 Utility.java,您可以让每个构建类型定义自己的文件版本,而不将其包含在 main/ 源集中。

清单文件合并

合并工具通过基于每个清单文件的优先级顺序地合并它们将所有清单文件组合成一个文件,如图:


manifest-merger_2x.png
清单文件合并规则:
  1. <manifest>元素中的属性从不会合并在一起 - 只使用来自最高优先级清单的属性。
  2. <uses-feature>和<uses-library>元素中的android:required属性使用OR合并,因此如果存在冲突,则应用“true”,并且始终包括一个清单所需的功能部件或库。
  3. <uses-sdk>元素中的属性始终使用优先级更高的清单中的值,但以下情况除外:
  • 当优先级较低的清单具有更高的minSdkVersion值时,会发生错误,除非您应用 overrideLibrary
    合并规则。
    main的清单文件如下定义时,其他清单文件定义的minSdkVersion比main中的还低时就不会报错:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.example.app"
          xmlns:tools="http://schemas.android.com/tools">
  <uses-sdk android:targetSdkVersion="22" android:minSdkVersion="2"
            tools:overrideLibrary="com.example.lib1, com.example.lib2"/>
...
  • 当优先级较低的清单的targetSdkVersion值较低时,合并工具使用来自较高优先级清单的值,但它还会添加必要的系统权限,以确保导入的库继续正常工作(对于其中较高的Android版本已经增加了许可限制)。有关此行为的详细信息,请参阅 implicit system permissions
  1. <intent-filter>元素永远不会在清单之间匹配。每个都被视为唯一,并添加到合并清单中的公共父元素。
  2. 对于属性之间的所有其他冲突,您将收到错误,并且必须通过在更高优先级的清单文件中添加特殊属性来指示合并工具如何解决它(请参阅merge rule markers
Element Merge policy Match key
<action> Merge android:name attribute
<activity> Merge android:name attribute
<application> Merge There is only one per <manifest>
<category> Merge android:name attribute
<data> Merge There is only one per <intent-filter>
<grant-uri-permission> Merge There is only one per <provider>
<instrumentation> Merge android:name attribute
<intent-filter> Keep No matching; several declarations within the parent element are allowed
<manifest> Merge children only There is only one per file
<meta-data> Merge android:name attribute
<path-permission> Merge There is only one per <provider>
<permission-group> Merge android:name attribute
<permission> Merge android:name attribute
<permission-tree> Merge android:name attribute
<provider> Merge android:name attribute
<receiver> Merge android:name attribute
<screen> Merge android:screenSize attribute
<service> Merge android:name attribute
<supports-gl-texture> Merge android:name attribute
<supports-screen> Merge There is only one per <manifest>
<uses-configuration> Merge There is only one per <manifest>
<uses-feature> Merge android:name attribute (if not present, then the android:glEsVersion attribute)
<uses-library> Merge android:name attribute
<uses-permission> Merge android:name attribute
<uses-sdk> Merge There is only one per <manifest>
Custom elements Merge No matching; these are unknown to the merger tool so they are always included in the merged manifest
标记合并规则
node
  1. tools:node="merge",默认行为
    低优先级manifest:
<activity android:name=”com.example.ActivityOne”
    android:windowSoftInputMode=”stateUnchanged”>
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

高优先级manifest:

<activity android:name=”com.example.ActivityOne”
    android:screenOrientation=”portrait”
    tools:node="merge”>
</activity>

合并后的manifest:

<activity android:name=”com.example.ActivityOne”
    android:screenOrientation=”portrait”
    android:windowSoftInputMode=”stateUnchanged”>
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>
  1. tools:node="merge-only-attributes"
    低优先级manifest:
<activity android:name=”com.example.ActivityOne”
    android:windowSoftInputMode=”stateUnchanged”>
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <data android:type="image/*" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

高优先级manifest:

<activity android:name=”com.example.ActivityOne”
    android:screenOrientation=”portrait”
    tools:node="merge-only-attributes”>
</activity>

合并后的manifest:

<activity android:name=”com.example.ActivityOne”
    android:screenOrientation=”portrait”
    android:windowSoftInputMode=”stateUnchanged”>
</activity>
  1. tools:node="remove"
    低优先级manifest:
<activity-alias android:name=”com.example.alias”>
  <meta-data android:name=”cow”
      android:value=”@string/moo”/>
  <meta-data android:name=”duck”
      android:value=”@string/quack”/>
</activity-alias>

高优先级manifest:

<activity-alias android:name=”com.example.alias”>
  <meta-data android:name=”cow”
      tools:node=”remove”/>
</activity-alias>

合并后的manifest:

<activity-alias android:name=”com.example.alias”>
  <meta-data android:name=”duck”
      android:value=”@string/quack”/>
</activity-alias>
  1. tools:node="removeAll"
    低优先级manifest:
<activity-alias android:name=”com.example.alias”>
  <meta-data android:name=”cow”
      android:value=”@string/moo”/>
  <meta-data android:name=”duck”
      android:value=”@string/quack”/>
</activity-alias>

高优先级manifest:

<activity-alias android:name=”com.example.alias”>
  <meta-data tools:node=”removeAll”/>
</activity-alias>

合并后的manifest:

<activity-alias android:name=”com.example.alias”>
</activity-alias>
  1. tools:node="replace"
    低优先级manifest:
<activity-alias android:name=”com.example.alias”>
  <meta-data android:name=”cow”
      android:value=”@string/moo”/>
  <meta-data android:name=”duck”
      android:value=”@string/quack”/>
</activity-alias>

高优先级manifest:

<activity-alias android:name=”com.example.alias”
    tools:node=”replace”>
  <meta-data android:name=”fox”
      android:value=”@string/dingeringeding”/>
</activity-alias>

合并后的manifest:

<activity-alias android:name=”com.example.alias”>
  <meta-data android:name=”fox”
      android:value=”@string/dingeringeding”/>
</activity-alias>
  1. tools:node="strict",如果优先级较低的清单只是包含一个额外的属性,都会构建失败(而默认行为将额外的属性添加到合并的清单中)。
    低优先级manifest:
<activity android:name=”com.example.ActivityOne”
    android:windowSoftInputMode=”stateUnchanged”>
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

高优先级manifest:

<activity android:name=”com.example.ActivityOne”
    android:screenOrientation=”portrait”
    tools:node="strict”>
</activity>

合并后的manifest:报错

Attribute
  1. tools:remove="attr, ..."
    低优先级manifest:
<activity android:name=”com.example.ActivityOne”
    android:windowSoftInputMode=”stateUnchanged”>

高优先级manifest:

<activity android:name=”com.example.ActivityOne”
    android:screenOrientation=”portrait”
    tools:remove=”android:windowSoftInputMode”>

合并后的manifest:

<activity android:name=”com.example.ActivityOne”
    android:screenOrientation=”portrait”>
  1. tools:replace="attr, ..."
    低优先级manifest:
<activity android:name=”com.example.ActivityOne”
    android:theme=”@oldtheme”
    android:exported=”false”
    android:windowSoftInputMode=”stateUnchanged”>

高优先级manifest:

<activity android:name=”com.example.ActivityOne”
    android:theme=”@newtheme”
    android:exported=”true”
    android:screenOrientation=”portrait”
    tools:replace=”android:theme,android:exported”>

合并后的manifest:

<activity android:name=”com.example.ActivityOne”
    android:theme=”@newtheme”
    android:exported=”true”
    android:screenOrientation=”portrait”
    android:windowSoftInputMode=”stateUnchanged”>
  1. tools:strict="attr, ...",当优先级较低的清单中的这些属性在较高优先级清单中不完全匹配时,则构建失败。
    低优先级manifest:
<activity android:name=”com.example.ActivityOne”
    android:screenOrientation=”landscape”>
</activity>

高优先级manifest:

<activity android:name=”com.example.ActivityOne”
    android:screenOrientation=”portrait”
    tools:strict="android:screenOrientation”>
</activity>

合并后的manifest:报错

tools:selector

将合并规则标记仅应用于特定导入的库。

<permission android:name="permissionOne"
    tools:node="remove"
    tools:selector="com.example.lib1">
如何查看清单文件合并冲突?
manifest-merged-view_2x.png

如果您想查看合并的完整日志,您可以在模块的build / outputs / logs /目录中找到名为manifest-merger-buildVariant-report.txt的日志文件

values合并

例如存在两个 strings.xml 文件,将按照上述列表中的相同顺序指定优先级。也就是说,在构建类型源集中的文件中定义的值将会替换产品风味中同一文件中定义的值,依此类推。

res和asset合并

如果两个或两个以上的源集中定义有同名资源,将按照上述列表中的相同顺序指定优先级。

库模块依赖项合并

Gradle 会为随库模块依赖项包含的资源和清单分配最低的优先级

如何添加依赖?

直接依赖项分类

模块依赖项

 // Dependency on the "mylibrary" module from this project
    compile project(":mylibrary")

远程依赖项

// Remote binary dependency
    compile 'com.android.support:appcompat-v7:25.1.0'

本地依赖项

 // Local binary dependency
    compile fileTree(dir: 'libs', include: ['*.jar'])

如何生成依赖项树?

demoDebug
\--- com.android.support:appcompat-v7:24.2.1
     +--- com.android.support:support-v4:24.2.1
     |    +--- com.android.support:support-compat:24.2.1
     |    |    \--- LOCAL: internal_impl-24.2.1.jar
     |    +--- com.android.support:support-media-compat:24.2.1
     |    |    +--- LOCAL: internal_impl-24.2.1.jar
     |    |    \--- com.android.support:support-compat:24.2.1
     |    |         \--- LOCAL: internal_impl-24.2.1.jar
     |    +--- com.android.support:support-core-utils:24.2.1
     |    |    +--- LOCAL: internal_impl-24.2.1.jar
     |    |    \--- com.android.support:support-compat:24.2.1
     |    |         \--- LOCAL: internal_impl-24.2.1.jar
     |    +--- com.android.support:support-core-ui:24.2.1
     |    |    +--- LOCAL: internal_impl-24.2.1.jar
     |    |    \--- com.android.support:support-compat:24.2.1
     |    |         \--- LOCAL: internal_impl-24.2.1.jar
     |    \--- com.android.support:support-fragment:24.2.1
     |         +--- LOCAL: internal_impl-24.2.1.jar
     |         +--- com.android.support:support-compat:24.2.1
     |         |    \--- LOCAL: internal_impl-24.2.1.jar
     |         +--- com.android.support:support-media-compat:24.2.1
     |         |    +--- LOCAL: internal_impl-24.2.1.jar
     |         |    \--- com.android.support:support-compat:24.2.1
     |         |         \--- LOCAL: internal_impl-24.2.1.jar
     |         +--- com.android.support:support-core-ui:24.2.1
     |         |    +--- LOCAL: internal_impl-24.2.1.jar
     |         |    \--- com.android.support:support-compat:24.2.1
     |         |         \--- LOCAL: internal_impl-24.2.1.jar
     |         \--- com.android.support:support-core-utils:24.2.1
     |              +--- LOCAL: internal_impl-24.2.1.jar
     |              \--- com.android.support:support-compat:24.2.1
     |                   \--- LOCAL: internal_impl-24.2.1.jar
     +--- com.android.support:support-vector-drawable:24.2.1
     |    \--- com.android.support:support-compat:24.2.1
     |         \--- LOCAL: internal_impl-24.2.1.jar
     \--- com.android.support:animated-vector-drawable:24.2.1
          \--- com.android.support:support-vector-drawable:24.2.1
               \--- com.android.support:support-compat:24.2.1
                    \--- LOCAL: internal_impl-24.2.1.jar

demoDebugAndroidTest
\--- com.android.support.test.espresso:espresso-core:2.2.2
     +--- com.android.support.test:rules:0.5
     |    \--- com.android.support.test:runner:0.5
     |         \--- com.android.support.test:exposed-instrumentation-api-publish:0.5
     +--- com.android.support.test:runner:0.5
     |    \--- com.android.support.test:exposed-instrumentation-api-publish:0.5
     \--- com.android.support.test.espresso:espresso-idling-resource:2.2.2

demoDebugUnitTest
No dependencies

demoRelease
......

demoReleaseUnitTest
No dependencies
  1. 点击 IDE 窗口右侧的 Gradle
  2. 导航至 MyApplication > Tasks > android 并双击 androidDependencies
  3. 要查看报告,请单击 IDE 窗口底部的 Gradle Console

如需了解在 Gradle 中管理依赖项的详细信息,请参阅《Gradle 用户指南》中的依赖项管理基础知识

如何配置依赖项?

compile

Gradle 将此配置的依赖项添加到类路径和应用的 APK。这是默认配置。

apk

指定 Gradle 需要将其与应用的 APK 一起打包的运行时依赖项。您可以将此配置与 JAR 二进制依赖项一起使用,而不能与其他库模块依赖项或 AAR 二进制依赖项一起使用。

provided

指定 Gradle 不与应用的 APK 一起打包的编译时依赖项。如果运行时无需此依赖项,这将有助于缩减 APK 的大小。您可以将此配置与 JAR 二进制依赖项一起使用,而不能与其他库模块依赖项或 AAR 二进制依赖项一起使用。

如何使用Gradle签名打包?

  1. 创建密钥
  2. 创建私钥
  3. 将签名配置添加到模块级 build.gradle 文件中:
...
android {
    ...
    defaultConfig {...}
    signingConfigs {
        release {
            storeFile file("myreleasekey.keystore")
            storePassword "password"
            keyAlias "MyReleaseKey"
            keyPassword "password"
        }
    }
    buildTypes {
        release {
            ...
            signingConfig signingConfigs.release
        }
    }
}

注:将发布密钥和密钥库的密码放在构建文件中并不安全。作为替代方案,您可以将此构建文件配置为通过环境变量获取这些密码,或让构建流程提示您输入这些密码。

如何以安全地方式获取密码?

过环境变量获取这些密码

storePassword System.getenv("KSTOREPWD")
keyPassword System.getenv("KEYPWD")

从命令行调用此构建时提示您输入这些密码

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

推荐阅读更多精彩内容