Run Script 之 修改AppIcon
Created by Ningyuan 2020/04/26
需求背景
方便地从图标上区分应用的版本以及环境等信息。
准备
首先,需要在Mac安装Homebrew,如果还没安装,请访问https://brew.sh了解并自行安装。
本次用到的主要工具为ImageMagick,它可以提供对图像的多种处理,有兴趣的可以自行学习。链接如下:
ImageMagick官方网址:https://www.imagemagick.org/script/command-line-options.php
ImageMagick中文站:http://www.imagemagick.com.cn
打开终端并输入以下命令,安装ImageMagick、GhostScripts:
brew install imagemagick
brew install ghostscript
简单尝试
- 下面使用convert命令,为”icon-60@2x.png“这张图片附加字体、图片,可自行找图片测试。
convert icon-60@2x.png -fill black -font Times-Bold -pointsize 18 -gravity south -annotate 0 "Hello World" test.png
```shell
# (运行项目后)应用所在路径,待会要用来查看生成的图标
echo "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
# 项目所在文件夹路径
echo "${SRCROOT}"
```
-
然后,Xcode -> Targets -> Build Phases -> 选“+” -> New Run Script phase -> 在新建的Run Script中填上下面的测试脚本代码,修改
BASE_IMAGE_PATH
与new.png
为自己的资源即可:BASE_IMAGE_PATH:要转换的图片路径,
- name
后的AppIcon60x60@2x.png
修改为项目中的其中一张图标名称new.png:beta图标的图片名称,同样需要修改为自己的图标
# Type a script or drag a script file from your workspace to insert its path. echo "hello sh" echo "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" IFS=$'\n' PATH=${PATH}:/usr/local/bin IFS=$'\n' function generateIcon () { BASE_IMAGE_NAME=$1 #获取本地的应用图标,然后分别将该路径保存到TARGET_PATH 和 BASE_IMAGE_PATH 变量中 TARGET_PATH="${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/${BASE_IMAGE_NAME}" BASE_IMAGE_PATH=$(find ${SRCROOT} -name "AppIcon60x60@2x.png") WIDTH=$(identify -format %w ${BASE_IMAGE_PATH}) FONT_SIZE=$(echo "$WIDTH * .15" | bc -l) #版本号 versionNumber=$MARKETING_VERSION #构建号 buildNumber=$CURRENT_PROJECT_VERSION #将new.png的图标的尺寸改为合适的大小 convert new.png -resize $WIDTHx$WIDTH resizedNew.png #首先,它在原始的应用图标上添加"Hello World"文本。 #然后该脚本执行合成的功能--将刚刚新生成的resizedNew.png放置在其上面。然后将合成的图片保存为应用的图标。 convert ${BASE_IMAGE_PATH} -fill black -font Times-Bold -pointsize ${FONT_SIZE} -gravity south -annotate 0 "$buildNumber" - | composite resizedNew.png - ${TARGET_PATH} } generateIcon "AppIcon60x60@2x.png" generateIcon "AppIcon60x60@3x.png" generateIcon "AppIcon76x76~ipad.png" generateIcon "AppIcon76x76@2x~ipad.png" generateIcon "AppIcon83.5x83.5@2x~ipad.png"
-
Command + B
编译,顺利的话会生成相应的图标,进入下面显示的路径,则可看到刚刚生成的图片:AppIcon60x60@2x.png、AppIcon60x60@3x.png、AppIcon76x76ipad.png、AppIcon76x76@2xipad.png、AppIcon83.5x83.5@2x~ipad.pngecho "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}
优化
- 实际使用中,将上面的测试脚本修改,封装为一个
replaceAppIcon.sh
或自己命名的一个.sh
文件 - 经测试,上述测试脚本只能在iOS10以及之前的版本生效,iOS11以后即使能成功生成图片,但实际运行项目时还是无法替换应用icon,需要将生成的图片存放到
Assets.xcassets
- 除了Release环境,根据当前scheme中选择的构建环境,自动生成对应
.xcassets
文件并存放到里面
下面是优化后的代码,复制到新建的.sh文件中,icons_path
和icons_desc_path
需要根据自己的项目修改成对应路径
#!/bin/sh
# 检查是否已安装所需工具
convertPath=`which convert`
echo ${convertPath}
if [[ ! -f ${convertPath} || -z ${convertPath} ]]; then
echo "监测到未安装ImageMagick、GhostScript,请在终端使用以下命令安装:
brew install imagemagick
brew install ghostscript"
exit -1;
fi
# version app-版本号
# build_num app-构建版本号
version=`/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "${CONFIGURATION_BUILD_DIR}/${INFOPLIST_PATH}"`
build_num=`/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "${CONFIGURATION_BUILD_DIR}/${INFOPLIST_PATH}"`
caption="${version}\n($build_num)"
echo $caption
# 处理icon
function processIcon() {
base_file=$1 # icon文件
temp_path=$2 # 生成文件的临时存放路径
dest_path=$3 # 目标路径
# 检查文件、路径是否存在,不存在则退出
if [[ ! -e $base_file ]]; then
echo "error: file does not exist: ${base_file}"
exit -1;
fi
if [[ -z $temp_path ]]; then
echo "error: temp_path does not exist: ${temp_path}"
exit -1;
fi
if [[ -z $dest_path ]]; then
echo "error: dest_path does not exist: ${dest_path}"
exit -1;
fi
file_name=$(basename "$base_file")
final_file_path="${dest_path}/${file_name}"
base_tmp_normalizedFileName="${file_name%.*}-normalized.${file_name##*.}"
base_tmp_normalizedFilePath="${temp_path}/${base_tmp_normalizedFileName}"
# Normalize
echo "Reverting optimized PNG to normal"
echo "xcrun -sdk iphoneos pngcrush -revert-iphone-optimizations -q '${base_file}' '${base_tmp_normalizedFilePath}'"
xcrun -sdk iphoneos pngcrush -revert-iphone-optimizations -q "${base_file}" "${base_tmp_normalizedFilePath}"
width=`identify -format %w "${base_tmp_normalizedFilePath}"`
height=`identify -format %h "${base_tmp_normalizedFilePath}"`
band_height=$((($height * 40) / 100))
band_position=$(($height - $band_height))
text_position=$(($band_position - 4))
point_size=$(((13 * $width) / 100))
echo "Image dimensions ($width x $height) - band height $band_height @ $band_position - point size $point_size"
# 添加你自己需定制的beta小标签 如new.png
baseBetaImg="new.png"
if [[ $baseBetaImg == "new.png" ]]; then
echo "不添加小标签。"
else
convert ${baseBetaImg} -resize ${width}x${height} /tmp/resizedBetaImg.png
fi
# 蒙版、版本号、构建号
convert "${base_tmp_normalizedFilePath}" -blur 10x8 /tmp/blurred.png
convert /tmp/blurred.png -gamma 0 -fill white -draw "rectangle 0,$band_position,$width,$height" /tmp/mask.png
convert -size ${width}x${band_height} xc:none -fill 'rgba(0,0,0,0.2)' -draw "rectangle 0,0,$width,$band_height" /tmp/labels-base.png
convert -background none -size ${width}x${band_height} -pointsize $point_size -fill white -gravity center -gravity South caption:"$caption" /tmp/labels.png
if [[ $baseBetaImg == "" ]]; then
convert "${base_tmp_normalizedFilePath}" /tmp/blurred.png /tmp/mask.png -composite /tmp/temp.png
else
convert "${base_tmp_normalizedFilePath}" /tmp/blurred.png /tmp/mask.png -composite /tmp/resizedBetaImg.png -composite /tmp/temp.png
rm /tmp/resizedBetaImg.png
fi
rm /tmp/blurred.png
rm /tmp/mask.png
# 合成最终icon图片
filename=New"${base_file}"
convert /tmp/temp.png /tmp/labels-base.png -geometry +0+$band_position -composite /tmp/labels.png -geometry +0+$text_position -geometry +${w}-${h} -composite -alpha remove "${final_file_path}"
# 最后清理临时生成的图片文件
rm /tmp/temp.png
rm /tmp/labels-base.png
rm /tmp/labels.png
rm "${base_tmp_normalizedFilePath}"
echo "Overlayed ${final_file_path}"
}
# 获取当前配置环境
config_envir=$CONFIGURATION
if [[$config_envir == "Release"]]; then
echo "Release环境不生成AppIcon"
exit -1;
else
# 非Release环境才生成新AppIcon
# Process all app icons and create the corresponding internal icons
# 本项目源icon路径
# 组成:@{PROJECT_DIR}/你的项目路径/.xcassets文件(如Assets.xcassets)/AppIcon.appiconset
icons_path="${PROJECT_DIR}/TingZhiPsychology/Assets.xcassets/AppIcon.appiconset"
# 生成icon图集存放路径
icons_dest_path="${PROJECT_DIR}/TingZhiPsychology/Assets.xcassets/AppIcon-${config_envir}.appiconset"
# 图片临时存放路径
tmp_path="${TEMP_DIR}/IconVersioning"
echo "icons_path: ${icons_path}"
echo "icons_dest_path: ${icons_dest_path}"
mkdir -p "${tmp_path}"
if [[ $icons_dest_path == "\\" ]]; then
echo "error: destination file path can't be the root directory"
exit -1;
fi
rm -rf "${icons_dest_path}"
cp -rf "${icons_path}" "${icons_dest_path}"
find "${icons_path}" -type f -name "*.png" -print0 |
while IFS= read -r -d '' file; do
echo "$file"
processIcon "${file}" "${tmp_path}" "${icons_dest_path}"
done
fi
使用
- 新建.sh文件,复制(并修改上述代码AppIcon存放路径)到项目中
- 将自己使用的beta图标移动到与
.xcodeproj
文件同级路径中,同时需要将图标的文件名.后缀
填入代码中的baseBetaImg
,没有则忽略此步骤 - Xcode -> Targets -> Build Phases -> 选“+” -> New Run Script phase -> 在新建的Run Script中填上.sh文件相应的路径,如下图所示:
- 先编译一次
command + B
,然后在Build Setting中搜索AppIcon,填入对应环境生成的AppIcon,如下图所示:
- 最后,若已删除新生成的AppIcon,或不需要使用,则需要步骤3中,将不同环境下的AppIcon还原