如何批量导入/更新Android PNG格式Drawable并覆盖原有WEBP文件?
高效解决PNG与WEBP冲突的非手动方案
嘿,这个场景我太熟悉了——之前团队转WEBP后也遇到过设计临时给PNG更新的情况,给你几个不用手动一个个改的方案,亲测有效:
方案一:Gradle批量处理任务(推荐)
直接在项目的Module级build.gradle里加一个自定义任务,自动完成「删除旧WEBP→转换新PNG为WEBP→删除原PNG」的完整流程:
- 把以下代码加到你的Module级
build.gradle文件末尾:
task updateDrawablesToWebp { doLast { // 遍历所有drawable目录 def drawableDirs = fileTree(dir: 'src/main/res', include: 'drawable-*/').dirs // 筛选出所有更新的PNG文件 def updatedPngs = fileTree(dir: 'src/main/res', include: 'drawable-*/**.png').files updatedPngs.each { pngFile -> // 构建对应的WEBP文件路径 def webpPath = pngFile.path.replace('.png', '.webp') def webpFile = new File(webpPath) // 删除已存在的同名WEBP if (webpFile.exists()) { println "清理旧WEBP文件: ${webpFile.name}" webpFile.delete() } // 调用Android SDK自带的cwebp工具转换(自动适配当前项目的build-tools版本) def cwebpTool = "${android.sdkDirectory}/build-tools/${android.buildToolsVersion}/cwebp" def convertCmd = "\"${cwebpTool}\" -lossless \"${pngFile.path}\" -o \"${webpPath}\"" println "开始转换PNG→WEBP: ${pngFile.name}" def process = convertCmd.execute() process.waitFor() // 转换成功后删除原PNG if (webpFile.exists() && webpFile.size() > 0) { println "删除原PNG文件: ${pngFile.name}" pngFile.delete() } else { println "⚠️ 转换失败,请检查${pngFile.name}" } } } }
- 在Android Studio的Gradle面板里,找到你的Module→Tasks→other→
updateDrawablesToWebp,双击运行即可。
注意:运行前建议先备份项目,避免意外;如果你的build-tools版本较低,可能需要升级到28+版本(确保支持cwebp工具)。
方案二:Bash脚本(适合熟悉命令行的同学)
如果更习惯用命令行,可以写一个简单的Bash脚本,逻辑和上面的Gradle任务一致:
#!/bin/bash # 替换成你的Android SDK路径,或确保ANDROID_HOME环境变量已设置 ANDROID_SDK="${ANDROID_HOME:-~/Library/Android/sdk}" # 替换成你的build-tools版本(比如34.0.0) BUILD_TOOLS_VERSION="34.0.0" CWEBP_PATH="${ANDROID_SDK}/build-tools/${BUILD_TOOLS_VERSION}/cwebp" # 遍历所有drawable目录 for dir in src/main/res/drawable-*; do echo "处理目录: $dir" # 遍历当前目录下的所有PNG for png_file in "$dir"/*.png; do # 跳过空匹配(目录里没有PNG的情况) [ -e "$png_file" ] || continue # 获取文件名(不带后缀) file_name=$(basename "$png_file" .png) webp_file="$dir/${file_name}.webp" # 删除旧WEBP if [ -f "$webp_file" ]; then echo "→ 删除旧WEBP: $webp_file" rm "$webp_file" fi # 转换PNG到无损WEBP echo "→ 转换PNG→WEBP: $png_file" "$CWEBP_PATH" -lossless "$png_file" -o "$webp_file" # 删除原PNG(转换成功才删) if [ -f "$webp_file" ]; then echo "→ 删除原PNG: $png_file" rm "$png_file" else echo "⚠️ 转换失败: $png_file" fi done done
使用方法:
- 把脚本保存为
update_webp.sh,放到项目根目录 - 给脚本加执行权限:
chmod +x update_webp.sh - 运行脚本:
./update_webp.sh
方案三:精准处理指定的33个文件(避免全量遍历)
如果不想处理所有PNG,只针对这33个更新文件,可以修改Gradle任务,先把新PNG按drawable目录结构放到项目根目录的new_drawables文件夹(比如new_drawables/drawable-xxhdpi/ic_icon.png),然后用下面的任务只处理这些文件:
task updateSpecificDrawables { doLast { def newDrawableRoot = file('new_drawables') def newPngs = fileTree(dir: newDrawableRoot, include: 'drawable-*/**.png').files newPngs.each { newPng -> // 计算项目中对应的文件路径 def relativePath = newDrawableRoot.toURI().relativize(newPng.toURI()).getPath() def projectPng = file("src/main/res/${relativePath}") def projectWebp = file(projectPng.path.replace('.png', '.webp')) // 删除旧WEBP if (projectWebp.exists()) { println "删除旧WEBP: ${projectWebp.name}" projectWebp.delete() } // 复制新PNG到项目目录(覆盖旧PNG) println "复制新PNG到项目: ${newPng.name}" projectPng.parentFile.mkdirs() newPng.copyTo(projectPng, overwrite: true) // 转换为WEBP def cwebpTool = "${android.sdkDirectory}/build-tools/${android.buildToolsVersion}/cwebp" def convertCmd = "\"${cwebpTool}\" -lossless \"${projectPng.path}\" -o \"${projectWebp.path}\"" def process = convertCmd.execute() process.waitFor() // 删除原PNG if (projectWebp.exists()) { println "删除原PNG: ${projectPng.name}" projectPng.delete() } } } }
这样就只会处理你指定的33个文件,效率更高。
内容的提问来源于stack exchange,提问作者Notlaw
相关产品推荐
相关产品推荐

