Preface
是不是早已受够了系统原有的奇丑无比的图标,对于追求完美不放过任何一个细节的我们来说,这个简直不能忍啊。
Launchpad早期图整个事情的起因就是这么简单,那天晚上我决定不能再这样下去了,于是乎我便迫不及待的打开电脑,兴致冲冲的干了起来。
在MacOSX下替换App图标主要有两种方式:
1.直接替换App包里的图标
右键>显示包内容>Contents>Resources,备份原来的图标,将你的图标按照原来的重命名。
2.显示简介里替换
这个比上面的要简单,将图标直接拖到简介里原来的图标上就可以了。
上面说的是替换App的icon,但是Finder
和废纸篓
不能用上述方法,需要前往/系统/资源库/CoreServices
,找到Dock
,然后进入content>resources,替换相对应的finder
,trashempty
,trashfull
图片。注意备份哟!
如果故事发展到这里就结束了,那个没有下文了,然而事情没这么简单。
Shell Script
话说刚开始试了几个,感觉还不错。这时候你说干脆写个自动脚本算了,一开始我是拒绝的。可是后来一个一个的替换,一想到还有一百多个图标,实在是太TM蛋疼了。。
为什么用shell脚本?因为我不会啊,正好给自己一个理由去学学shell编程。
(最后才发现,原来替换图标是个大坑,用代码更麻烦。。)
有哪些功能:
- 用默认的主题替换App icon
- 恢复原来的图标
- 从Launchpad中隐藏指定的App
- 用指定的主题替换App icon
- 替换指定文件或文件夹的icon
- 帮助
# Usage
function usage() {
echo "[*] Usage:"
echo "[*] $0 [-i | -r | -h | -d [app_name] | -s [theme] | -f [file] [icon]]"
echo "[*] -i: install the default icon theme"
echo "[*] -r: restore the origin icon"
echo "[*] -d: delete/hide the app in Launchpad"
echo "[*] -s: install the specified theme"
echo "[*] -f: set icon for file or folder"
echo "[*] -h: help"
}
由于某些要对系统文件进行操作,所以需要root权限。
if [ $UID -ne 0 ]; then
echo "[*] Superuser privileges are required to run this script."
echo "[*] e.g. \"sudo $0\""
exit 1
fi
if [ ! $1 ]; then
usage
exit 1
fi
从上面我们知道有两种方法可以替换图标,其实这两种方法原理不同。下面我们来分别实现:
1.替换App包里的图标
第一种方法最简单,我们只需要替换相应的/Contents/Resources/
的App图标即可。先备份原来的icon文件,然后复制新的icon过来。
# setAppIcon [app_path] [iconfile]
function setAppIcon() {
apath=$1
ipath=$2
# Replace the *.app/Contents/Resources/*.icns
icon=`readPlist "$apath/Contents/Info.plist" "CFBundleIconFile"`
if [ "${icon##*.}" != "icns" ]; then
icon="$icon".icns
fi
if [ ! -e "$apath/Contents/Resources/$icon.bak" ]; then
cp "$apath/Contents/Resources/$icon" "$apath/Contents/Resources/$icon.bak"
fi
cp "$ipath" "$apath/Contents/Resources/$icon"
touch "$apath/1"
rm "$apath/1"
}
咦,最后这个奇葩的touch
接着rm
是干嘛的,老实说当时我手动替换图标后发现半天没有变化,相信大家试过也是这样。
但是有次不经意间多创建了一个文件,奇怪的发现居然变了,估计是缓存的原因吧,我也不知道。。反正就通过这种方式更新App icon使之生效。。
还有一个问题就是,App中icns格式的图标众多,如何找到其中的icon图标?
Plist文件是以.plist为结尾的文件的总称. 众所周知, Plist在Mac OS X系统中起着举足轻重的作用,就如同Windows里面的Registry一样,系统和程序使用Plist文件来存储自己的安装/配置/属性等信息。
由于每个App的icon文件名不是固定的,但是我们可以在App里的Info.plist文件中找到,其中CFBundleIconFile
对应的就是icon文件。
icon=`readPlist "$apath/Contents/Info.plist" "CFBundleIconFile"`
然而怎么读取plist
格式的文件呢?
用cat
命令输出文本然后去匹配读取其中的键值对?太麻烦了,这里我们寻找到了一个自带的工具Plutil
。
Plutil
是开发环境提供的一个命令行命令,使用这个命令可以转换Plist
文件的格式,而且可以检查Plist
文件的语法和完整性。
通过plutil -p [plist file]
可以以键值对的格式输出。最后,读取键值的readPlist
函数如下:
# readPlist [plist] [key]
function readPlist() {
plist=$1
key=$2
value=`plutil -p "$plist" | grep $key | awk -F '=>' '{print $2}' | sed -e 's/\"//g'`
echo $value
}
2.显示简介里替换
首先我们要搞清楚当我们把图片拖到简介里的小图标时到底改变了什么。
我们随便打开一个App看看,感觉里面没有什么啊。
Sketch App现在,看不到什么并不意味着没有什么,在终端里再看看:
居然发现一个隐藏文件Icon?
,看名字也知道是干嘛的了,找了半天原来你在这里!
那个
?
不是真的问号,而是乱码。其实这个文件的名字应该是Icon\r
,\r
指的就是十六进制的0x0D
,因为\r
不是可打印字符,所以在终端里显示为?
。如果在终端里自动补全的话则会显示Icon^M
,^M
就是\r
。
ls -lO
hidden
说明这是一个隐藏文件,所以我们在Finder里看不到。
当你尝试打开它时
open Icon^M
打不开,什么都木有。
可是,不知注意到没,好奇怪,为啥这个文件的大小是零啊~
The actual icon data is stored in the file's Resource Fork. These days Mac OS doesn't use actual resource forks, so the image is stored in an HFS extended attribute named
com.apple.ResourceFork
.
在 Mac OS X 下,文件经常会被附加上 OS X 特有的扩展属性 ( extend attributes ),具体表现是用
ls -l
查看时会有@
的标记,这个@
属性是用户在 Finder 中对文件进行任意操作后就会被附带上
通过@
参数查看扩展属性:
ls -l@ Icon^M
果然icon数据存在com.apple.ResourceFork
中。
我们还可以把resource fork
里面的数据复制出来:
sudo cp Icon^M/..namedfork/rsrc Icondata
从十六进制数据中很清楚的看出这是一个icns
格式的icon。
现在我们已经知道替换的东西在哪里了,接下来就是如何替换了。
这里要用到Xcode
里面的Developer Tools
一些工具,所以前提是你已安装了Xcode
及其Developer Tools
,具体过程见代码:
# xcodeDevToolsSetIcon [filepath] [iconfile]
function xcodeDevToolsSetIcon() {
fpath=$1
ipath=$2
xcode_devtools="/Applications/Xcode.app/Contents/Developer/Tools/"
if [ -d $xcode_devtools ]; then
if [ -d "$fpath" ]; then
# $fpath is a direstory
touch "$fpath/Icon\r"
cp "$ipath" tempIcon.icns
sips -i tempIcon.icns > /dev/null 2>&1
derez -only icns tempIcon.icns > tempicns.rsrc
rez -a tempicns.rsrc -o "$fpath/Icon\r"
setfile -a C "$fpath"
rm tempIcon.icns
rm tempicns.rsrc
# hide Icon^M file inside folder
setfile -a V "$fpath/Icon\r"
elif [ -e "$fpath" ]; then
# $fpath is a file
cp "$ipath" tempIcon.icns
sips -i tempIcon.icns > /dev/null 2>&1
derez -only icns tempIcon.icns > tempicns.rsrc
rez -a tempicns.rsrc -o "$fpath"
setfile -a C "$fpath"
rm tempIcon.icns
rm tempicns.rsrc
else
echo "$fpath is NOT a file or direstory"
exit 1
fi
else
echo "[*] Error: this need Xcode Developer/Tools. Please install it first!"
exit 1
fi
}
Whst's more
当上面两个重头完成后,剩下还有一些其他的,比如说替换Finder和废纸篓:
# Change Finder & Trash app icon
echo "[*] Replace the Finder & Trash icon ..."
for img in ${imgs[*]}
do
if [ ! -e $dock_res/$img.bak ]; then
mv $dock_res/$img $dock_res/$img.bak
else
rm $dock_res/$img 2> /dev/null
fi
done
for file in $default_theme/Docker/*
do
cp -p $file $dock_res/
done
# delete caches & restart docker
find /private/var/ -name *dock.iconcache* -exec rm {} \;
killall Dock
注意的是,要使Dock的上的图标生效需重启Dock。
隐藏 Launchpad 里的图标:
# hideAppIconInLaunchpad [app_name]
function hideAppIconInLaunchpad() {
appname=$1
sqlite3 $(find /private/var/folders -name com.apple.dock.launchpad)/db/db "DELETE FROM apps WHERE title='$appname';"
killall Dock
}
将动态屏保设置成背景(这是什么鬼。。)
# Make screensaver load as the desktop wallpaper
function screensaverWallpaper() {
/System/Library/Frameworks/ScreenSaver.framework/Resources/ScreenSaverEngine.app/Contents/MacOS/ScreenSaverEngine -background &
}
当然啦,还要有还原的功能:
# restoreAppIcon [app_path]
function restoreAppIcon() {
apath=$1
for bak in "$apath"/Contents/Resources/*.icns.bak
do
if [ "$bak" != "$apath/Contents/Resources/*.icns.bak" ]; then
pre="${bak%.*}"
rm "$pre"
cp "$bak" "$pre"
fi
done
if [ -e "$apath/Icon\r" ]; then
rm "$apath/Icon\r"
fi
touch "$apath/1"
rm "$apath/1"
}
function restoreDocker() {
for img in ${imgs[*]}
do
if [ -e $dock_res/$img.bak ]; then
mv $dock_res/$img.bak $dock_res/$img
fi
done
find /private/var/ -name *dock.iconcache* -exec rm {} \;
killall Dock
}
主程序的大部分是逻辑控制,这里就不贴出来了,全部代码请移步Github——Iconista。
注:上述所有代码中的 "/Icon\r" 都应该是 "/Icon"$'\r'。为啥会乱码,简书的bug?
Iconista
经过本人的慎重决定,这货的名字就叫Iconista
,我们的口号是:不要998,就要Iconista~
本着分享的精神,Iconista是一个开源项目,并且欢迎大家无限次无羞耻的免费使用和反馈。项目地址看这里看这里---->O_O!
使用方法很简单,下载好源码后:
cd build/
sudo ./Iconista -i
即可!
更多的使用方法见文档。
这里多说一句的是,默认使用的主题图标来自BlackVariant (Patrick),非商业性免费使用。
其放在/Themes/default/
目录下。你也可以使用自己的主题,同时也欢迎大家制作更多更炫酷的主题。
如何自定义主题
在
/Themes/
路径下建立一个以你主题为名字的文件夹,必须包含以下目录:
- /Applications
- /Apps
- /Docker
- /Utilities
每个文件夹里放相应的
icns
格式的图标,图标名以App名命名,具体可参考默认主题
这么酷炫的东东怎么能没有主页呢,当然有啦,在这里也预告一下,关于这个页面有好多要讲的,下一篇文章将要带领你体验背后那些不为人知的故事。
地址:http://urinx.github.io/app/iconista/
Iconista主页Preview
用Mac,自定义主题图标,从此逼格又提升一个数量级。这里我就给大家预览一下最后的效果吧!
这是原先的:
原来的
Iconista后期处理后的:
就是这么任性!
Last
最后的最后,欢迎大家关注我的微信公众号(urinx),满满的干货
如果你有什么建议和想法想和我交流,各种bug想要反馈,或者纯属想要交朋友,这是我的微信(google-2)
wechatUpdates
2015.6.6
- 新增了 Mac OS X 10.9 的图标主题
- 默认主题补充了更多的第三方App图标
- 修复了一些bug
Reference
[0]. MAC系统图标的更换
[1]. 在 10.9 下换 Finder 图标的方法
[2]. plutil(1) Mac OS X Manual Page
[3]. Mac OS X: 编辑PList文件的嵌套键值
[4]. OS X 的一些技巧汇总
[5]. osx - Icon? file on OS X desktop - Super User
[6]. How to change the icon of file in MacOS in Objective-C? - Stack Overflow
[7]. Changing icon of package created by package maker - Stack Overflow
[8]. osx - Manipulate Mac OS X file icons from Automator or command-line - Super User
网友评论
[*] Replace the default system icon ...
[*] - This is NOT support now
[*] done
第三步好像没执行成功?!