日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android gradle dependency tree change(依赖树变化)监控实现,sdk version 变化一目了然

發布時間:2024/1/18 Android 31 coder
生活随笔 收集整理的這篇文章主要介紹了 Android gradle dependency tree change(依赖树变化)监控实现,sdk version 变化一目了然 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

@

目錄
  • 前言
  • 基本原理
  • 執行流程
  • diff 報告
    • 不同分支 merge 過來的 diff 報告
    • 同個分支產生的 merge 報告
    • 同個分支提交的 diff 報告
  • 具體實現原理
    • 我們需要監控怎樣的 Dendenpency 變化
    • 怎樣獲取 dependency Tree
      • project.configurations 方式
      • ./gradlew dependencies
      • AsciiDependencyReportRenderer
      • 方案選擇
    • 怎樣對 dependency Tree 進行 diff 計算
      • 傳統 diff 方案
      • 自定義的 diff 方案
    • 如何找到一個基準點,進行 diff 計算
    • 怎樣集合 Gialab CI 進行計算
  • 總結
  • 參考文章

前言

這篇文章,其實在一年之前的時候就已經寫好了。當時是在公司內部分享的,作為一個監控框架。當時是想著過一段時間之后,分享到技術論壇上面的,沒想到計劃趕不上變化,過完國慶被裁了

當時忙著找工作,就一直沒有更新了,放在筆記里面吃灰

最近,發現好久沒有分享技術文章了,從筆記里面找了一下,就拿來分享了

在項目開發中,會有很多第三方依賴,通過 gradle 引入進來的。比如 androidxDesignVersion、androidxSupportVersion、 rxjava2Version、 okhttpVersion 等第三方庫。有時候第三方庫改到了或者升級了,我們并不能及時發現,往往需要等到出問題的時候,去排查的時候,才發現是某個依賴版本改動導致的。

這時候其實是有點晚了,如果能夠提前暴露,那么我們能夠大大地減少風險,因此我們希望能夠監控起來。

基本原理

  1. 代碼 merge 到 dev 分支的時候,借助 gitlab ci,促發 gradle task 任務,自動分析 dependency 鏈表
  2. 對比上一次打包的 dependency 鏈表,如果發現變更了,會通過 機器人進行通知。并附上最新的 commit,提交作者信息,需要 author 確認一下

執行流程

目前主要對 dev 分支進行監控,以下幾種場景會促發 diff 檢查

  • MR 合并進 dev 分支的時候
  • 在 dev 分支直接提交代碼的時候

diff 報告

diff 報告主要包括以下幾種信息

  • 作者,當前 commitId 的 author
  • branch 分支名
  • commitId 當前的 commitId, baseCommitId:基準 id
  • 變動依賴,這里最多顯示 6 行,超過會截斷,具體變動可以見詳情
  • 提交:如果是 MR 合并進來的,會顯示 MR 鏈接,否則,會顯示 commit 鏈接

不同分支 merge 過來的 diff 報告

檢測到  Dependency 變化
分支: 573029_test
作者: 徐俊
commitId: 4844590b     baseCommitId: bed4cb64
變動依賴: 
+\--- project :component-matrix
+     \--- com.google.code.gson:gson:2.8.2 -> 2.8.9
詳情: {url}
提交:{url}/merge_requests/4425/diffs

同個分支產生的 merge 報告

檢測到 Dependency 變化
分支: 573029_dep_diff
作者: xujun
commitId: 16145365     baseCommitId: 4844590b
變動依賴: 
+\--- project :component-matrix
+     \--- com.squareup.retrofit2:converter-gson:2.4.0 (*)
詳情: {url}
提交: {url)/commit/16145365

同個分支提交的 diff 報告

檢測到  Dependency 變化
分支: 573029_dep_diff
作者: xujun
commitId: 19f22516     baseCommitId: 8c90d512
變動依賴: 
+\--- project :component-tcpcache
+     \--- com.google.code.gson:gson:2.8.2 -> 2.8.9
詳情: {url}
提交: {url)/commit/16145365

