LoginSignup
1
0

More than 1 year has passed since last update.

iOSでアイコンのメンテナンスを自動化する方法

Last updated at Posted at 2020-07-29

はじめに

先日、SARAHというグルメアプリの、ダークモード対応を担当しました🎉

その際に、大量のアイコンをメンテナンスする必要があったので、Xcodeへのiconアセット取り込みを自動化するスクリプトを作りました。
ZeplinからエクスポートしたPDFに癖があり、一致を調べるのが案外難しかったので、参考になれば幸いです。(実は、imagemagick便利、という話です。)

課題

  • ZeplinのどのアイコンがLightとDarkのペアなのか分からない👀
  • 手で一つ一つXcodeに登録していくのは、めちゃ時間がかかる😭
    • アイコンがアップデートされた時に、また大変😱
  • 人手で行うと、ミスが起こるリスクがある

自動化の方針

  • 同じアイコンのLight/Dark違いは、必ず同じファイル名にしてもらう
  • Zeplinから一括でダウンロードする
  • スクリプトで*.imagesetContents.jsonを自動生成する

自動化の課題

ZeplinからエクスポートしたPDFは、レンダリング結果が同じでも、バイナリレベルでは毎回違うことが判明しました。(メタデータ?)
そうすると以下のような事になり、あまり美しくありません。

  • 変更されたアイコンが少なくても、gitのログだと全て変更されたように見える
  • light/darkが同じアイコンなのに、余分なPDFが登録される

工夫した点

2つのPDFの内容がピクセルレベルで同じかどうかを、imagemagickで判別するようにしました。
いつの間にか、PDFにも標準で対応してたんですね〜
最初は単純にググってdiff-pdfとかを使ってましたが、依存ライブラリが大量な上に、結果はイマイチでした。

  • lightとdarkのPDFの内容が同じだった場合、anyのみで登録
  • 前回インポートしたPDFと内容が同じだった場合、copyしない
    • gitのログで、何のアイコンが更新されたかが分かる!

参考: ImageMagickで2枚の画像を比較

スクリプト

shellで関数とか分岐をこんなに書いたのは初めてかも…😅

参考: 割りと便利だけど微妙に忘れがちなbashのコマンド・チートシート

  • ~/Downloads/light/にダウンロード
  • ~/Downloads/dark/にダウンロード
  • ./scripts/import-icons.shで一括インポート

compareの出力画像は捨てて、終了コードだけを利用しています。

#!/usr/bin/env sh

brew install imagemagick

light_dir=~/Downloads/light
dark_dir=~/Downloads/dark
assets_dir=SARAH/Resources/Icons.xcassets
tmpdir=$(mktemp -d)
trap "rm -rf $tmpdir" 0 2

# compare by pixel
function is_identical() {
  if [ ! $# = 2 ] ; then
    echo "is_identical(): Invalid arguments: $*"
    exit 1
  fi
  if [ ! -f $1 -o ! -f $2 ] ; then
    return 1
  fi
  compare -metric AE $1 $2 /dev/null >& /dev/null
  return $?
}

# copy only if not identical
function overwrite() {
  file=`basename $2`
  if is_identical $1 $2 ; then
    echo "Skip: $file"
    return
  fi
  echo "Copy: $file"
  cp $1 $2
}

# Create any-dark imageset
function create_dual_imageset() {
  file=$1
  file_base=${file%.*}
  light_icon=$light_dir/$file
  dark_icon=$dark_dir/$file
  imageset=$assets_dir/$file_base".imageset"
  mkdir -p $imageset

  light_pdf=$file_base"_light.pdf"
  dark_pdf=$file_base"_dark.pdf"
  overwrite $light_icon $imageset/$light_pdf
  overwrite $dark_icon $imageset/$dark_pdf
  cat <<- EOF > $imageset/Contents.json
{
  "images" : [
    {
      "filename" : "$light_pdf",
      "idiom" : "universal"
    },
    {
      "appearances" : [
        {
          "appearance" : "luminosity",
          "value" : "dark"
        }
      ],
      "filename" : "$dark_pdf",
      "idiom" : "universal"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  },
  "properties" : {
    "preserves-vector-representation" : true
  }
}
EOF
}

# Create any imageset
function create_any_imageset() {
  file=$1
  file_base=${file%.*}
  icon=$light_dir/$file
  imageset=$assets_dir/$file_base".imageset"
  #rm -rf $imageset
  mkdir -p $imageset

  overwrite $icon $imageset/$file
  cat <<- EOF > $imageset/Contents.json
{
  "images" : [
    {
      "filename" : "$file",
      "idiom" : "universal"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  },
  "properties" : {
    "preserves-vector-representation" : true
  }
}
EOF
}

# Usage
if [ ! -d $light_dir -o ! -d $dark_dir ] ; then
  cat <<- EOF

1. Download all icons by "Download all assets" with "Original" naming convention:
    - https://app.zeplin.io/project/[light]
    - https://app.zeplin.io/project/[dark]
2. Unzip those as:
    - $light_dir -- light icons
    - $dark_dir -- dark icons

EOF
  exit 1
fi

# Diff
ls $light_dir > $tmpdir/light.txt
ls $dark_dir > $tmpdir/dark.txt
if ! diff $tmpdir/light.txt $tmpdir/dark.txt ; then
  echo "There are differences."
  exit 1
fi

# Clean assets
# TODO: create diff and remove
#for file in $assets_dir/*.imageset ; do
#  rm -rf $file
#done

# Import
icons=`cd $light_dir; ls -1`
for file in $icons ; do
  file_base=${file%.*}
  light_icon=$light_dir/$file
  dark_icon=$dark_dir/$file

  if is_identical $light_icon $dark_icon ; then
    create_any_imageset $file
  else
    create_dual_imageset $file
  fi
done

今後の課題

  • 削除されたIconに対応する
  • エクスポートまでデザイナーにお願いして、GitHub Actionで取り込むPRを作る

最後に

最初はポチポチ登録してたので、一括インポートは感動でした😭
あとimagemagickめちゃ便利、という話でした。
他にもこんな方法もあるよとか、フィードバックもぜひお願いします!
(SketchやFigmaからエクスポートした場合はどうなるんだろう…?🤔)

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0