Android项目构建--gradle常用知识小结与多渠道多Apk打包

gradle概览

Project build.gradle

//配置构建过程
buildscript {
//配置依赖仓库 maven
    repositories {
        mavenCentral()
    }
//配置依赖插件 gradle
    dependencies {
        classpath 'com.android.tools.build:gradle:0.11.1'
    }
}
//应用android插件
apply plugin: 'android'
//配置android构建所需所有参数
android {
    compileSdkVersion 19
    buildToolsVersion "19.0.0"
}

Module build.gradle

下面是实际项目的一个截图,我们常用的几个顶层配置都在这了,我们重点关注android这个配置项,其他几项不太需要修改
这里写图片描述
接下来看下android配置项下面的子集

defaultConfig{} 默认配置,是ProductFlavor类型。它共享给其他ProductFlavor使用
sourceSets{ } 源文件目录设置,是AndroidSourceSet类型。
buildTypes{ } BuildType类型
signingConfigs{ } 签名配置,SigningConfig类型
productFlavors{ } 产品风格配置,ProductFlavor类型
testOptions{ } 测试配置,TestOptions类型
aaptOptions{ } aapt配置,AaptOptions类型
lintOptions{ } lint配置,LintOptions类型
dexOptions{ } dex配置,DexOptions类型
compileOptions{ } 编译配置,CompileOptions类型
packagingOptions{ } PackagingOptions类型
jacoco{ } JacocoExtension类型。 用于设定 jacoco版本
splits{ } Splits类型

下面列几个常用的配置项,

lintOptions {
  lintConfig file("lint.xml")
  abortOnError false
}

sourceSets {  //目录指向配置
   main {
      manifest.srcFile  'AndroidManifest.xml'  //指定 AndroidManifest 文件
      java.srcDirs = ['src']  //指定 source 目录
      resources.srcDirs = ['src']  //指定 source 目录
      aidl.srcDirs = ['src']  //指定 source 目录
      renderscript.srcDirs = ['src']  //指定 source 目录
      res.srcDirs = ['res']  //指定资源目录
      assets.srcDirs = ['assets']  //指定 assets 目录
      jniLibs.srcDirs = ['libs']  //指定 lib 库目录
   }
    debug.setRoot('build-types/debug')  //指定 debug 模式的路径
    release.setRoot('build-types/release')  //指定 release 模式的路径
}

signingConfigs {  //签名配置
    release {  //发布版本签名配置
       storeFile file("fk.keystore")  //密钥文件路径
       storePassword  "123"  //密钥文件密码
       keyAlias  "fk"  //key 别名
       keyPassword  "123"  //key 密码
    }
    debug {  //debug版本签名配置
       storeFile file("fk.keystore")  
       storePassword  "123"
       keyAlias  "fk"
       keyPassword  "123"
    }
}

 buildType {  // build 类型
    release {  //发布
        minifyEnabled  true  //混淆开启
        proguardFiles  getDefaultProguardFile('proguard-android.txt'),'proguard-android.txt'  //指定混淆规则文件
        signingConfig   signingConfigs.release  //设置签名信息
    }
    debug {  //调试
        signingConfig signingConfigs.release
    }
    custom {//自定义类型
       minifyEnabled false
       renderscriptDebuggable true
   }
}

local.properties

配置sdk.dir属性,配置这个跟配置ANDROID_HOME环境变量差不多

任务

这里写图片描述
● assemble 这个任务会汇集工程的所有输出。
● check 这个任务会执行所有校验检查
● connectedCheck 运行checks需要一个连接的设备或者模拟器,这些checks将会同时运行在所有连接的设备上。
● deviceCheck 通过API连接远程设备运行checks。它被用于CI(译者注:持续集成)服务器上。
● build 这个任务会同时执行 assemble 和 check 任务
● clean 这个任务会清理工程的所有输出

共享变量

定义整个项目的公共变量,如sdk版本等,让所有子module都使用同样的配置
新建common_config.gradle文件

project.ext{
//java语言相关
javaVersion = 8
javaMaxHeapSize = '4G'
//Android编译相关
compileSdkVersion = 23
buildToolsVersion = '23.1.1'
minSdkVersion = 16
targetSdkVersion = 23
//混淆相关
minifyEnbale = true
shrinkResEnable = minifyEnable
//JDK版本兼容
sourceCompatibility = this.&getJavaVersion()
targetCompatibility = this.&getJavaVersion()
}