我們主要講述以下幾點

  • 我們需要監控怎樣的 Dendenpency 變化
  • 怎樣獲取 dependency Tree
  • dependency Tree 怎樣做 diff
  • 如何找到基準點,進行 diff 計算
  • 怎樣結合 CI 進行計算

具體實現原理

我們需要監控怎樣的 Dendenpency 變化

眾所周知,Android 的 Dependency 是通過 gradle 進行配置的,如果我們在 build.gradle 下面配置了這樣,證明了我們依賴 recyclerview 這個庫。

dependencies {
    implementation androidx.recyclerview:recyclerview:1.1.0 ”
}

那一行代碼會給我們的 Dendenpency 帶來怎樣的變化呢?

有人說,它是新增了 recyclerview 這個庫。

這個說法對嘛?

不全對。

因為 gradle 依賴默認是有傳遞性的。他還會同時引入 recyclerview 自身所依賴的庫。

+--- androidx.recyclerview:recyclerview:1.1.0
|    +--- androidx.annotation:annotation:1.1.0 
|    +--- androidx.core:core:1.1.0 
|    +--- androidx.customview:customview:1.1.0
|    \--- androidx.collection:collection:1.0.0 -> 1.1.0 (*)
  1. 如果項目當中當前沒有這些庫的,會同時導入這些庫。
  2. 如果項目中有這些庫了,庫的版本比較低,會升級到相應的版本。比如 collection 會從 1.0.0 升級到 1.1.0

然而這些情況就是我們往往所忽略的,即使有代碼 review,有時候也會漏了。即使 review 待了,可能下意識也只以為只引入了這個庫,卻很難看到它背后的變化

而這些如果帶到線上去,有時候會發生一些難以預測的結果,因此,我們需要有專門的手段來監控這些變化。能夠監測到整條鏈路的變化,而不僅僅只是 implementation androidx.recyclerview:recyclerview:1.1.0 ” 這行代碼的變化

至于如果依賴的傳遞性,可以通過 transitiveexclude 等用法做到。 可以看這些文章,這里不再一一展開。

解決 Android Gradle 依賴的各種版本問題

build.gradle管理依賴的版本(傳遞(transitive)\排除(exclude)\強制(force)\動態版本(+))

怎樣獲取 dependency Tree

獲取 dependency Tree 的話,有多種方式

  1. 通過 project.configurations 這種方式獲取
  2. 通過 gradlew :app:dependencies task
  3. 通過 AsciiDependencyReportRenderer 獲取,需要適配不同版本的 gradle 版本

project.configurations 方式

通過這種方式獲取的,他是能夠獲取到所有的 dependencies,但是并不能看到 dependencies 的樹形關系。

偽代碼如下

        def configuration = project.configurations.getByName("debugCompileClasspath")
        configuration.resolvedConfiguration.lenientConfiguration.allModuleDependencies.each {
            def identifer = it.module.id
            depList.add(identifer)
        }

./gradlew dependencies

./gradlew dependencies 會輸出所有 configuration 的 Dependcency Tree。包括 testDebugImplementation、testDebugProvided、testDebugRuntimeOnly 等等

事實上,我們只關心打進 APK 包里面的 dependencies。因此我們可以指定更詳細的 configuration 。即

gradlew :app:dependencies --configuration releaseRuntimeClasspath

這樣,就只會輸出 Release 包 runtimeClasspath 相關的東西。

RuntimeClasspath 跟我們常用的 implementation,關系大概如下

在輸出的 dependencies tree 報告中,我們看到的格式一般是這樣的

** 這里有幾個格式需要說明一下**

  • x.x.x (*), 比如圖中的 4.2.2(*), 該依賴已經有了,將不再重復依賴,
  • x.x.x -> x.x.x 該依賴的版本被箭頭所指的版本代替
  • x.x.x -> x.x.x(*) 該依賴的版本被箭頭所指的版本代替,并且該依賴已經有了,不再重復依賴

AsciiDependencyReportRenderer

