AndroidStudio编译配置

1、概述

AndroidStudio的编译系统编译app的资源文件和代码,打包为一个可测试、部署、签名、发布的apk。Android Studio使用一个高级的编译工具:gradle,该工具可以自由灵活的客制化,自动生成和管理编译进度。编译app,编译配置可以有公共部分,每一个编译配置文件也可以有自己单独的编译文件和资源。使用gradle和针对gradle的Android插件,和编译工具包共同提供编译进程和可配置的编译设置,这些说明app的编译和测试。

Gradle和Android插件独立于AndroidStudio运行。这意味着我们可以有多重方式编译app,如命令行、持续集成服务器、AndroidStudio.无论哪一种方式,都可以编译出相同的输出。

2、命令行编译

命令行编译,使用的是Gradle wrapper命令行工具。命令在工程的根目录下执行。

2.1 查看可编译目标

gradlew task-name

例如:

D:\AndroidProjects\HalService>gradlew tasks

> Task :tasks

------------------------------------------------------------
Tasks runnable from root project
------------------------------------------------------------

Android tasks
-------------
androidDependencies - Displays the Android dependencies of the project.
signingReport - Displays the signing info for the base and test modules
sourceSets - Prints out all the source sets defined in this project.

Build tasks
-----------
assemble - Assembles the outputs of this project.
assembleAndroidTest - Assembles all the Test applications.
build - Assembles and tests this project.
buildDependents - Assembles and tests this project and all projects that depend on it.
buildNeeded - Assembles and tests this project and all projects it depends on.
bundle - Assemble bundles for all the variants.
classes - Assembles main classes.

...

lint - Runs lint on all variants.
lintDebug - Runs lint on the Debug build.
lintRelease - Runs lint on the Release build.
lintVitalRelease - Runs lint on just the fatal issues in the release build.
test - Runs the unit tests.
testDebugUnitTest - Run unit tests for the debug build.
testReleaseUnitTest - Run unit tests for the release build.

Rules
-----
Pattern: clean<TaskName>: Cleans the output files of a task.
Pattern: build<ConfigurationName>: Assembles the artifacts of a configuration.
Pattern: upload<ConfigurationName>: Assembles and uploads the artifacts belonging to a configuration.

To see all tasks and more detail, run gradlew tasks --all

To see more detail about a task, run gradlew help --task <task>

2.2 编译debug版本apk

gradlew assembleDebug

生成apk在project_name/module_name/build/outputs/apk/目录下,该apk已使用默认debug签名和压缩对齐。

安装debug版本apk

gradlew installDebug

Debug可以被替换为已定义的BuildType。debug是默认就有的编译类型,无需显示定义,其他类型需要显示定义。

清除编译缓存

gradlew cleanBuildCache

3、配置自动签名

3.1 配置签名

android {
    ...
    defaultConfig { ... }
    signingConfigs {
        release {
            // You need to specify either an absolute path or include the
            // keystore file in the same directory as the build.gradle file.
            storeFile file("my-release-key.jks")
            storePassword "password"
            keyAlias "my-alias"
            keyPassword "password"
        }
    }
    buildTypes {
        release {
            signingConfig signingConfigs.release
            ...
        }
    }
}

3.2 编译release版本

在配置文件中配置签名文件后,就可以使用

gradlew installRelease 

编译release版本

4、自定义编译变体

4.1 Build types

自定义编译类型可以指定该编译类型具有的编译特性。例如增加编译类型staging

android {
    defaultConfig {
        manifestPlaceholders = [hostName:"www.example.com"]
        ...
    }
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }

        debug {
            applicationIdSuffix ".debug"
            debuggable true
        }

        /**
         * The `initWith` property allows you to copy configurations from other build types,
         * then configure only the settings you want to change. This one copies the debug build
         * type, and then changes the manifest placeholder and application ID.
         */
        staging {
            initWith debug
            manifestPlaceholders = [hostName:"internal.example.com"]
            applicationIdSuffix ".debugStaging"
        }
    }
}

