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'  //編譯第三方開源庫
 }
發佈了48 篇原創文章 · 獲贊 8 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章