AsciiDependencyReportRenderer 這個東東,在不同的 gradle 版本有不同的差異,需要適配一下。

如果要這種方案,建議將某個版本的代碼剝離出來,偽代碼一般如下,單獨集成一個庫。

project.afterEvaluate {
   Log.i(TAG, "afterEvaluate")
   val renderer = AsciiDependencyReportRenderer()
   val sb = StringBuilder()
   val f = StreamingStyledTextOutputFactory(sb)
   renderer.setOutput(f.create(javaClass, LogLevel.INFO))
   val projectDetails = ProjectDetails.of(project)
   renderer.startProject(projectDetails)
   // sort all dependencies

   val configuration: org.gradle.api.artifacts.Configuration =
       project.configurations.getByName("releaseRuntimeClasspath")
   renderer.startConfiguration(configuration)
   renderer.render(configuration)
   renderer.completeConfiguration(configuration)
   // finish the whole processing
   renderer.completeProject(projectDetails)
   val textOutput = renderer.textOutput
   textOutput.println()
   Log.i(TAG, "end sb is $sb")

}

方案選擇

從上面闡述可知,第一種方案 project.configurations, 通過這種方式獲取的,他是能夠獲取到所有的 dependencies,但是并不能看到 dependencies 的樹形關系。

第二種方案 ./gradlew dependencies 的優點是簡單,直接采用 gradle 原生 Task,輸出特定格式的文本。然后根據規律將所有的 dependency tree 提出出來。

可能有人擔心 ./gradlew dependencies 的輸出格式會變化。

其實還好,看了幾個 gradle 版本的輸出格式,基本都是一樣的。

第三種方AsciiDependencyReportRenderer 的優點是可定制性高,缺點是麻煩,需要適配不同版本的 gradle。

最終我選擇的方案是方案二

怎樣對 dependency Tree 進行 diff 計算

傳統 diff 方案

可能很多人想到的方案是使用 Git diff 進行 diff 計算。但是這種方式有局限性。

  • 當有多個修改的時候,key -value 可能無法一一對應。
  • 他的 diff 類型 add、remove、 change 并不能一一對應我們 dependency add、remove、 change 的類型。

這無法達到我們想要的結果。因此,我們需要整合自己的 diff 算法。

自定義的 diff 方案

這里的方案是借鑒了 JakeWharton 大神的方案,在其基礎之上進行了改造。

原理大概如下

  1. 分別計算當前,上一次的 dependency tree,用 Set<List> 儲存,分別表示為 oldPaths,newPaths
  2. 接著根據 oldPaths 和 newPaths 計算出 removedTree, addedTree, changedTree
  3. 最后,根據 removedTree, addedTree 計算出 diff

第一步

對于這里的依賴,我們會使用 Set<List<String>> 的數據結構儲存

轉換之后的數據結構

這樣的好處就是可以看到每一個 dependency 的全路徑,如果 dependency 的全路徑不一樣,那么可以 diff 出來。

第二步 計算 remove 樹 和 add 樹

有了第一步的基礎,其實很簡單,直接調用 kotlin 的擴展方法 Set<T>.minus

如何找到一個基準點,進行 diff 計算

其實,這個說到底,就是找到上一個 commit 提交的 diff 文件。

  1. 看是不是 MR,如果是 MR,我們應該找到 MR 合并前的一個 commit
  2. 不是 MR 合并進來的,我們直接找到上一個 commit 即可

因此,我們可以借助 git 命令來處理。對于 merge request,目前主要有幾種情況會產生 merge request。

  • 直接 MR 合并進來的,這時候 parent 會產生兩個點,我們去 parent[0] 即可
  • 當前本地分支落后遠程分支, 且 local 分支有 commit 的時候,pull 或者 push 的時候,會產生一個 merge 節點,這時候 parent 會產生兩個點,我們去 parent[1] 即可

原理圖如下:

怎樣集合 Gialab CI 進行計算