可配置的属性,详见“build type DSL reference

4.2 Product flavors

4.21 概述

不同风味的产品代表不同的版本release给用户使用,例如免费的和收费的。可以通过不同的代码和资源定义不同分为的版本软件。定义不同风味的版本,是可选功能,且只能手动创建。
创建不同风味的软件版本,和自定义编译类型方式类似。创建不同风味版本,在productFlavors块中添加需要的配置。风味的产品定义都支持如defaultConfig的属性,该属性属于ProductFlavor类。这意味着,不同风味产品的共有属性可以在defaultConfig中配置,各风味产品可以修改需要修改的属性。
每一个风味类型必须属于一个风味盒(a named flavor dimension),风味盒是不同风味产品的集合。所有的风味产品必须有一个风味盒,否则,编译会出错。如果给定的module只有一个风味盒,gradle插件会默认分配所有的module的风味到这个风味盒。
例:创建一个命名为“version”的风味盒且添加“demo”和“full”风味产品。

android {
    ...
    defaultConfig {...}
    buildTypes {
        debug{...}
        release{...}
    }
    // Specifies one flavor dimension.
    flavorDimensions "version"
    productFlavors {
        demo {
            // Assigns this product flavor to the "version" flavor dimension.
            // If you are using only one dimension, this property is optional,
            // and the plugin automatically assigns all the module's flavors to
            // that dimension.
            dimension "version"
            applicationIdSuffix ".demo"
            versionNameSuffix "-demo"
        }
        full {
            dimension "version"
            applicationIdSuffix ".full"
            versionNameSuffix "-full"
        }
    }
}

创建完成不同风味产品配置后,点击Sync Now,同步代码。同步完成后,gradle会自动根据编译类型和产品风味创建编译变体,命名为“”,例如,创建了demo、full两种风味产品,有默认的debug、release两种编译类型,gradle会创建一下编译变体:

  • demoDebug
  • demoRelease
  • fullDebug
  • fullRelease

可以通过Build > Select Build Variant 选择想要编译和运行的变体。
为了定制化不同编译变体,使用于不同的特性和资源,需要给不同的变体配置不同的资源,详见下文的“创建和管理资源集”。

4.2.2 多个风味产品和风味盒结合

在一些情况下,可能会需要根据不同风味合并成一个配置。例如,要创建不同配置的风味产品“fulll”、“demo”,每个风味产品又会基于不同的api创建。这种情况下,gradle插件提供可配置多个风味盒,编译时gradle会合并每个风味盒中的一个风味产品配置到一个配置,相同风味盒中的产品配置不会合并。风味产品配置合并完后和编译类型组合,形成不同的编译变体。(也即不同的风味盒中的风味产品配置、编译类型做组合)。通过flavorDimensions定义不同的风味盒。
定义不同的风味盒,合并不同风味产品配置,形成不同编译变体,例如下:

android {
  ...
  buildTypes {
    debug {...}
    release {...}
  }

  // Specifies the flavor dimensions you want to use. The order in which you
  // list each dimension determines its priority, from highest to lowest,
  // when Gradle merges variant sources and configurations. You must assign
  // each product flavor you configure to one of the flavor dimensions.
  flavorDimensions "api", "mode"

  productFlavors {
    demo {
      // Assigns this product flavor to the "mode" flavor dimension.
      dimension "mode"
      ...
    }

    full {
      dimension "mode"
      ...
    }

    // Configurations in the "api" product flavors override those in "mode"
    // flavors and the defaultConfig block. Gradle determines the priority
    // between flavor dimensions based on the order in which they appear next
    // to the flavorDimensions property above--the first dimension has a higher
    // priority than the second, and so on.
    minApi24 {
      dimension "api"
      minSdkVersion 24
      // To ensure the target device receives the version of the app with
      // the highest compatible API level, assign version codes in increasing
      // value with API level. To learn more about assigning version codes to
      // support app updates and uploading to Google Play, read Multiple APK Support
      versionCode 30000 + android.defaultConfig.versionCode
      versionNameSuffix "-minApi24"
      ...
    }

    minApi23 {
      dimension "api"
      minSdkVersion 23
      versionCode 20000  + android.defaultConfig.versionCode
      versionNameSuffix "-minApi23"
      ...
    }

    minApi21 {
      dimension "api"
      minSdkVersion 21
      versionCode 10000  + android.defaultConfig.versionCode
      versionNameSuffix "-minApi21"
      ...
    }
  }
}
...

