プロジェクトのアップデートを繰り返していると未使用なイメージなどのリソースが放置され、次第にアプリサイズが増大してくることがよくある。
しかしXcodeはそのあたりのケアをしてくれない。膨大なリソース数だったら1つ1つ検索もしたくない。
スクリプトで頑張る文化となっている(と思われる)
不要なイメージを検出するスクリプトは適当に落ちてるけど、プロジェクトの形態や構成がまちまちなためか、
- pngやjpgなど特定のファイルフォーマットのものを対象としている
- .mや.hを対象としたobj-c用
- asset参照名と実体ファイル名が同一の前提
などなかなか自分のプロジェクトにあったものがなかったりする上に
R.swiftなどのリソース管理ライブラリを使用しているとうまく検出できなかったりもする。
そこで次の条件のプロジェクトに最適化した不要リソース検出スクリプトを書いてみた。
- R.swiftでリソース管理している
- イメージはSingle Scale(PDF)で管理している
- ついでにxcassetsで管理している色(.colorset)も不要なものを検出しておきたい
こちらに上げておいた。
https://github.com/yumemi-ajike/detect_unused_resources
- Xcode 11.3.1
- R.swift 5.0.2
# !/bin/sh
# Usage:
# ```
# $ cd path/to/project_root
# $ sh path/to/detect_unused_resources.sh . project_name/Assets.xcassets imageset
# ```
# $1=The search path for .xib, .swift, .storyboard files in your project.
# $2=The path of .xcassets directory
# $3=Specify "imageset" or "colorset"
echo "Creating files from $1 ..."
files=(`find $1 -type f -name "R.generated.swift" -prune -o -type f \( -name '*.xib' -o -name '*.swift' -o -name '*.storyboard' \) -exec echo ''{}'' \;`)
echo "${#files[*]} files found."
echo "Creating $3 resources from $2 ..."
resources=(`find $2 -type d -name *.$3 -exec echo ''{}'' \;`)
number_of_resources=${#resources[*]}
echo "$number_of_resources resources found."
i=0
unused_resources=()
for resource in ${resources[*]}
do
let "i += 1"
name=`basename -s .$3 $resource`
if ! grep -qhs "\b$name\b" ${files[*]}; then
unused_resources+=( $name )
echo "($i / $number_of_resources) $name is not referenced."
else
echo "($i / $number_of_resources)"
fi
done
echo "${#unused_resources[*]} unused resources found.\n${unused_resources[*]}\n"
使い方
$ cd path/to/project_root
$ sh path/to/detect_unused_resources.sh . project_name/Assets.xcassets imageset
引数は以下の通り
1つ目、プロジェクト内の.xib, .swift, .storyboardを検索するパス
2つ目、.xcassetsのパス
3つ目、"imageset"または"colorset"を指定する
処理内容
echo "Creating files from $1 ..."
files=(`find $1 -type f -name "R.generated.swift" -prune -o -type f \( -name '*.xib' -o -name '*.swift' -o -name '*.storyboard' \) -exec echo ''{}'' \;`)
echo "${#files[*]} files found."
1つ目の引数で指定したパスからR.generated.swiftを除外した上で再帰的に.xib, .swift, .storyboardファイルを検索している。
echo "Creating $3 resources from $2 ..."
resources=(`find $2 -type d -name *.$3 -exec echo ''{}'' \;`)
number_of_resources=${#resources[*]}
echo "$number_of_resources resources found."
2つ目の引数で指定したパスから再帰的に3つ目で指定した拡張子を持つディレクトリを検索している。
例では、Assets.xcassets以下から.imagesetのディレクトリを検索している。
for resource in ${resources[*]}
do
let "i += 1"
name=`basename -s .$3 $resource`
if ! grep -qhs "\b$name\b" ${files[*]}; then
unused_resources+=( $name )
echo "($i / $number_of_resources) $name is not referenced."
else
echo "($i / $number_of_resources)"
fi
done
files内から拡張子を除いたディレクトリ名をgrepして、無ければunused_resourcesに追加している。
echo "${#unused_resources[*]} unused resources found.\n${unused_resources[*]}\n"
最後に検出したリソース数と内容を出力。
結果
Creating files from . ...
1106 files found.
Creating imageset resources from project_name/Assets.xcassets ...
76 resources found.
(1 / 76)
(2 / 76)
(3 / 76)
~ 省略 ~
(45 / 76)
(46 / 76) background_image is not referenced.
(47 / 76)
(48 / 76)
(49 / 76) action_menu_icon is not referenced.
(50 / 76) rocket_icon is not referenced.
(51 / 76)
~ 省略 ~
(76 / 76)
3 unused resources found.
background_image action_menu_icon rocket_icon
検出された名称を元にXcode上で削除処理を行う必要がある。(ここも自動化したいけど、めんどくさそう。。)
因みに3つ目の引数でcolorsetを指定すると未使用な色定義が検出可能となっている。
$ sh path/to/detect_unused_resources.sh . project_name/Assets.xcassets colorset
Creating files from . ...
1106 files found.
Creating colorset resources from project_name/Assets.xcassets ...
23 resources found.
(1 / 23)
(2 / 23)
(3 / 23)
~ 省略 ~
(17 / 23)
(18 / 23) background_gray is not referenced.
(19 / 23)
(20 / 23) action_menu_red is not referenced.
(21 / 23)
(22 / 23)
(23 / 23)
2 unused resources found.
background_gray action_menu_red