利用gradle腳本驅(qū)動python腳本在打包時執(zhí)行項目全局圖片自動壓縮,達到精簡apk包的大小。
1、背景
為什么要做自動化壓縮圖片?設計給的切圖多半是采用png格式,就算使用png的有損壓縮也是九牛一毛,但是webp的壓縮效果就很明顯,一個png直接轉(zhuǎn)換成webp壓縮效率平均有70%以上,這個開發(fā)一般都知道。當然我們直接把圖片放到項目中點擊右鍵也可以直接轉(zhuǎn)換成webp,但是這種操作難免效率低下影響開發(fā),而且有時候可能會忘記壓縮。所以萌生了在打包或者上線前添加一個主動壓縮圖片的流程的想法。
2、如何做
既然涉及到自動化,就免不了使用Jenkins,Python一開始最先想到的是這個過程入手,但是Jenkins在構建后流程中加入指令是比較方便的,一些對打好包的自動化流程就比較方便,比如自動化加固,自動化批量簽名渠道包等等。但是想在構建前加入指令就不是很方便了。
所以這里我采用的是從Gradle入手,因為以前在Gradle中做過其他的自動化構建流程。
這里的想法是使用Gradle中加入新的打包任務在執(zhí)行完圖片壓縮之后,在執(zhí)行打包流程。
這里還需要一個Webp轉(zhuǎn)化工具:官方鏈接
看文檔命令比較簡單 一般我們可能會用的參數(shù)主要是-q,也可以采用默認值,也是官方的標準值
cwebp [options] input_file -o output_file.webp
-q float指定 RGB 通道在 0 和 100 之間的壓縮因數(shù)。默認值為 75。在使用有損壓縮(默認)的情況下,一個小因素會導致質(zhì)量較低的較小文件。使用 100 值可以實現(xiàn)最佳質(zhì)量。對于無損壓縮(通過 -lossless 選項指定),較小的因素可以提高壓縮速度,但生成的文件也較大。通過使用 100 值來實現(xiàn)最大壓縮
2.1、編寫Python腳本
這里我們需要Python,至于怎么安裝太簡單了,就不細說了。
python這里我們也可以采用image庫里的PIL對png進行預壓縮然后再轉(zhuǎn)Webp,效果會好一點點,也就好一點點,所以我沒用。然后Python主要思路是遍歷項目指定目錄的png文件,然后自動轉(zhuǎn)換并替換原來的源文件。
if __name__ == "__main__":
if os.getcwd().endswith("tools"):
projectPath = "/".join(os.getcwd().split("/")[:-1])
else:
projectPath = os.getcwd()
print(projectPath + "/../app")
convert2WebpInDirectory(projectPath + "/../app")
# convert2WebpInDirectory(projectPath + "/common")
# convert2WebpInDirectory(projectPath + "/resource")
# convert2WebpInDirectory(projectPath + "/market")
print("\n\n==> convert " + str(len(result)) + " png to webp")
print(result)
這邊我采用的相對目錄從os.getcwd獲取項目根目錄。
腳本是在項目根目錄里建了一個Script文件夾存放python腳本,自動化python腳本都是放在這個目錄下。
然后遍歷指定的目錄去尋找png圖片的時候注意忽略.9圖,Build目錄,asset目錄下的圖片。
def convert2WebpInDirectory(dir):
print(" ------> begin:",dir)
if os.path.isdir(dir):
allfiles = os.listdir(dir)
for fi in allfiles:
#print(" ------> fi:", fi)
fi_d = os.path.join(dir, fi)
if os.path.isdir(fi_d):
convert2WebpInDirectory(fi_d)
else:
if fi_d.endswith(".png"):
print("fi_d:", fi_d)
png = fi_d
if png.find(".9.png") > 0:
continue
if png.find("build/intermediates/") > 0:
continue
if png.find("assets/images/") > 0:
continue
print(" ------> png:", png)
filename = png.split("/")[-1].replace(".png", ".webp")
print(" ------> filename:", filename)
filedir = "/".join(png.split("/")[:-1])
webp = "%s/%s" % (filedir, filename)
print(" ------> webp:", webp)
commandline = "%s/../tools/libwebp-0.4.1/bin/cwebp -q 80 %s -o %s" % (projectPath, png, webp)
os.system(commandline)
result.append(webp.split("/")[-1])
os.remove(png)
print(webp + " ------> sucess")
2.2 編寫Gradle腳本
在項目根目錄下創(chuàng)建autoRelease.gradle文件
def projectPath = "."
def zipPath = "${projectPath}/tools/libwebp-0.4.1.zip" //rootProject.ext.jiagu["unzipPath"]
def unzipPath = "${projectPath}/tools" //rootProject.ext.jiagu["unzipPath"]
def jarPath = "${projectPath}/tools/libwebp-0.4.1" //rootProject.ext.jiagu["unzipPath"]
編寫2個新的打包任務,依賴預處理任務preHandleBeforeRelease,打測試包app:assembleDebug,打正式包
app:assembleDebug
任務分類為build這樣我們就可以在gradle列表里的build文件夾看到了。這個任務主要是判斷cwebp可執(zhí)行文件是否解壓了,沒有解壓則先解壓。
task releaseDebugAuto(dependsOn: ['preHandleBeforeRelease','app:assembleDebug']){
group = "build"
def jarFile = file(jarPath)
if (jarFile.exists()) {
return
}
//解壓 Zip 文件
ant.unzip(src: zipPath, dest: unzipPath, encoding: "utf-8")
//將解壓后的文件開啟讀寫權限,防止執(zhí)行 Jar 文件沒有權限執(zhí)行
if(!Os.isFamily(Os.FAMILY_WINDOWS) && !Os.isFamily(Os.FAMILY_MAC)){
exec {
executable = 'chmod'
args = ['-R', '777', unzipPath]
}
}
}
預處理任務,則是在保證壓縮包ok的情況下,執(zhí)行Python腳本。
這里為了保證py文件依賴的三方庫存在,執(zhí)行了requirements.text,壓縮webp這個文件里是空的。
生成這個文件也很簡單,在編寫完腳本之后再py項目里執(zhí)行
pip freeze -> requirements.txt
就可以了。
task preHandleBeforeRelease(){
exec {
workingDir = "${projectPath}/Script"
commandLine = ['python3','-m','pip','install','-r','requirements.txt']
}
exec {
workingDir = "${projectPath}/Script"
commandLine = ['python3','png2webp.py']
}
}
好了這里基本所有的主要步驟都ok了,執(zhí)行一下打包命令。

我這里因為png已經(jīng)全部轉(zhuǎn)換完畢,所以convert 0 png,執(zhí)行成功。
最后一步打開Jenkins,配置自動打包任務。
Jenkins配置