def getJavaVersion(){
    switch(project.ext.javaVersion){
        case "6":
            return JavaVersion.VERSION_1_6
        case "7":
            return JavaVersion.VERSION_1_7
        case "8":
            return JavaVersion.VERSION_1_8
        default:
            return JavaVersion.VERSION_1_6
    }
}

module中使用

apply from: "${project.rootDir}/common_config.gradle"
minSDKVersion project.ext.minSdkVersion

除了在每个module中进行如上配置导入common_config.gradle之外还可以使用下面方式
只需在Project的build.gradle做如下一次性配置

subprojects{
    apply from: "${project.rootDir}/common_config.gradle"
    dependencies{
        testCompile 'junit:junit:4.12'
    }
}

多渠道打包

上面的常用内容配置一个apk的打包足够了,但很多时候我们应用上架需要配置多个应用商店每个apk包都有一些不同的信息,下面看看这种情况如何处理。
多渠道需要处理的主要就是每个渠道都有一些各自的参数,下面看看这方面怎么处理。这里假设每个渠道的application label都不一样。
这里写图片描述
这里引用一个变量${APP_NAME},我们需要在build.gradle中根据不同的渠道进行配置
这里主要是两个配置项,都在android配置项里

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

上面配置了release和debug两个版本

productFlavors{
        //百度推广渠道
        baidu {
            applicationId "com.android.baidu"
            versionCode 1
            versionName "1.0"
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "baidu"]
            manifestPlaceholders = [  APP_NAME  : "app-百度"] 
        }
        //360推广渠道
        qh360 {
            applicationId "ccom.android.three"
            versionCode 1
            versionName "1.0"
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "qh360"]
            manifestPlaceholders = [  APP_NAME  : "app-360"] 
        }
        //豌豆荚推广渠道
        wandoujia {
            applicationId "com.android.douban"
            versionCode 1
            versionName "1.0"
            manifestPlaceholders = [  APP_NAME  : "app-豌豆荚"] 
        }
    }

上面配置了三个渠道,三个渠道主要修改了包名跟配置了APP_NAME.这样配置渠道包的工作就差不多好了,这里会生成(release+debug) * (baidu + 360 + wandoujia) = 6个Apk包。
此外还要做一个额外的工作,就是输出的时候 修改apk文件名,否则你只能看到一个Apk包了
这个工作只需要配置andorid下的一个配置项即可

applicationVariants.all{variant ->
        variant.outputs.each { output ->
            def outputFile = output.outputFile
            if (outputFile != null && outputFile.name.endsWith('.apk')) {
                def buildType = variant.buildType.name
                //这里修改apk文件名,格式为 app_渠道名-版本名-当前时间-编译版本.apk
                def fileName = "app_${variant.productFlavors[0].name}-V${defaultConfig.versionName}-${getCurrentTime()}-${buildType}.apk"
                output.outputFile = new File(outputFile.parent, fileName)
            }
        }

    }

我们注意到这边还需要一个getCurrentTime()的函数,在与android同级的目录下定义一个好了

//获取当前时间
def getCurrentTime() {
    return new Date().format("yyyy-MM-dd", TimeZone.getTimeZone("UTC"))
}

最后在项目的根目录下运行gradle build,注意输出目录
这里写图片描述

这里写图片描述

签名

签名这块也很简单,Build -> Generate Signed APK 里可以创建一个key
这里写图片描述
创建后,我们在build.gradle的android配置项里做如下配置

    signingConfigs{
        myconfig {
            keyAlias 'huang'
            keyPassword '123456'
            storeFile file('/home/huangshunbo/demo.jks')
            storePassword 'huangshunbo'
        }
    }

最后在想要使用该签名的buildTypes里做下引用即可

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

就这样,签名搞定。下面备注点小知识

查看三方应用或是系统应用签名:解压apk -> 进入META-INF得到CERT.RSA文件,通过
keytool -printcert -file META-INF/CERT.RSA
查看签名信息

查看签名文件demo.jks信息
keytool -v -list -keystore demo.jks

混淆

首先在buildTypes配置需要混淆并指定混淆规则文件

buildTypes {
        debug {
            minifyEnabled true //是否要混淆
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'//混淆的规则
        }
    }

