欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

關于gradle你應該知道的一些小事

 更新時間:2018年10月13日 09:53:14   作者:iceanson  
這篇文章主要給大家介紹了關于gradle你應該知道的一些小事,文中通過示例代碼介紹的非常詳細,對大家學習或者使用gradle具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

前言

gradle的定義(來自維基百科)

Gradle是一個基于Apache Ant和Apache Maven概念的項目自動化建構工具。它使用一種基于Groovy的特定領域語言來聲明項目設置,而不是傳統(tǒng)的XML。當前其支持的語言限于Java、Groovy和Scala,計劃未來將支持更多的語言。

通俗的理解:gradle是一種構建工具,我們可以用他來對多工程進行各種管理(依賴,打包,部署,發(fā)布,各種渠道的差異管理);

有些時候,我們會有一些個性化的構建需求,比如我們引入了第三方庫,或者我們想要在通用構建過程中做一些其他的事情,這時我們就要自己在系統(tǒng)默認構建規(guī)則上做一些修改。這時候我們就要自己向Gradle”下命令“了,這時候我們就需要用Gradle能聽懂的話了,也就是Groovy。

我們在開頭處提到“Gradle是一種構建工具”。實際上,當我們想要更靈活的構建過程時,Gradle就成為了一個編程框架——我們可以通過編程讓構建過程按我們的意愿進行。也就是說,當我們把Gradle作為構建工具使用時,我們只需要掌握它的配置腳本的基本寫法就OK了;而當我們需要對構建流程進行高度定制時,就務必要掌握Groovy等相關知識了。

遭遇的問題

我們在實時多項目構建的時候經常遇到以下這些問題:

1、同時依賴了不同版本的某個庫,編譯時出現duplicate class錯誤;

2、gradle 不同版本api報錯;

3、不會寫gradle配置,看不懂gradle語法,不知道從何學起;

4、對編譯過程中gradle的報錯無從下手;

等等…

我們接下來將從實際項目出發(fā)一步一步來學習gradle的這些事,本文主旨在于學習gradle的思路,深度細節(jié)將會忽略;

揭開Gradle的面紗

一、理解打包命令 gradle clean assembleDebug/assembleRelease

以上這條命令可以分解為三個部分,gradle,clean, assembleDebug;實際上就和我們執(zhí)行腳本一樣,gradle是執(zhí)行器,而clean 和 assembleDebug是入參, 在這里它們兩個代表不同的task,就類似gradle task1 task2 這樣。

二、什么是task?

在build.gradle寫上

task task1 {
 println "===>task 1"
}
task task2 {
 println "===>task 2"
}

這樣就定義了兩個task;當我們執(zhí)行gradle task1 task2 -q的時候(-q是設置日志級別),理論上會看到日志輸出:

===>task 1
===>task 2

task的關系有dependsOn,mustRunAfter等等,由于項目中用的比較少這里先跳過這部分;

這里我們簡單講一下閉包的概念:

閉包在groovy中是一個處于代碼上下文中的開放的,匿名代碼塊。它可以訪問到其外部的變量或方法,
更詳細的請自行google

然而,當我們在項目里執(zhí)行gradle task1 task2 -q的時候,我們發(fā)現輸出是這樣的:

 SeeyouClient git:(SeeyouClient-dev) ✗ gradle task1 task2 -q