形成12中编译变体如下:
[minApi24, minApi23, minApi21][Demo, Full][Debug, Release]
生成apk有:
app-[minApi24, minApi23, minApi21]-[demo, full]-[debug, release].apk
具体编译结果如下:
Build variant: minApi24DemoDebug
Corresponding APK: app-minApi24-demo-debug.apk
可以为不同的风味产品创建目录,放置和该风味相关的资源文件,如src/demoMinApi24/java/。具体不同编译变体如何组织和合并资源,详见下文的“创建资源集”。

4.3 过滤变体

若定义多个风味产品配置,gradle编译后组成多个编译变体,若其中一些变体是不需要的,可以通过过滤规则过滤掉不需要的变体。
例如不需要demo风味产品的API小于23的变体

android {
  ...
  buildTypes {...}

  flavorDimensions "api", "mode"
  productFlavors {
    demo {...}
    full {...}
    minApi24 {...}
    minApi23 {...}
    minApi21 {...}
  }

  variantFilter { variant ->
      def names = variant.flavors*.name
      // To check for a certain build type, use variant.buildType.name == "<buildType>"
      if (names.contains("minApi21") && names.contains("demo")) {
          // Gradle ignores any variants that satisfy the conditions above.
          setIgnore(true)
      }
  }
}
...

配置完成后,同步代码,gradle会忽略不需要的变体。

4.4 创建资源集

默认情况下,Android Studio创建了main/资源集,该目录下的资源被所有变体共用。当然,我们也可以为具体的某个风味版本、编译类型、编译变体创建特有的资源集,如此情况下,在main/资源集下放置共用的基础功能资源,其他资源集按照关联特性放置资源。
Gradle规定新增的资源集需要按照main/资源集的组织结构。例如,为debug编译类型创建一个资源集,资源集目录为src/debug/java/
Android插件为Gradle提供了一个很好用的Gradle task功能,告诉我们怎样组织新增的资源集。如下例,使用Gradle task功能,可以输出一个描述文件,文件中告诉我们:新增一个debug编译类型的资源集,资源集中文件的组织结构应该是怎样的。

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

...

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

注:文档中描述的生成该描述文件的方法,在最新版本的AndroidStudio中没有找到,这里不做说明。
当生成一个新的编译变体,Android Studio创建该变体的资源集,但提供了创建向导:

  1. 项目结构选在project显示
  2. 打开到MyProject/app/src/
  3. 右击src,New->Floder->[select source type]
  4. 后面就是创建向导,在向导页面选择Target Source Set,例如debug
  5. 完成

利用该向导可以创建需要的资源集。

4.5 修改默认资源集

如果创建了和Gradle默认定义的目录结构不同的资源集,这种情况可以在module下的build.gradle配置资源集,配置使用的属性详见“Android plugin for Gradle DSL reference”,部分内容如下:
在这里插入图片描述
以下示例,改变main/moudle的资源集内容和修改androidTest的根目录