Proguard的4个特性:压缩、优化、混淆、预检测
proguard-android.txt是Proguard默认的混淆配置文件
proguard-rules.pro在module根目录下,可替代proguard-android.txt作为补充。
一般的,我们在proguard-rules.pro文件里做相关的混淆配置
常用的一些配置:

-keep开头的表示保持不变,不去混淆

-keep {Modifier} {class_specification}    #保护指定的类文件和类的成员   
-keepclassmembers {modifier} {class_specification}    #保护指定类的成员,如果此类受到保护他们会保护的更好  
-keepclasseswithmembers {class_specification}    #保护指定的类和类的成员,但条件是所有指定的类和类成员是要存在。   
-keepnames {class_specification}    #保护指定的类和类的成员的名称(如果他们不会压缩步骤中删除)   
-keepclassmembernames {class_specification}    #保护指定的类的成员的名称(如果他们不会压缩步骤中删除)   
-keepclasseswithmembernames {class_specification}    #保护指定的类和类的成员的名称,如果所有指定的类成员出席(在压缩步骤之后) 

 eg:
-keep public class * extends android.app.Activity       #保持Activity的子类不被混淆
-keep public class * extends android.support.v4.**
-keep public class * extends android.support.v7.**
-keep public class * extends android.support.annotation.**
-keep class **.R$* {*;}            # 保留R下面的资源

# 代码混淆压缩比,在0~7之间,默认为5,一般不做修改
-optimizationpasses 5

# 混合时不使用大小写混合,混合后的类名为小写
-dontusemixedcaseclassnames

# 指定不去忽略非公共库的类
-dontskipnonpubliclibraryclasses

#不做预校验  
-dontpreverify  

# 混淆时所采用的算法  
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*  

#忽略警告  
-ignorewarning 
#混淆过程打印日志的级别
-verbose
#不使用优化方案
-dontoptimize
#混淆时不做预校验
-dontpreverify
#如果项目中使用到注解,需要保留注解属性
-keepattributes *Annotation*
#保持native方法不作混淆
-keepclasseswithmembernames class * {
    native <methods>;
}
#保持Views中的setter和getter方法不混淆,保证属性动画能够正常执行
-keepclassmembers public class * extends android.view.View{
    void set*(***);
    *** get*();
}
#保持Activity中参数是View类型的函数,保证在XML文件中配置的onClick属性的值能够正常调用到
-keepclassmembers class * extends android.app.Activity{
    public void *(android.view.View);
}
#保持枚举类型中的函数
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}
#不混淆泛型
-keepattributs Signature
#保留代码行号,这在混淆后代码运行中抛出异常信息时,有利于定位出问题的代码
-keepattributes SourceFile,LineNumberTable
#保留R类
-keep class **.R$*{
    *;
}

Proguard运行后生成的四个文件(build/outputs/mapping/release目录下)

  • dump.txt:列出生成的APK文件中所有class文件的内部结构
  • mapping.txt:列出混淆钱的Java源码和混淆后的类、方法、属性名之间的映射关系
  • seeds.txt:列出未混淆的类和成员
  • usage.txt:列出从APK文件中剥离的代码

Maven Central 和 JCenter

目前存在两个标准的Java & Android Maven仓库:Maven Central 和 JCenter。目前JCenter相对有优势而且Maven Central可以说是JCenter的一个子集。上传函数库到JCenter只需要到Bintray网站上进行操作即可
仓库的匹配模式

compile 'de.greenrobot:eventbus:2.4.0'
GROUP_ID组织/公司/个人名:ARTIFACT_ID函数库名:VERSION版本号

.arr 的导入

# 生成arr
android{
    repositories {
      flatDir {
          dirs 'aars' 
      }
    }
}

# 使用aar
dependencies {
  compile(name:'libraryname', ext:'aar')
}

dependencies

dependencies  {
    compile  fileTree(include: ['*.jar'], dir: 'libs')  //编译lib 目录下的 jar 文件
    compile  project(':Easylink')  //编译附加的项目
    compile 'com.android.support:appcompat-v7:25.0.1'
    compile 'com.jakewharton:butterknife:8.4.0'  //编译第三方开源库
 }

猜你喜欢

转载自blog.csdn.net/xiaoru5127/article/details/76503547