App极致瘦身: png 打包前自动化转换 webp。身轻如燕就是爽!
前言
大家都知道 png 是比較占用App體積的,有沒有工具可以在打包前(比如 assembleDebug、assembleRelease)自動去轉化所有的 png 圖片,包括第三方依賴庫里面的呢?之前不經意間發現有一個神器cwebp 轉化工具,是不是可以借鑒這種工具自己寫個Plugin完成圖片轉換,同時支持檢查大圖片,圖片大小可配置。話不多說,說干就干~
作者:小木箱
鏈接:https://juejin.cn/post/6897894068068876295
編寫插件前,需要思考幾個業務痛點
- 怎么拿到所有的 res 資源呢?
- 自動化轉換工具Task 的執行時機點?
- 如何檢查大圖片,并配置圖片大小,自動化開啟圖片轉換開關?
鑒于問題1,我們可以參考McImage, 其實也很簡單,就是一個 Gradle API,看鏈接文檔的文檔即可
鑒于問題2,該 Task 的執行時機其實是依賴于 MergeResources Task
鑒于問題3, 我們可以通過 Gradle API 自定義API 設置開關,圖片最大體積,給圖片添加白名單
convert2WebpConfig{enableWhenDebug truemaxSize 1024*1024 // 1MwhiteList ["xxx.png","xxx.png"]//... }圖片格式轉換開發流程
第一步: 新建Gradle Plugin 工程
第二步: 添加Png轉Webp配置
第三步: 針對com.android.application和com.android.library配置Plugin
實現自定義屬性圖片轉換器開關配置,圖片最大體積配置,圖片添加白名單配置
第五步: 將mac版本和windows版本圖片轉換工具移到 tool/cwebp 目錄下,并添加可執行程序
第六步 添加 auto.service 方便在編譯期間動態添加依賴
kapt "com.google.auto.service:auto-service:1.0-rc4"implementation "com.google.auto.service:auto-service:1.0-rc4"compileOnly "com.android.tools.build:gradle:4.0.1"testCompileOnly "com.android.tools.build:gradle:4.0.1"利用AutoService注解,使用的反射去實例化對象 VariantProcessor ,動態注冊Convert2WebpTask任務,后期使用該注解處理器處理Convert2WebpTask任務
@AutoService(VariantProcessor::class) class Convert2WebpVariantProcessor : VariantProcessor {override fun process(variant: BaseVariant) {val variantData = (variant as ApplicationVariantImpl).variantDataval tasks = variantData.scope.globalScope.project.tasksval convert2WebpTask = tasks.findByName("convert2Webp") ?: tasks.create("convert2Webp",Convert2WebpTask::class.java)val mergeResourcesTask = variant.mergeResourcesProvider.get()mergeResourcesTask.dependsOn(convert2WebpTask)} }第七步 Convert2WebpTask任務 執行
7.1 檢查tools 路徑下是否有 webp工具
7.2 如果配置屬性配置開關為false,中斷任務
if (!config.enableWhenDebug) {return@all}7.3 拿到所有的Android資源文件,遍歷資源文件,將滿足條件的大圖添加到大圖列表
? val dir = variant.allRawAndroidResources.files ? */** \* 遍歷資源文件目錄 \*/* ? ? ? **for** (channelDir **in** dir) { ? traverseResDir(channelDir, imageFileList, cacheList, object : IBigImage { ? override fun onBigImage(file: File) { ? bigImageList.add(file.absolutePath) ? } ? }) ? } ? ? **private** fun traverseResDir( ? file: File, ? imageFileList: ArrayList<File>, ? cacheList: ArrayList<String>, ? iBigImage: IBigImage ? ) {? **if** (cacheList.contains(file.absolutePath)) { ? **return** ? } **else** { ? cacheList.add(file.absolutePath) ? }? **if** (file.isDirectory) { ? file.listFiles()?.forEach { ? if (it.isDirectory) { ? traverseResDir(it, imageFileList, cacheList, iBigImage) ? } else { ? filterImage(it, imageFileList, iBigImage) ? } ? } ? } else { ? filterImage(file, imageFileList, iBigImage) ? } ? }7.4 過濾不合規的圖片文件
-
如果添加了圖片白名單或者文件不是圖片格式,過濾
-
如果圖片尺寸合規,并且圖片是大圖,大圖白名單沒有圖片,添加到大圖列表
-
否則添加到圖片目錄
7.5 檢查大圖,并且將圖片引用找出來
**private** fun checkBigImage() {**if** (bigImageList.size != 0) {val stringBuffer = StringBuffer("Big Image Detector! ").append("ImageSize can't over ${config.maxSize / 1024}kb.\n").append("To fix this exception, you can increase maxSize or config them in bigImageWhiteList\n").append("Big Image List: \n")**for** (fileName **in** bigImageList) {stringBuffer.append(fileName)stringBuffer.append("\n")}**throw** GradleException(stringBuffer.toString())}}7.6 處理圖片壓縮任務
? **private** fun dispatchOptimizeTask(imageFileList: java.util.ArrayList<File>) { ? **if** (imageFileList.size == 0 || bigImageList.isNotEmpty()) { ? **return** ? } ? val coreNum = Runtime.getRuntime().availableProcessors() ? **if** (imageFileList.size < coreNum) { ? **for** (file **in** imageFileList) { ? optimizeImage(file) ? } ? } **else** { ? val results = ArrayList<Future<Unit>>() ? val pool = Executors.newFixedThreadPool(coreNum) ? val part = imageFileList.size / coreNum ? **for** (i **in** 0 until coreNum) { ? val from = i * part ? val to = **if** (i == coreNum - 1) imageFileList.size - 1 **else** (i + 1) * part - 1 ? results.add(pool.submit(Callable<Unit> { ? **for** (index **in** from..to) { ? optimizeImage(imageFileList[index]) ? } ? })) ? } ? **for** (f **in** results) { ? **try** { ? f.get() ? } **catch** (e: Exception) { ? println("EHiPlugin Convert2WebpTask#dispatchOptimizeTask() execute wrong.") ? } ? } ? } ? }? */** \* 壓縮圖片 \*/* ? **private** fun optimizeImage(file: File) { ? val path: String = file.path ? **if** (File(path).exists()) { ? oldSize += File(path).length() ? } ? ImageUtil.convert2Webp(file) ? calcNewSize(path) ? }7.7 計算壓縮前后圖片大小,以及壓縮耗時時間
**private** fun **optimizeImage**(file: File) {val path: String = file.path**if** (File(path).**exists**()) {oldSize += File(path).length()}ImageUtil.convert2Webp(file)calcNewSize(path)}dispatchOptimizeTask(imageFileList)? println("Before optimize Size: ${oldSize / 1024}kb") ? println("After optimize Size: ${newSize / 1024}kb") ? println("Optimize Size: ${(oldSize - newSize) / 1024}kb")? println("CostTotalTime: ${System.currentTimeMillis() - startTime}ms") ? println("------------------------------------")總結
本文主要是在打包前對App做了一次圖片全量替換,圖片轉換方式借助的是Google開源工具cwebp,當然我們可以通過白名單方式規范圖片尺寸大小和插件開關,如果你掌握本文內容,不僅會對你們公司應用瘦身有所幫助,同時也能彌補你對 Gradle Plugin 知識的渴望~
筆記
【360°全方位性能調優】
這份筆記我將Android-360°全方位性能優化知識點,以及微信、淘寶、抖音、頭條、高德地圖、優酷等等億萬級用戶APP在性能優化方面的實踐經驗,整合成了一套系統的知識筆記PDF,從理論到實踐,涉及Android性能優化的所有知識點,長達721頁電子書!相信看完這份文檔,你會對Android性能調優知識體系及各種方案有更系統、更深入的理解。
需要的小伙伴點贊+關注后在我的GitHub即可直接免費下載獲取~
文末
感謝大家關注我,分享Android干貨,交流Android技術。
對文章有何見解,或者有何技術問題,都可以在評論區一起留言討論,我會虔誠為你解答。
也歡迎大家來我的B站找我玩,有各類Android架構師進階技術難點的視頻講解,助你早日升職加薪。
B站直通車:https://space.bilibili.com/544650554
總結
以上是生活随笔為你收集整理的App极致瘦身: png 打包前自动化转换 webp。身轻如燕就是爽!的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 写在飞雪如絮时
- 下一篇: 2022年资料员-岗位技能(资料员)复训