android {
  ...
  sourceSets {
    // Encapsulates configurations for the main source set.
    main {
      // Changes the directory for Java sources. The default directory is
      // 'src/main/java'.
      java.srcDirs = ['other/java']

      // If you list multiple directories, Gradle uses all of them to collect
      // sources. Because Gradle gives these directories equal priority, if
      // you define the same resource in more than one directory, you get an
      // error when merging resources. The default directory is 'src/main/res'.
      res.srcDirs = ['other/res1', 'other/res2']

      // Note: You should avoid specifying a directory which is a parent to one
      // or more other directories you specify. For example, avoid the following:
      // res.srcDirs = ['other/res1', 'other/res1/layouts', 'other/res1/strings']
      // You should specify either only the root 'other/res1' directory, or only the
      // nested 'other/res1/layouts' and 'other/res1/strings' directories.

      // For each source set, you can specify only one Android manifest.
      // By default, Android Studio creates a manifest for your main source
      // set in the src/main/ directory.
      manifest.srcFile 'other/AndroidManifest.xml'
      ...
    }

    // Create additional blocks to configure other source sets.
    androidTest {

      // If all the files for a source set are located under a single root
      // directory, you can specify that directory using the setRoot property.
      // When gathering sources for the source set, Gradle looks only in locations
      // relative to the root directory you specify. For example, after applying the
      // configuration below for the androidTest source set, Gradle looks for Java
      // sources only in the src/tests/java/ directory.
      setRoot 'src/tests'
      ...
    }
  }
}
...

4.6 编译资源集

可以使用资源集放置不同的代码和资源。例如,如果编译“demo”、“debug”的变体“demoDebug”,编译资源为不同资源集的笛卡尔积(相同文件名使用高优先级的,不同的部分做并集处理),编译的优先级书序如下(从高到低):

  1. src/demoDebug/ (变体的资源集)
  2. src/debug/ (编译类型的资源集)
  3. src/demo/ (风味版本的资源集)
  4. src/main/ (主资源集)
    注意: 如果有多个风味版本类型,不同风味版本的结合优先级取决于不同风味版本在风味盒中的优先级。风味盒列表,排在前面的风味版本具有高优先级。另外,不同风味版本结合的资源集优先级高于单个风味版本的资源集。
    当有相同文件在不同资源集时,使用高优先级的资源集文件。Gradle处理优先级按照如下规则:
  • 所有java目录下的文件最终结合编译为一个输出。注意: 在编译一个具体的变体时,若多个资源集中包含相同的文件,会报错“duplicate class”,此时需要在各自的资源集中定义各自的文件,不要和main/资源集中的文件名相同。
  • Manifests 会被合并为一个Manifest。优先级同上说明,高优先级的重写低优先级的。具体合并规则,详见Merge multiple manifest files
  • values目录下的文件时合并。按照优先级,高优先级的重写低优先级的(非直接替换文件)。
  • res、assert目录下的文件按照优先级打包在一块。相同文件名按照优先级替换。
  • 最后,Gradle结合依赖库(最低优先级)中的资源和manifests编译出apk

4.7 声明依赖

可以通过在Implementation前面加前缀为编译变体或资源集指明各自的依赖。例如

dependencies {
    // Adds the local "mylibrary" module as a dependency to the "free" flavor.
    freeImplementation project(":mylibrary")

    // Adds a remote binary dependency only for local tests.
    testImplementation 'junit:junit:4.12'

    // Adds a remote binary dependency only for the instrumented test APK.
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}

5、增加编译依赖

详见“Add build dependencies

6、配置签名设置

给apk签名有两种方式:

  • 使用AndroidStudio,创建一个key,给apk签名
  • 手动配置一个签名设置,使用Gradle签名

第一种方式不做说明,第二中方式如下:

  1. 创建一个keystore,keystore包含一组私钥。
  2. 创建一个私钥,一个私钥代表app的标识
  3. 在module中的build.gradle增加如下配置:
...
android {
    ...
    defaultConfig {...}
    signingConfigs {
        release {
            storeFile file("myreleasekey.keystore")
            storePassword "password"
            keyAlias "MyReleaseKey"
            keyPassword "password"
        }
    }
    buildTypes {
        release {
            ...
            signingConfig signingConfigs.release
        }
    }
}

直接把密码写在代码中不是一个安全的方式,可以通过以下方式获取密码:

  1. 从环境变量获取密码
storePassword System.getenv("KSTOREPWD")
keyPassword System.getenv("KEYPWD")
  1. 终端输入
storePassword System.console().readLine("\nKeystore password: ")
keyPassword System.console().readLine("\nKey password: ")
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值