Gialab push 或者 merge 的時候,我們需要感知到,接著執行特定的 task,進行計算。 每個公司的 CI 可能不太一樣,具體可以修改一下

gradlew :{appName}:checkDepDiff

總結

dependency diff 監控的原理其實不難,主要是涉及到挺多方面的,有興趣的可以看一下。如果覺得對你有所幫助的話,希望可以一鍵三連。

參考文章

https://wajahatkarim.com/2020/03/gradle-dependency-tree/

https://tomgregory.com/gradle-dependency-tree/

https://github.com/jfrog/gradle-dep-tree

http://muydev.top/2018/08/21/Analyze-Android-Dependency-Tree/

總結

以上是生活随笔為你收集整理的Android gradle dependency tree change(依赖树变化)监控实现,sdk version 变化一目了然的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 日韩有码专区 | 国产在线一区二区三区四区 | 超碰人人射 | 91精品国产色综合久久不卡电影 | 黑人巨大精品欧美一区免费视频 | 特种兵之深入敌后高清全集免费观看 | 91福利在线播放 | 欧美一二区 | 337p粉嫩日本欧洲亚洲大胆 | 国产精品熟女视频 | 国产精品天天干 | 免费av一区 | 欧美八区| 人人妻人人玩人人澡人人爽 | 精品无码一区二区三区免费 | 亚洲av成人一区二区国产精品 | 在线永久看片免费的视频 | 国内外成人在线视频 | 亚洲瑟瑟| 激情视频网站在线观看 | 国产视频在线观看网站 | 久久精品国产亚洲av麻豆图片 | 色老板av | 国产传媒在线播放 | 亚洲欧美日韩高清 | 色噜噜狠狠狠综合曰曰曰88av | 欧美精品1区 | 日韩专区一区 | 影音先锋亚洲精品 | 欧美日韩精品一区二区在线播放 | 91影院在线播放 | 天堂网中文字幕 | 国产性―交―乱―色―情人 | 免费观看在线高清 | 国产91熟女高潮一区二区 | 香蕉网站在线观看 | 免费成人福利视频 | 91天天综合 | 亚洲精品一区二区三区四区乱码 | 亚洲欧美一区二区三区不卡 | 亚洲成人动漫在线观看 | 88久久精品无码一区二区毛片 | 一本一道波多野结衣一区二区 | 日本大乳奶做爰 | 亚洲成a人片777777久久 | 999国产| 深夜视频在线观看 | 欧美精品色视频 | 亚洲毛片在线 | 激情小说一区 | 男人天堂手机在线观看 | 中文字幕资源站 | 日批黄色 | 啪视频在线观看 | 国产激情久久久久久熟女老人av | 日本一区免费视频 | 日韩高清中文字幕 | 日韩欧美一区在线 | 草久久 | 韩国19主播内部福利vip | 五月婷婷视频 | 亚洲va中文字幕 | 午夜视频入口 | 综合激情久久 | 一区在线不卡 | 18色av | 乱精品一区字幕二区 | 久久久久久久久久久久久国产 | 国产一区二区三区在线看 | 日韩欧美中文字幕在线观看 | 国内黄色一级片 | 尤果网福利视频在线观看 | 毛片网站在线 | 午夜av在线播放 | 亚洲欧美日韩精品久久亚洲区 | 欧美调教视频 | eeuss日韩| 亚洲九九九九 | 四虎影视成人永久免费观看亚洲欧美 | 亚洲综合在线一区二区 | 国产日韩免费视频 | 国产二区精品 | 毛片在线免费 | 久草这里只有精品 | 亚洲高清无码久久久 | 国产精品300页 | 尤物视频最新网址 | 绯色av蜜臀vs少妇 | 日韩女同强女同hd | 亚洲午夜无码久久久久 | 日韩亚洲一区二区三区 | 欧美一级淫片免费视频魅影视频 | 欧美色999 | 国产一在线观看 | 韩国三级hd两男一女 | 五月婷婷六月色 | www.色啪啪.com | 欧美一级淫片bbb一84 | 无码专区久久综合久中文字幕 |