• Android开发之深入理解Android Studio构建文件build.gradle配置


    摘要:

    每周一次,深入学习Android教程,TeachCourse今天带来的一篇关于Android Studio构建文件build.gradle的相关配置。重点学习几个方面的内容:1、applicationIdpackage属性值的关系。2、怎么配置安全的自己定义签名,3、两种构建类型的差别,4、为什么要定制产品的偏好配置?,5、怎么才干加快DEX文件的生成速度。6、为什么要将一个apk拆分成多个?。7、关于引入依赖包你不知道的秘密。通过这篇文章的学习。你会对build.gradle文件有一个全新的认识,能够将TeachCourse文章提到的相关说明作为文档參考,方便在还有一个module中引入。代码例如以下:

    apply plugin: 'com.android.application'
    
    android {
        compileSdkVersion 24
        buildToolsVersion "25.0.2"
        /**
         * 一、默认产品偏好配置
         */
        defaultConfig {
            ...
        }
        /**
         * 二、自己定义签名配置
         */
        signingConfigs {
            config {
              ...
            }
        }
        /**
         * 三、构建类型。分为release和debug两种
         */
        buildTypes {
            release {
              ...
            }
            debug {
              ...
            }
        }
        /**
         * 四、自己定义产品偏好配置。能够定义多个偏好产品
         */
        productFlavors {
            demo {
                applicationId "cn.teahcourse.demo"
                versionName "1.0-demo"
                signingConfig signingConfigs.config
            }
            personal{
              ...
            }
            enterprise{
              ...
            }
        }
        /**
         *五、DEX文件构建属性配置(加快构建速度)
         */
        dexOptions {
            ...
        }
        /**
         * 六、将一个apk拆分成多个相关配置(拆分根据:屏幕密度、系统架构)
         */
        splits {
            density {
               ...
            }
            abi {
               ...
            }
        }
    }
    /**
     * 七、引入依赖包的秘密
     */
    dependencies {
       ...
    }
    

    一、applicationIdpackage属性值的关系

    Android Studio开发工具创建module的时候,默认在build.gradle文件生成一个applicationId。相应的属性值是填写的package name,例如以下图:

    applicationId属性值

    这时候的applicationIdpackage属性值一样,刚開始接触Android Studio的时候。TeachCourse就听说applicationId表示真正的包名。而package不再被觉得是包名,由于应用程序被打包成apk文件的时候。原先在manifest声明的packageapplicationId取代,也就是说假设你的build.gradle文件加入了applicationId属性值,不管两者是否一样。打包的apk文件的package属性值等于applicationId。假设不信,TeachCourse先来做过实验,将applicationId改为cn.teachcourse.demo。将package改为cn.teachcourse。然后将module打包成apk文件,使用反编译工具apktool.exe。例如以下图:

    apktool反编译工具

    最后。打开AndroidManifest.xml文件。例如以下图:

    package被applicationId取代

    结果证明:cn.teachcoursecn.teachcourse.demo取代

    正是由于打包的apk文件的package的属性值被applicationId取代。也刚好说明为什么应用程序安装到手机后,手机上显示的是applicationId。而不是显示package,同一时候假设想在应用程序中接入第三方的API。填写的包名也必须是applicationId,常见的样例有:1.接入微信的支付功能,2.接入微信的分享功能,3.集成百度地图的定位功能

    那么,AndroidManifest.xmlpackage究竟有什么用呢?虽然。package在打包成apk的时候被applicationId取代。可是在构建的时候package有双方面的作用:

    第一个作用:package指定的文件夹下,生成相应的R.java文件,上面的样例。构建的时候,生成R文件的文件夹,例如以下图:

    appuildgeneratedsource
    demodebugcn	eachcourseR.java

    第二个作用:package指定的文件夹下,引用相应的activityserver组件。例如以下图:

    <!-- 定义Activity -->
    <activity android:name=".MainActivity"/>
    
    <!-- 加入service组件 -->
    <service android:name=".service.music.MusicService" />

    在上面反编译的AndroidManifest.xml文件里,查看相应的组件文件夹。例如以下图:

    package属性值作用

    也就是说,manifest指定的组件不管使用相对路径还是绝对路径。打包成apk文件后,都变成绝对路径,结构是:package.组件

    须要特别注意的问题有:
    第一个问题:代码中使用getPackageName()getPackageManager()相应的方法,返回的是applicationId属性值

    第二问题:使用WebView基本存放于res/raw内的文件时,假设applicationId不等于package,提示ClassNotFoundException异常(可能是官方的bug),TeachCourse測试后找到两个解决的办法

    1. 尝试将res/raw/note.html文件移动到assets文件夹下,更换资源文件载入路径
    mWebView.loadUrl("file:///android_asset/note.html");
    1. 保持applicationId属性值和package属性值一致
    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="cn.teahcourse.demo">
        ...
    </manifest>

    二、怎么配置安全的自己定义签名

    自己定义签名指的是使用开发人员导出的密钥库对apk文件进行签名,关于怎么生成自己的密钥库。不懂的同学,能够后面看一下TeachCourse还有一篇文章《Android Studio执行时自带签名配置过程具体解释》,文章介绍了怎么配置Android Studio的执行时签名,这样做的目的:在接入一些须要自己定义签名的API时。方便直接调试。

    这里。介绍的是安全的自己定义签名,即怎么才让别人看不到我们在build.gradle写入的password(包括别名password、密钥库password)。关于签名文件的重要性。TeachCourse在这里就不说了。

    * 2.1 配置安全的自己定义签名(1),步骤:*
    1. 在项目的根文件夹下创建一个名称为 keystore.properties 的文件。此文件应当包括您的签署信息。例如以下所看到的:

    storePassword=myStorePassword
    keyPassword=mykeyPassword
    keyAlias=myKeyAlias
    storeFile=myStoreFileLocation

    *这里须要注意:***keystore.propertiesstoreFile签名文件是相对module文件夹的路径,即将密钥库文件保存在module根文件夹下
    密钥库配置

    1. 在模块的 build.gradle 文件里,于 android {} 块的前面加入用于载入 keystore.properties 文件的代码。
    ...
    def keystorePropertiesFile = rootProject.file("keystore.properties")
    def keystoreProperties = new Properties()
    keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
    android {
        ...
    }

    注:您能够选择将 keystore.properties 文件存储在其它位置(比如。存储在模块文件夹中而不是项目的根文件夹中,或者假设您使用连续集成工具,也能够存储在构建服务器上)。在这样的情况下,您应当改动上面的代码。以便使用实际 keystore.properties 文件的位置正确初始化 keystorePropertiesFile。

    1. 您能够使用语法 keystoreProperties['属性名称'] 引用存储在 keystoreProperties 中的属性。改动模块 build.gradle 文件的 signingConfigs 块。以便使用此语法引用存储在 keystoreProperties 中的签署信息。
    android {
        signingConfigs {
            config {
                keyAlias keystoreProperties['keyAlias']
                keyPassword keystoreProperties['keyPassword']
                storeFile file(keystoreProperties['storeFile'])
                storePassword keystoreProperties['storePassword']
            }
        }
        ...
      }
    1. 最后,我们就能够依照《Android Studio执行时自带签名配置过程具体解释》介绍的方式,将signingConfigs 块作用于release版本号或debug版本号

    * 2.2 配置安全的自己定义签名(2)。步骤:*
    1. 另外一种安全的自己定义签名的方式是:将别名、别名password、密钥password以键值对的形式保存到当前电脑的环境变量中,然后通过变量名读取变量值,例如以下图:

    android {
        signingConfigs {
            config {
                keyAlias System.getenv("KEYALIAS")
                keyPassword System.getenv("KEYPWD")
                storeFile file('release.jks')
                storePassword System.getenv("KSTOREPWD")
            }
        }
        ...
      }
    1. KEYALIAS指的是环境变量的变量名,System.getenv("KEYALIAS")的读取变量名相应的变量值,如图:
      读取环境变量值

    2. KEYPWD。依照上图的方式加入。例如以下图:
      加入KEYPWD环境变量

    3. KSTOREPWD以相同的方式。例如以下图:
      加入KSTOREPWD环境变量

    须要特别注意的是:另外一种自己定义签名的方式,须要先检查Android Studio是否已配置了gradle工具的环境变量,打开Android Studio的terminal窗体,输入:gradle build。例如以下图:

    检查gradle环境变量

    假设,你的terminal窗体提示gradle不是内部命令,操作上述步骤之前。你得加入gradle工具的环境变量。Android Studio的gradle工具默认存放路径:

    C:Program FilesAndroidAndroid Studiogradlegradle-3.2

    配置gradle的环境变量。例如以下图:

    加入gradle根文件夹

    加入gradle到path变量中

    三、两种构建类型的差别

    每个APP至少包括debugrelease两种构建类型。debug定义APP的调试版本号,debug模式的几个特点:

    1. 支持断点调试和log打印信息。debuggable属性值为true
    2. 使用系统默认的密钥库签署apk文件
    3. 没有对apk文件进行代码和资源文件的优化(包括文件压缩、冗余文件删除)
    4. 没有对代码进行混淆

    release定义APP的公布版本号,创建项目module中的build.gradle文件,代码例如以下:

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

    minifyEnable定义是否压缩代码,false表示不压缩;proguardFiles定义混淆代码的默认混淆规则,proguard-android.txt表示系统自带的混淆规则。proguard-rules.pro位于当前module根文件夹下,用于定义开发人员自己的混淆规则。

    release模式须要注意的几个特点:
    1. 不支持断点调试。debuggable默觉得false
    2. 没有压缩类文件代码,minifyEnabled。默觉得false
    3. 没有压缩资源文件。shrinkResources。默觉得false
    4. 没有指定自己定义签名文件。默认使用系统的密钥库签署apk

    开发人员在公布应用程序时。须要对release模式下的属性配置进行改动,优化apk文件,删除没用的代码和资源文件,混淆类文件和资源名称,自己定义签名密钥库,代码例如以下:

    release {
        shrinkResources true
        minifyEnabled true
        useProguard true
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        signingConfig signingConfigs.config
    }

    总结:debugrelease模式,最大的差别默认属性配置不一样。两种模式支持的属性配置还包括。例如以下图:

    debug和release相关配置

    debug和release相关配置

    记不住代码的同学,能够选中Build Types定义的模式,在可选项中改变相应属性配置。Android Studio执行时签名的实质将debug模式下的Signing Config设置为自己定义密钥库文件,可是TeachCourse随着不断深入学习后发现,事实上debug模式下配置Signing Config多此一举,而仅仅要在release模式下配置Signing Config就够了,Android Studio的能够方便为我们生成两种模式下相应的apk文件,在Android Studio的左下角Build Variant中切换。例如以下图:

    切换debug或release构建类型

    以下介绍了产品偏好配置后。回头再看看它们两者之间的关系。

    四、为什么要定制产品的偏好配置?

    什么是产品的偏好配置呢?比方说,TeachCourse想要开发一个应用程序,包括个人版本号personal和企业版本号enterprise,这两个版本号之间在功能上有所差别,企业版自然比个人版功能要多一些,非常明显就是要就一个Android项目打包成两个产品公布。它们之间的要求例如以下所看到的:

    personal:版本号号为1,最低SDK版本号定义为11。最高SDK定义为24,版本号名称后缀定义为-personal,applicationId后缀定义为-per,签名文件为自己定义密钥库,代码例如以下:

    personal {
        versionCode 1
        minSdkVersion 11
        targetSdkVersion 24
        versionNameSuffix '-personal'
        applicationIdSuffix '-per'
        signingConfig signingConfigs.config
    }
    

    enterprise:版本号号为1000。最低SDK版本号定义为11,最高SDK定义为24,版本号名称后缀定义为-profession。applicationId后缀定义为-pro,签名文件为自己定义密钥库代码例如以下:

    enterprise {
        versionCode 1000
        minSdkVersion 11
        targetSdkVersion 24
        versionNameSuffix '-profession'
        applicationIdSuffix 'full'
        signingConfig signingConfigs.config
    }
    

    同一时候。TeachCourse定义第三个产品偏好配置为demo,用于上传GitHub,提供下载,代码例如以下:

    demo {
        applicationId "cn.teahcourse.demo"
        versionName "1.0-demo"
        signingConfig signingConfigs.config
    }

    一个Android项目。配置三个偏好的产品,即使改动了项目代码,也能够高速编译并打包三个apk文件,在Android Studio的左下角Build Variant中切换。例如以下图:

    产品偏好配置

    看上面的图片,你是不是发现了什么,突然间,三个偏好配置的产品,出现了6个变体。一个产品包括debugrelease两个版本号,构建类型和偏好产品之间的关系是:一个偏好产品,肯定包括一个debug版本号和一个release版本号,能够生成变体的总数为flavors*2。选中须要调试的版本号或选中须要公布的版本号,Android Studio自己主动又一次构建Android项目,就能够针对指定的产品进行调试或打包,非常的方便吧!

    偏好产品相关配置,例如以下图:

    产品偏好配置

    defaultConfig也属于当中一种偏好产品,在我们未定义自己的偏好产品时,我们构建和编译的就是默认的defaultConfig这个产品,也就仅仅包括debugrelease两个变体。

    五、怎么才干加快DEX文件的生成速度?

    你有没有遇到Android Studio在每次构建的时候,都感觉花好长时间。TeachCourse就不止一次和同事抱怨说,Android Studio的编译速度还不如Eclipse快,蜗牛的速度真受不了呀?那该怎么办呢?

    Android Studio提供dexOption区块以便于我们配置DEX构建属性。加快DEX文件的生成速度,代码例如以下:

      dexOptions {
        preDexLibraries true
        maxProcessCount 8
        javaMaxHeapSize "2048m"
      }
    • preDexLibraries声明是否预先编译依赖库,从而加快构建速度,实质是通过延时清除已生成的依赖库的构建文件。从而提高构建速度,根据使用情况合理配置。
    • maxProcessCount设置进程执行过程中能够使用的最大线程数。

      默认值为4。

    • javaMaxHeapSize设置DEX编译器的最大堆大小,堆或者栈都是用于存放临时不用的垃圾,当内存不足时。垃圾回收机制会清除过时的缓存,堆大小决定垃圾清除的频率,影响着构建的速度

    六、为什么要将一个apk拆分成多个?

    根据TeachCourse以往的经验。一个apk文件能够支持不同屏幕密度和不同ABIs的手机设备,是由于我们进行了屏幕适配。做法:将市场主流的屏幕密度和ABIs集成到一个apk。造成的影响。假设你的应用程序本身就比較大,集成了不同屏幕密度和支持不同ABIs的代码。打包出来的apk文件变得更大。考虑到流量成本和用户体验。降低apk文件的大小当中一种方式将一个apk文件拆分成多个。

    Gradle能够单独指定仅仅包括一种屏幕密度或一种ABI代码和资源文件的apk,在build.gradle文件里使用到splits区块,splits区块内同一时候提供了按屏幕密度拆分density区块和按abi拆分abi区块,在一个build.gradle文件里能够同一时候指定两者或两者中的当中一者,以下分别介绍:

    * 6.1 按屏幕密度拆分*

    android {
      ...
      splits {
    
        density {
          enable true
          exclude "xxxhdpi"
          reset() 
          include "ldpi", "xxhdpi"
          compatibleScreens 'small', 'normal', 'large', 'xlarge'
        }
      }
    }

    上面是一个按屏幕密度拆分的一个样例,各个标签的含义是:
    - enable。是否基于定义的屏幕密度拆分成多个apk文件,默觉得false
    - exclude。指定忽略拆分的屏幕密度列表,想要拆分成很多其它类型的apk文件,该关键字包括的屏幕密度列表应就可能少
    - reset(),重置默认拆分的屏幕密度根据,然后使用include标签定义拆分的屏幕密度根据
    - include,结合reset一起使用,定义拆分的屏幕密度根据
    - compatibleScreens,指定兼容的屏幕尺寸列表,差别于屏幕密度,该标签将会在清单文件manifest中通过<compatible-screens>注入到每个apk文件里,即apk文件仅仅能安装到<compatible-screens>指定尺寸的手机上

    依照上面在build.gradle配置完毕后,点击Build APK后,将在apk文件夹内生成多个apk文件。例如以下图:

    按屏幕密度拆分apk

    为了验证是否在清单文件里注入指定屏幕尺寸,反编译当中一个apk文件。例如以下图:

    反编译apk文件

    * 6.2 按abi拆分*

    android {
      ...
      splits {
    
        abi {
    
          enable true
          reset()
          include "x86", "armeabi-v7a", "mips"
          universalApk false
        }
      }
    }

    上面是一个按abi拆分的一个样例,除了universal标签不一样外,其它标签是一样的,用法一样,include标签定义拆分的abi根据,关于abi介绍,參考以下连接:

    https://developer.android.google.cn/ndk/guides/abis.html

    相同,点击Build APK后,将在apk文件夹内生成多个apk文件。例如以下图:

    按abi拆分apk

    细致观察生成的apk文件,会发现以下两个规律:
    - 第一个规律:apk总数=abi数量+density数量xabi数量
    - 第二个规律:apk filename=modulename-screendensityABI-buildvariant.apk

    关于引入依赖包你不知道的秘密

    不知道你会不会有和TeachCourse一样的想法,dependencies区块引入的jar包的名称长,基本无法记住。每一节又表示什么含义?Android Studio引入依赖项有几种方式?让我先看以下的这个样例:

    dependencies {
        compile project(":mylibrary")
        compile files('libs/zxing.jar')
        compile fileTree(include: ['*.jar'], dir: 'libs')
        compile 'com.android.support:appcompat-v7:25.1.0'
        compile group: 'com.android.support', name: 'appcompat-v7', version: '25.1.0'
    }

    能够看到Android Studio引入依赖项的方式分为上述四种。按顺序依次称为:1、模块依赖项。2、本地二进制依赖项。3、本地二进制依赖项,4、远程二进制依赖项。5、远程二进制依赖项

    • compile project(':mylibrary') 行声明了一个名为mylibrary的本地 Android 库模块作为依赖项,并要求构建系统在构建应用时编译并包括该本地模块。

    • compile files('libs/zxing.jar')compile fileTree(dir: 'libs', include: ['*.jar'])都称为本地依赖项。告诉构建系统在编译类路径和终于的应用软件包中包括 app/libs/ 文件夹内的指定或所有 JAR 文件。

      假设您有模块须要本地二进制依赖项。请将这些依赖项的 JAR 文件拷贝到项目内部的 /libs 中。

    • compile 'com.android.support:appcompat-v7:25.1.0'compile group: 'com.android.support', name: 'appcompat-v7', version: '25.1.0'都称为远程二进制依赖项,通过指定其 JCenter 坐标。针对 Android 支持库的 25.1.0 版本号声明了一个依赖项。

      默认情况下,Android Studio 会将项目配置为使用顶级构建文件里的 JCenter 存储区。当您将项目与构建配置文件同步时,Gradle 会自己主动从 JCenter 中抽取依赖项。

      或者,您也能够通过使用 SDK 管理器下载和安装特定的依赖项。

    第五种能够清楚看出每一节表示的含义。在Android Studio引入远程二进制依赖项。通常的做法是在Library Dependency窗体中搜索,搜索到最新版本号的依赖项,例如以下图:

    加入远程依赖项

    似乎无法搜索到低版本号的依赖项。假设想要引入低版本号的,那该怎么办呢?假设先前不了解远程二进制依赖项的含义。可能想不到改动version的办法。如今就变得非常easy了。

    总结:

    本篇文章在阅读Android Studio用户指南多篇相关文档后完毕的。想要更具体深入学习gradle指令的同学,能够继续研读Gradle官网文档。部分内容在TeachCourse开发的项目没有相应的需求,临时也没实用到,是否使用很多其它应该根据项目实际情况而定,但能够作为用户开发的样例,先分享和收藏,以备不时之需。

    參考资料:
    https://developer.android.google.cn/studio/build/application-id.html
    https://developer.android.google.cn/studio/build/optimize-your-build.html
    https://developer.android.google.cn/studio/build/dependencies.html
    https://developer.android.google.cn/studio/build/build-variants.html

    版权声明:本文著作权归TeachCourse所有,未经许可禁止转载,谢谢支持!
    转载请注明出处:http://teachcourse.cn/2385.html

  • 相关阅读:
    excel成绩统计公式
    freebsd Cacti
    图片处理程序
    php 图片水印+文字水印函数,但是不能设置透明
    PHP计算两个时间之差的函数(年,月,周,日,小时,分钟,秒数)
    php图片水印(可以设置透明度)
    使用函数递归实现基于PHP和MySQL的动态树型菜单[转]
    PHP实现MYSQL备份
    FreeBSD备忘录转载
    超级简单但超级实用的 PHP 的 mysql 类
  • 原文地址:https://www.cnblogs.com/llguanli/p/8781466.html
Copyright © 2020-2023  润新知