zoukankan      html  css  js  c++  java
  • 《Gradle权威指南》--Android Gradle高级自定义

    No1:

    指定共享库

    <uses-library
        android:name="com.google.android.maps"
        android:required="true"/>

    No2:

    android除了标准的sdk,还存在两种库

    1)add-on库:位于add-ons目录下,大部分是第三方厂商或者公司开发的

    2)optional可选库:位于platforms/android-xx/optional目录下,一般是为了兼容旧版本的API,比如HttpClient的org.apache.http.legacy

    第一种Android Gradle会自动解析并添加到classpath里,第二种就不会

    No3:

    android{
        useLibrary 'org.apache.http.legacy'
    }

    No4:

    批量修改生成的apk文件名

    android{
        compileSdkVersion 23
        buildToolsVersion "23.0.1"
        useLibrary 'org.apache.http.legacy'
        
        defaultConfig{
            applicationId "org.flysnow.app.example92"
            minSdkVersion 14
            targetSdkVersion 23
            versionCode 1
            versionName "1.0"
        }
        buildTypes{
            release{
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android.txt'),'proguard-rules.pro'
                zipAlignEnabled true
            }
        }
        productFlavors{
            google{
                
            }
        }
        applicationVariants.all{
            variant->variant.outputs.each{
                output->if(output.outputFile!=null && output.outputFile.name.endsWith('.apk') && 'release'.equals(variant.buildType.name)){
                    def flavorName = variant.flavorName.startsWith("_")?variant.flavorName.substring(1) : variant.flavorName
                    def apkFile = new File(output.outputFile.getParent(),"Example92_${flavorName}_v${variant.versionName}_${buildTime()}.apk")
                    output.outputFile = apkFile
                }
            }
        }
    }
    
    def buildTime{
        def date = new Date()
        def formattedDate = date.format('yyyyMMdd')
        return formattedDate
    }

    每一个ApplicationVariant至少有一个或多个outputs输出

    No5:

    Android支持基于文件的模块化,就是apply from

    version.gradle文件

    ext{
        appVersionCode = 1
        appVersionName = "1.0.0"
    }

    build.gradle文件中引用

    apply from: 'version.gradle'

    No6:

    获取当前的tag名称

    git describe --abbrev=0 --tags

    No7:

    动态从git tag中获取应用的版本名称

    def getAppVersionName(){
        def stdout = new ByteArrayOutputStream()
        exec{
            commandLine 'git','describe','--abbrev=0','-tags'
            standardOutput = stdout
        }
        return stdout.toString()
    }

    调用

    android{
        compileSdkVersion 23
        buildToolsVersion "23.0.1"
        
        defaultConfig{
            applicationId "org.flysnow.app.example93"
            minSdkVersion 14
            targetSdkVersion 23
            versionCode appVersionCode
            versionName getAppVersionName()
        }
    }

    No8:

    以git tag的数量作为其版本号

    def getAppVersionCode(){
        def stdout = new ByteArrayOutputStream()
        exec{
            commandLine 'git','tag','--list'
            standardOutput = stdout
        }
        return stdout.toString().split("
    ").size()
    }

    调用

    android{
        compileSdkVersion 23
        buildToolsVersion "23.0.1"
        
        defaultConfig{
            applicationId "org.flysnow.app.example93"
            minSdkVersion 14
            targetSdkVersion 23
            versionCode getAppVersionCode()
            versionName getAppVersionName()
        }
    }

    No9:

    隐藏签名文件信息(签名文件放在服务器,兼容debug打包)

    android{
        compileSdkVersion 23
        buildToolsVersion "23.0.1"
        
        signingConfigs{
            def appStoreFile = System.getenv("STORE_FILE")
            def appStorePassword = System.getenv("STORE_PASSWORD")
            def appKeyAlias = System.getenv("KEY_ALIAS")
            def appKeyPassword = System.getenv("KEY_PASSWORD")
            
            //当不能从环境变量里获取到签名信息的时候,就使用项目中带的debug签名
            if(!appStoreFile||!appStorePassword||!appKeyAlias||!appKeyPassword){
                appStoreFile = "debug.keystore"
                appStorePassword = "android"
                appKeyAlias = "androiddebugkey"
                appKeyPassword = "android"
            }
            release{
                storeFile file(appStoreFile)
                storePassword appStorePassword
                keyAlias appKeyAlias
                keyPassword appKeyPassword
            }
        }
    }

    No10:

    动态配置AndroidManifest文件

    ManifestPlaceholders是ProductFlavor的一个属性,是一个Map类型,所以我们可以同时配置很多个占位符

    <meta-data android:value="${UMENG_CHANNEL}" android:name="UMENG_CHANNEL">
    
    android{
        compileSdkVersion 23
        buildToolsVersion "23.0.1"
        
        productFlavors{
            google{
                manifestPlaceholders.put("UMENG_CHANNEL","google")
            }
            baidu{
                manifestPlaceholders.put("UMENG_CHANNEL","baidu")
            }
        }
    }

    它会把AndroidManifest文件中所有占位符变量为UMENG_CHANNEL的内容替换为manifestPlaceholders中对应的value的值

    缩写

    android{
        compileSdkVersion 23
        buildToolsVersion "23.0.1"
        
        productFlavors{
            google{}
            baidu{}
        }
        
        productFlavors.all{
            flavor->manifestPlaceholders.put("UMENG_CHANNEL",name)
        }
    }

    No11:

    自定义你的BuildConfig

    public final class BuildConfig{
        public static final boolean DEBUG = Boolean.parseBoolean("true");
        public static final String APPLICATION_ID = "org.flysnow.app.example96";
        public static final String BUILD_TYPE = "debug";
        public static final String FLAVOR = "baidu";
        public static final int VERSION_CODE = 1;
        public static final String VERSION_NAME = "1.0.0";
    }

    获取当前包名

    context.getPackageName()
    //更方便,性能更快
    BuildConfig.APPLICATION_ID

    注:DEBUG常量在debug模式下的值是true,在release模式下自动变为false

    新增一些常量

    public void buildConfigField(@NonNull String type,@NonNull String name,@NonNull String value){}

    第一个参数type是要生成字段的类型,第二个参数name是要生成字段的常量名字,第三个参数value是要生成字段的常量值。最终生成字段格式:<type> <name> = <value>

    例:安装渠道包的时候打开相应的网页

    android{
        compileSdkVersion 23
        buildToolsVersion "23.0.1"
        
        defaultConfig{
            applicationId "org.flysnow.app.example96"
            minSdkVersion 14
            targetSdkVersion 23
            versionCode 1
            versionName '1.0.0'
        }
        
        productFlavors{
            google{
                buildConfigField 'String','WEB_URL','"http://www.google.com"'
            }
            baidu{
                buildConfigField 'String','WEB_URL','"http://www.baidu.com"'
            }
        }
    }

    BuildConfig类就会生成相应的常量

    public static final String WEB_URL = "http://www.baidu.com";

    我们通过BuildConfig.WEB_URL使用即可,在打包的时候,Android Gradle会帮我们自动生成不同的值

    No12:

    动态添加自定义的资源

    res/Values文件夹里可以使用xml方式定义,还可以在我们的Android Gradle中定义,实现这一功能的正是resValue方法

    public void resValue(@NonNull String type,@NonNull String name,@NonNull String name,@NonNull String value){
        ClassField alreadyPresent = getResValues().get(name);
        if(alreadyPresent != null){
            String flavorName = getName();
            if(BuilderConstants.MAIN.equals(flavorName)){
                logger.info("DefaultConfig:resValue '{}' value is being replaced: {} -> {}",name,alreadyPresent.getValue(),value);
            }else{
                logger.info("ProductFlavor({}):resValue'{}' value is being replaced:{} -> {}",flavorName,name,alreadyPresent.getValue(),value);
            }
        }
        addResValue(AndroidBuilder.createClassField(type,name,value));
    }

    例:

    android{
        compileSdkVersion 23
        buildToolsVersion "23.0.1"
        productFlavors{
            google{
                resValue 'string','channel_tips','google渠道欢迎你'
            }
            baidu{
                resValue 'string','channel_tips','baidu渠道欢迎你'
            }
        }
    }

    生成

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <string name="channel_tips" translatable="false">baidu渠道欢迎你</string>
    </resources>

    No13:

    Java编译选项

    compileOptions来对Java编译选项进行配置

    android{
        compileSdkVersion 23
        buildToolsVersion "23.0.1"
        
        compileOptions{
            encoding = 'utf-8'
            sourceCompatibility = JavaVersion.VERSION_1_6
            targetCompatibility = JavaVersion.VERSION_1_6
        }
    }

    注:scourceCompatibility是配置Java源代码的编译级别,比如1.5/1.6这样

    targetCompatibility是配置生成的Java字节码的版本

    No14:

    adb操作选项配置--adbOptions

    public class AdbOptions implements com.android.builder.model.AdbOptions{
        int timeOutInMs;
        List<String> installOptions;
        
        @Override
        public int getTimeOutInMs(){
            return timeOutInMs;
        }
        
        public void timeOutInMs(int timeOutInMs){
            this.timeOutInMs(timeOutInMs);
        }
        
        public void timeOutInMs(int timeOutInMs){
            setTimeOutInMs(timeOutInMs);
        }
        
        @Override
        public Collection<String> getInstallOptions(){
            return installOptions;
        }
        
        public void setInstallOptions(String option){
            installOptions = ImmutableList.of(option);
        }
        
        public void setInstallOptions(String... options){
            installOptions = ImmutableList.copyOf(options);
        }
        
        public void installOptions(String option){
            installOptions = ImmutableList.of(option);
        }
        
        public void installOptions(String... options){
            installOptions = ImmutableList.copyOf(options);
        }
    }

    使用

    android{
        compileSdkVersion 23
        buildToolsVersion "23.0.1"
        
        adbOptions{
            timeOutInMs = 5*1000//
            installOptions '-r','-s'
        }
    }

    adb install有六个选项:

    -l:锁定该应用程序

    -r:替换已存在的应用程序,就是强制安装

    -t:允许测试包

    -s:把应用程序安装到SD卡上

    -d:允许进行降级安装,就是安装的程序比手机上带的版本低

    -g:为该应用授予所有运行时的权限

    No15:

    Dex选项配置--dexOptions{}

    package com.android.builder.core;
    import com.android.annotation.Nullable;
    
    public interface DexOptions{
        boolean getIncremental();
        boolean getPreDexLibraries();
        boolean getJumboMode();
        @Nullable
        String getJavaMaxHeapSize();
        @Nullable
        Integer getThreadCount();
    }

    incremental用来配置是否启用dx的增量模式

    android{
        compileSdkVersion 23
        buildToolsVersion "23.0.1"
        
        dexOptions{
            incremental true
        }
    }

    javaMaxHeapSize配置执行dx命令时为其分配的最大堆内存,主要用来解决执行dx时内存不够用的情况

    android{
        compileSdkVersion 23
        buildToolsVersion "23.0.1"
        
        dexOptions{
            javaMaxHeapSize '4g'
        }
    }

    jumboMode用来配置是否开启jumbo模式,解决函数数量超过65535个的问题

    android{
        compileSdkVersion 23
        buildToolsVersion "23.0.1"
        
        dexOptions{
            jumboMode true
        }
    }

    preDexLibraries用来配置是否预执行dex Libraries库工程,开启后会大大提高增量构建的速度,不过可能会影响clean构建的速度

    threadCount用来配置Android Gradle运行dx命令时使用的线程数量,适当提高dx的效率

    android{
        compileSdkVersion 23
        buildToolsVersion "23.0.1"
        
        dexOptions{
            threadCount 2
        }
    }

    No16:

    app方法数为什么有65535这个限制?

    Dalvik虚拟机在执行DEX文件的时候,它使用了short这个类型来索引DEX文件中的方法,所以单个DEX文件可以被定义的方法最多只能是65535个。

    No17:

    Android 5.0之后,使用了ART的运行时方式,可以天然支持app有多个DEX文件。ART在安装app的时候执行预编译,把多个DEX文件合并成一个oat文件执行。

    No18:

    突破65535方法限制

    android{
        compileSdkVersion 23
        buildToolsVersion "23.0.1"
        
        defaultConfig{
            applicationId "org.flysnow.app.example911"
            minSdkVersion 14
            targetSdkVersion 23
            versionCode 1
            versionName '1.0.0'
            //启用multidex
            multiDexEnabled true
        }
    }
    dependencies{
        compile fileTree(dir: 'libs',include:['*.jar'])
        compile 'com.android.support:multidex:1.0.1'
    }

    1)如果没有自定义Application,直接使用MultiDexApplication

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="org.flysnow.app.example911">
        <application
            ...
            android:name="android.support.multidex.MultiDexApplication">
            ...
        </application>
    </manifest>

    2)如果有自定义Application,直接继承MultiDexApplication即可

    3)如果自定义Application继承了其他第三方提供的Application,就需要重写attachBaseContext方法

    public class Example911Application extends Application{
        @Override
        protected void attachBaseContext(Context base){
            super.attachBaseContext(base);
            MultiDex.install(this);
        }
    }

    因为继承MultiDexApplication也是通过重写attachBaseContext方法然后MultiDex.install(this)方法实现的

    No19:

    自动清理未使用的资源--Resource Shrinking

    android{
        compileSdkVersion 23
        buildToolsVersion "23.0.1"
        
        buildTypes{
            release{
                minifyEnabled true
                shrinkResources true
                proguardFiles getDefaultProguardFile('proguard-android.txt'),'proguard-rules.pro'
            }
        }
    }

    避免误删--keep(文件位置:res/raw/keep.xml)

    <?xml version="1.0" encoding="utf-8"?>
    <resources xmlns:tools="http://schemas.android.com/tools"
        tools:keep="@layout/l_used*_c,@layout/l_used_a,@layout/l_used_b*"/>

    只用中文的语言资源

    android{
        compileSdkVersion 23
        buildToolsRevision "23.0.1"
        
        defaultConfig{
            applicationId "org.flysnow.app.example912"
            minSdkVersion 14
            targetSdkVersion 23
            versionCode 1
            versionName '1.0.0'
            resConfigs 'zh'
        }
    }

    动清理资源只是在打包的时候,不打包到apk中,并没有删除工程中的资源

  • 相关阅读:
    关于运行和调试的困惑
    初识函数
    Php的基本语法
    Apache的安装
    php的初步了解
    线程笔记
    Matlab笔记
    matlab取模与取余
    DialogFragment学习笔记
    MVP学习笔记——参考Google官方demo
  • 原文地址:https://www.cnblogs.com/anni-qianqian/p/8619175.html
Copyright © 2011-2022 走看看