doPackage value:False
Configuration 'compile' in project ':app' is deprecated. Use 'implementation' instead.
==============anna apply start==================
configuration do:
include
**  onClick 
**  onItemClick 
**  onCheckedChanged 
**  onItemSelected 
**  onSwitchButtonCheck 
**  onItemLongClick 
**  onLongClick 
**  onPullRefresh 
**  OnRefresh 
configuration do:
exclude
org/conscrypt/ 
configuration do:
exceptions
java/lang/Exception 
java/lang/NullPointerException 
configuration do:
switch
custom 
need inject=false
==============anna apply end==================
Configuration 'provided' in project ':app' is deprecated. Use 'compileOnly' instead.
Configuration 'debugCompile' in project ':app' is deprecated. Use 'debugImplementation' instead.
===>task 1
===>task 2
DexKnife: Processing Variant
DexKnife: processSplitDex true
DexKnife: processing Task
----------------------tinker build warning ------------------------------------
tinker auto operation:
excluding annotation processor and source template from app packaging. Enable dx jumboMode to reduce package size.
enable dx jumboMode to reduce package size.
disable preDexLibraries to prevent ClassDefNotFoundException when your app is booting.
disable archive dex mode so far for keeping dex apply.
tinker will change your build configs:
we will add TINKER_ID=117 in your build output manifest file build/intermediates/manifests/full/*
if minifyEnabled is true
you will find the gen proguard rule file at build/intermediates/tinker_intermediates/tinker_proguard.pro
and we will help you to put it in the proguardFiles.
if multiDexEnabled is true
you will find the gen multiDexKeepProguard file at build/intermediates/tinker_intermediates/tinker_multidexkeep.pro
and we will help you to put it in the MultiDexKeepProguardFile.
if applyResourceMapping file is exist
we will build app apk with resource R.txt file
if resources.arsc has changed, you should use applyResource mode to build the new apk!
-----------------------------------------------------------------
Task spend time:

這是為什么呢?原因是gradle具有自己的生命周期:

初始化階段:負責判斷有多少個Projects參與構建:
 先執(zhí)行settings.gradle
配置階段:負責對初始化階段創(chuàng)建的Projects完成配置:
 比如添加Task,修改Task的行為,閉包的內容會被執(zhí)行,執(zhí)行build.gradle的內容;
執(zhí)行階段:根據配置階段的配置執(zhí)行任務:
 執(zhí)行task對應的內容,如doLast,doFirst之類的

因此gradle task1 task2 -q的輸出日志就可以理解了,其實按照task1和task2的寫法,執(zhí)行gradle task1 task2 -q和gradle -q實際上效果是一樣的。

三、gradle clean assmebleDebug到底做了什么?(源碼追蹤和依賴分析出編譯流程)

1、打開gradle-4.5.1/bin/gradle文件可以看到執(zhí)行了代碼:

 eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.launcher.GradleMain "$APP_ARGS"

 最終調用exec "$JAVACMD" "$@"來執(zhí)行;所以入口就是:org.gradle.launcher.GradleMain

 具體細節(jié)可以參照:https://blog.csdn.net/yanbober/article/details/60584621

2,最終會調用DefaultGradleLauncher里,我們可以很明確的看到它的生命周期:

這邊最需要注意的時候,當我們只執(zhí)行gradle -q這樣的時候,實際上每一次都會執(zhí)行到TaskGraph的階段;也就是所有的tasks都已經梳理完成;

public class DefaultGradleLauncher implements GradleLauncher {
 //(這里是4.5.1的版本,生命周期更細致化)
 private enum Stage {
  Load, LoadBuild, Configure, TaskGraph, Build, Finished
 }
 //2.14.1的版本則是: 
 private enum Stage {
  Load, Configure, Build
 }
//核心方法
private void doBuildStages(Stage upTo) {
  try {
   loadSettings();
   if (upTo == Stage.Load) {
    return;
   }
   configureBuild();
   if (upTo == Stage.Configure) {
    return;
   }
   constructTaskGraph();
   if (upTo == Stage.TaskGraph) {
    return;
   }
   runTasks();
   finishBuild();
  } catch (Throwable t) {
   Throwable failure = exceptionAnalyser.transform(t);
   finishBuild(new BuildResult(upTo.name(), gradle, failure));
   throw new ReportedException(failure);
  }
 }
 
 //調用時機
  @Override
 public SettingsInternal getLoadedSettings() {
  doBuildStages(Stage.Load);
  return settings;
 }
 @Override
 public GradleInternal getConfiguredBuild() {
  doBuildStages(Stage.Configure);
  return gradle;
 }
 public GradleInternal executeTasks() {
  doBuildStages(Stage.Build);
  return gradle;
 }

四、知道編譯流程后有什么用呢?

1、我們經常在app/build.gradle看到這樣的代碼:

project.afterEvaluate {...}
android.applicationVariants.all {...}
gradle.addListener(new TaskListener())
apply from '../mvn.gradle'
...

這里我們介紹幾個概念:

project

對應gradle源碼的Project.java(按住control點擊project會自動跳轉),里邊提供一些對外的方法,如afterEvalute,beforeEvalue; 在理解編譯流程后,才能靈活的使用這些api;

android

對應gradle插件的AppExtension.java文件,提供了一些對外的參數和方法,我們可以使用android.xxx來訪問app/build.gradle里的任意參數和方法;

gradle

對應的gradle源碼里的Gradle.java對象,也是提供了一系列的方法給外部使用;

那么接下來假設我們有這樣一個需求:找到一個叫cleanBuildCache的task,找到之后添加一個action,打印一行字; 要實現這個需求,首先我們如何遍歷這個app的所有task:

有很多種寫法:

gradle.getTaskGraph().whenReady {
 project.tasks.each {
  task->
   println "taskName:"+task.getName()
 }
}
project.afterEvaluate {
 project.tasks.each {
  task->
   println "taskName:"+task.getName()
 }
}

執(zhí)行gradle -q 感受一下。

接下看看如何添加action

project.afterEvaluate {
 project.tasks.each {
  task->
   // println "taskName:"+task.getName()
   if(task.getName().equals("cleanBuildCache")){
    println "find cleanBuildCache!!!!!!"
    List<Action<? super Task>> list = new ArrayList<>()
    list.add(new Action<Task>() {
     @Override
     void execute(Task task1) {
      println 'excute cleanBuildCache action !!!!!!'
     }
    })
    task.setActions(list)
   }
 }
}

執(zhí)行gradle cleanBuildCache感受一下,

你會看到‘excute cleanBuildCache action !!!!!!'的打印字樣;

那為什么一定要放在afterEvaluate之后呢,因為這樣tasksGrap完成才有那么多task讓你遍歷,這就是理解生命周期所帶來的好處。

2、現在回顧我們之前主app寫的代碼:

processProductDebugManifest;

project.tasks.each {
  task->
   if(task.getName().equals("processZroTestDebugManifest")){
    println '!!!!!find processZroTestDebugManifest task:'
    task.outputs.files.each {
     file ->
      println 'file.getAbsolutePath():'+ file.getAbsolutePath()
      //file.getAbsolutePath():/Users/mu/MeiyouCode/PeriodProject/SeeyouClient/app/build/intermediates/manifests/instant-run/zroTest/debug
      //file.getAbsolutePath():/Users/mu/MeiyouCode/PeriodProject/SeeyouClient/app/build/intermediates/manifests/full/zroTest/debug
      //file.getAbsolutePath():/Users/mu/MeiyouCode/PeriodProject/SeeyouClient/app/build/outputs/logs/manifest-merger-zroTest-debug-report.txt
    }
    task.doLast {
     println '!!!!!excute processZroTestDebugManifest task'
     def dated = new Date().format("MMdd HH:mm")
     def manifestFile = "${buildDir}/intermediates/manifests/full/zroTest/debug/AndroidManifest.xml"
     def updatedContent = new File(manifestFile).getText('UTF-8')
       .replaceAll("MY_APP_PKGNAME", "${MY_APP_PKGNAME}")
       .replaceAll("MY_JPUSH_APPKEY", "${JPUSH_APPKEY}")
       .replaceAll("MY_HUAWEI_APPKEY", "${HUAWEI_APPKEY}")
       .replaceAll("MY_MEIZU_APPKEY", "${MEIZU_APPKEY}")
       .replaceAll("MY_MEIZU_APPID", "${MEIZU_APPID}")
     // .replaceAll("MY_XIAOMI_APPKEY", "${XIAOMI_APPKEY}")
     // .replaceAll("MY_XIAOMI_APPID", "${XIAOMI_APPID}")
     //.replaceAll("cn.jpush.android.service.PluginXiaomiPlatformsReceiver","com.meiyou.message.mipush.XiaomiReceiver")
       .replaceAll("MY_APK_VERSION", "${archivesBaseName}-${dated}")
     new File(manifestFile).write(updatedContent, 'UTF-8')
    }
   }
 }

實際上也可以寫成這樣(但是這樣因為變種不確定,寫死成zroTest/debug,所以還是用上面的方法比較好,直接替換所有的變種):

project.tasks.each {
  task->
   if(task.getName().equals("processZroTestDebugManifest")){
    println '!!!!!find processZroTestDebugManifest task:'+task.outputs.files.each {
     file ->
      file.getAbsolutePath();
    }
    task.doLast {
     println '!!!!!excute processZroTestDebugManifest task'
     def dated = new Date().format("MMdd HH:mm")
     def manifestFile = "${buildDir}/intermediates/manifests/full/zroTest/debug/AndroidManifest.xml"
     def updatedContent = new File(manifestFile).getText('UTF-8')
       .replaceAll("MY_APP_PKGNAME", "${MY_APP_PKGNAME}")
       .replaceAll("MY_JPUSH_APPKEY", "${JPUSH_APPKEY}")
       .replaceAll("MY_HUAWEI_APPKEY", "${HUAWEI_APPKEY}")
       .replaceAll("MY_MEIZU_APPKEY", "${MEIZU_APPKEY}")
       .replaceAll("MY_MEIZU_APPID", "${MEIZU_APPID}")
     // .replaceAll("MY_XIAOMI_APPKEY", "${XIAOMI_APPKEY}")
     // .replaceAll("MY_XIAOMI_APPID", "${XIAOMI_APPID}")
     //.replaceAll("cn.jpush.android.service.PluginXiaomiPlatformsReceiver","com.meiyou.message.mipush.XiaomiReceiver")
       .replaceAll("MY_APK_VERSION", "${archivesBaseName}-${dated}")
     new File(manifestFile).write(updatedContent, 'UTF-8')
    }
   }
 }

3、如何知道某個task干了什么呢,比如processZroTestDebugManifest或者Clean:

這些是com.android.tools.build到源碼里尋找或者直接compile ‘com.android.tools.build:gradle:3.0.1'直接從依賴庫里看源碼; 或者直接下載源碼(大概30G左右):

$ mkdir gradle_2.3.0
$ cd gradle_2.3.0
$ repo init -u https://android.googlesource.com/platform/manifest -b gradle_2.3.0
$ repo sync

大部分tasks都在com.android.build.gradle.tasks文件夾下,比如:ManifestProcessorTask和CleanBuildCache

具體可以:https://fucknmb.com/2017/06/01/Android-Gradle-Plugin源碼閱讀與編譯/

4、如何查找某個task的依賴呢,比如我想知道assmebleZroTestDebug執(zhí)行后最終執(zhí)行了哪些task;

1、編譯后打印;

gradle.addListener(new TaskListener())
class TaskListener implements BuildListener,TaskExecutionListener {
 private List<String> tasks = new ArrayList<>();
 @Override
 void buildStarted(Gradle gradle) {
 }
 @Override
 void settingsEvaluated(Settings settings) {
 }
 @Override
 void projectsLoaded(Gradle gradle) {
 }
 @Override
 void projectsEvaluated(Gradle gradle) {
 }
 @Override
 void buildFinished(BuildResult result) {
  StringBuilder stringBuilder = new StringBuilder();
  for(String taskName:tasks){
   stringBuilder.append(taskName).append("\n")
  }
  println("任務列表:\n"+stringBuilder.toString())
 }
 @Override
 void beforeExecute(Task task) {
 }
 @Override
 void afterExecute(Task task, TaskState state) {
  //println("===>Task:"+task.getName())
  tasks.add(task.getName())
 }
}

2、不用編譯直接打?。?/p>

void printTaskDependency(Task task, String divider) {
 divider += "-------"
 task.getTaskDependencies().getDependencies(task).any() {
  println(divider+ it.getPath())
  if (it.getPath().contains(":app")) {
   printTaskDependency(it,divider)
  }
 }
}
gradle.getTaskGraph().whenReady {
 project.tasks.all {
  //println("!!!!!!!!!! it:"+it.getName()+"==>it.getPath:"+it.getPath())
  if (it.getPath().equals(":app:assembleZroTestDebug")) {
   //println(it.getPath())
   printTaskDependency(it,"")
  }
 }
}

5、常用技能

1、gradle :app:dependencies > 1.txt 分析整個app的aar依賴

可以用于排查依賴庫異常的問題;

請注意!:對工程依賴無效;

2、productFlavors和buildType概念,組合成變種 如:

productFlavors {
 branchOne {
  applicationId "com.example.branchOne"
  buildConfigField "String", "CONFIG_ENDPOINT", "http://branchOne.com/android"
 }
 branchTwo {
  applicationId "com.example.branchTwo"
  buildConfigField "String", "CONFIG_ENDPOINT", "http://branchTwo.org"
 }
}
dependencies {
 compile 'com.android.support:support-v4:22.2.0'
 branchOneCompile 'com.android.support:appcompat-v7:22.2.0'//只為branchOne添加這個依賴
}

3、排除依賴和強制使用某個版本和強制排除某個庫:

configurations.all {
  resolutionStrategy {
//   force 'org.javassist:javassist:3.18.2-GA'
   // don't cache changing modules at all
   cacheChangingModulesFor 0, 'seconds'
//   //強制模塊使用指定版本號(防止其他模塊使用、跟主工程不匹配的版本:
   forcedModules = [
     "com.meiyou:peroid.base:${PERIOD_BASE_VERSION}",
     'org.javassist:javassist:3.18.2-GA'//"org.javassist:javassist:3.20.0-GA"http://
     , 'com.google.guava:guava:18.0'//'com.google.guava:guava:19.0-rc2'//
   ]
   exclude group: 'com.squareup.okhttp3'
   exclude group: 'com.google.code.findbugs', module: 'annotations'
  }
 }

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。

相關文章

  • Flutter Dio二次封裝的實現

    Flutter Dio二次封裝的實現

    這篇文章主要介紹了Flutter Dio二次封裝的實現,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-01-01
  • Android中復制圖片的實例代碼

    Android中復制圖片的實例代碼

    本文通過實例代碼給大家介紹了android 復制圖片的實現方法,非常不錯,具有參考借鑒價值,需要的朋友參考下吧
    2017-08-08
  • 詳解Android使用Socket對大文件進行加密傳輸

    詳解Android使用Socket對大文件進行加密傳輸

    這篇文章主要介紹了詳解Android使用Socket對大文件進行加密傳輸,使用Socket進行文件傳輸過程時,需要先進行加密,有興趣的可以了解一下。
    2017-01-01
  • android真機調試時無法顯示logcat信息的解決方法介紹

    android真機調試時無法顯示logcat信息的解決方法介紹

    以下是對android真機調試時無法顯示logcat信息的解決方法進行了詳細的分析介紹,需要的朋友可以過來參考下
    2013-07-07
  • flutter實現磨砂玻璃效果實例詳解

    flutter實現磨砂玻璃效果實例詳解

    這篇文章主要為大家介紹了flutter實現磨砂玻璃效果實例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-11-11
  • Android 如何采用Lame編碼器編碼mp3文件

    Android 如何采用Lame編碼器編碼mp3文件

    這篇文章主要介紹了Android 如何采用Lame編碼器編碼mp3文件,幫助大家更好的理解和學習使用Android,感興趣的朋友可以了解下
    2021-03-03
  • Android 圖片Bitmap的剪切的示例代碼

    Android 圖片Bitmap的剪切的示例代碼

    本篇文章主要介紹了Android 圖片Bitmap的剪切的示例代碼,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-01-01
  • Android 消息機制問題總結

    Android 消息機制問題總結

    本文主要介紹Android 消息機制,這里整理了消息機制的詳細資料,和經常出現的問題,希望能幫助大家對消息機制的理解
    2016-08-08
  • Android中如何取消listview的點擊效果

    Android中如何取消listview的點擊效果

    這篇文章主要介紹了 Android中取消listview的點擊效果的實現方法,通過引用transparent之后會讓點擊效果透明化,一起通過本文學習吧
    2017-01-01
  • android實現歌詞自動滾動效果

    android實現歌詞自動滾動效果

    這篇文章主要為大家詳細介紹了android實現歌詞自動滾動效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-11-11

最新評論