apkサイズの最適化とSketchプラグインを作った話

みてねデザイナーの渡辺です。

少し前にエンジニアチームからapkサイズを減らそうという提案があり、apkサイズの最適化プロジェクトがスタートしました。

普段見落としがち & 自分も気づけていなかった apkサイズですが、ユーザーのストレージ容量やアプリのダウンロード時間に影響するととても重要な部分です。大きすぎるアプリはストレージを圧迫し、削除の対象になりやすそうです。また回線の細い環境では使い始めるまでの大きな障壁になったり、外出時であれば消費する通信量にも影響します。apkサイズの最適化は使い始めから使い続けてもらう上でのユーザー体験に大きく影響する大事な部分と言えそうです。

昨年より海外展開をスタートしたみてねとしては日本と比較して通信環境や使用デバイスのスペックにバラツキのある環境への配慮にもなり、実施コストに対して高い効果が見込めそうなとても良い施策に思いました。

現状のapkを確認

作業を始めるにあたって、今現在のapkの状況を見てみることにしました。ググって見るとGoogle が提供しているAPK Analyzerを使うとできるようです。

APK Analyzer

https://developer.android.com/studio/build/apk-analyzer

使い方は簡単で、Android Studio の上のメニューからBuild > Analyze APKを選び、対象のapkを選択するとファイルの構成が表示されました。 今回のスコープは画像リソースの最適化なので、resフォルダの値をどこまで最適化できるのかという話になりそうです。

APK Analyzerで調べた最適化前のapkファイルの構成

やることの整理

画像リソースの最適化でやることは下記3点になりそうです。

  • 使われていない画像の削除
  • 画像リソース(png, jpg)の最適化
  • 今後の運用を決める

使われていないイメージファイルの削除はエンジニアチームで進めていただいたのですが、画像の最適化はデザイナーサイド目視確認しつつ作業を進める必要がありました。 また今回一度きりの最適化ではなく、今後追加する画像に関してもapkが無駄に肥大化しないよう運用面も含めてデザインチームで考えていけると良さそうです。

仕組み化する

デザイナー個人個人に任せると自分も含めて忘れがちなので仕組み化して抜け漏れのないようにしたいと考えました。また運用方法を決めた上で実現可能なツールを選ぶ必要があるので、最適化ツールの選定より先にデザイナーの作業フローどのどこで最適化するかを決めることにしました。候補としては

  • コミットなど特定アクションで最適化(Git フック)
  • 書き出し時に最適化(Sketchプラグイン)

どちらも抜け漏れは防げそうですが、Sketchプラグインであれば目視確認もできる & オンオフも可能なのでより柔軟そうです。 なのでまずはSketchプラグインを探すことにしました。

Bitmap Compressor

Sketchプラグインとしての画像最適化ツールでは唯一Bohemian Coding が作ったオフィシャルプラグインが見つかりました。Quick CompressionとFull Compressionの2種類があり、Sketchのツールバー(画面右側)のExportから書き出すと前者が、画面上部のPluginsから書き出すと後者が実行されるようでした。

Quick Compression

pngはoptipng、jpgはjpegoptimで圧縮される

Quick Compression happens automatically, whenever you export an asset from Sketch using the File › Export… menu option or the Export button in the toolbar. The Plugin will run your PNG & JPG assets through optipng and jpegoptimusing the quickest settings for both, so that you get smaller files as fast as possible.

Full Compression

pngはadvpngoptipngpngcrushzopflipng、jpgはjpegtranjpegoptimで圧縮される。おそらく1つのファイルに対して複数のツールを実行して最適化している。

Full Compression happens when you choose the Plugins › Sketch Image Compressor › Export All Assets menu option. You’ll be asked for a path where your assets will be exported, and then the Plugin will export every exportable layerfrom your document, and run the assets through advpng, optipng, pngcrush, zopflipng, jpegtran and jpegoptim, using more aggressive settings than the Quick Compression (i.e: the operation will be extremely slow)

アセットを書き出す際にはツールバーのExportを使用することが通例なので最適化ツールをoptipngjpegoptimに決めればこのプラグインで進めることができそうです。

最適化ツールの検証

Bitmap Compressor プラグインが本当にベストなのか、optipngjpegoptimに加えて代表的なツールをテストが必要そうです。 公式のドキュメントの Reduce the APK size というページにもいくつか最適化ツールが紹介されていたので合わせて試してみることにしました。

Android公式(Reduce the APK size) https://developer.android.com/topic/performance/reduce-apk-size

pngquant を除いて全てロスレス圧縮(ピクセル単位でオリジナルと同じ、メタデータ削除などで画像最適化)になっています。画像にもよるとは思いますが、optipngpngcrushzopflipngあたりはおおよそ同じ値なので、lossless or lossy どちらの方針にするかでツールを決めて行けそうです。

JPGは jpegoptim が良さそうでした。

pngquantで最適化 & 実機確認

全体に対して pngquant で最適化したテストビルドを作成してデザインチームで確認しました。結果、ほぼ人の目で判断できないという話になり、pngquant で進めていくことになりました。画像のクオリティはもちろん大事にしたいですが、ほぼ見分けがつかないレベル & apkサイズを減らす方が圧倒的にユーザー体験の向上に貢献しそう、というのが決め手になりました。

プラグインの作成準備

前述のSketchプラグイン( Bitmap Compressor)では残念ながら pngquant に対応していないため自前でプラグインを作ってみることにしました。

公式ドキュメントによるとNode.js環境を整えつつ、skpm というSketchプラグインを作るためのツールチェーンを入れてくださいと書かれています。 Node.jsはskpmを動かすために必要で、skpmはプラグインを作ったり、ビルドしたり、パブリッシュするのに必要で、プラグイン自体はCocoaScript(JavaScript + the Cocoa frameworks)という基本JavaScriptみたいなもので書けばMocha経由でSketch側とやりとりできる仕組みと理解しました。(間違ってたらすみません)

Sketch Plugins are made possible by Mocha and CocoaScript, a bridge that lets you use Objective-C/Cocoa code from an external script written in JavaScript. The bridge takes care of the translation between JavaScript and Cocoa, so you can concentrate on the important parts (namely, making Sketch do awesome stuff).

node.jsのセットアップ

// nodebrewのインストール
$ brew install nodebrew// nodebrewのセットアップ
$ nodebrew setup// nodebrewのパスを通す
$ echo "export PATH=\$HOME/.nodebrew/current/bin:\$PATH" >> ~/.bash_profile
$ source ~/.bash_profile// 最新のnode.jsをインストール
$ nodebrew install-binary latest// インストールした最新版を使うように指定
$ nodebrew use latest// 最新のnode.jsのバージョンが返って来ればok
$ node -v

Sketchプラグイン開発環境のセットアップ

skpmはプラグイン開発用ツールチェーンのパッケージ

// skpmパッケージのインストール
$ npm install -g skpm// skpmを使って`my-plugin`という名前のプラグイン作成
$ skpm create my-plugin// 作成したプラグインディレクトリに移動
$ cd my-plugin// プラグインのビルド
$ npm run build

プラグインのテスト

Sketchを起動して何らかドキュメントを開くとプラグインがインストールされていて、Plugins > my-plugin > My Command ように作ったプラグインが実行できるようになっていました。

プラグインディレクトリの構成

├── .gitignore
├── README.md
├── src                         // 基本この中だけいじれば良い
│   ├── manifest.json           // プラグイン名とか設定
│   └── my-command.js           // 実際に実行されるコマンド
├── node_modules
│   └── skpm                    // ツールチェーン
├── my-plugin.sketchplugin      // npm run buildで生成される
│   └── Contents
│       ├── Resources
│       └── Sketch
│           ├── manifest.json
│           └── my-command.js
└── package.json

上記サンプルのプラグインでいうと、src ディレクトリ内の2つのファイル以外は気にしなくて良さそうです。

Sketchプラグイン作成

プラグインでやりたいこととしてはアセットを書き出す際にpngであればpngquant、jpgであれば jpegoptimを実行するというシンプルなものです。 プラグイン名を Awesome Image Compressor にすることに決め、skpm ツールでプラグインをcreateしました。

$ skpm create awesome-image-compressor

以下 主要なファイルのソースです。

manifest.json

actionsでトリガーの指定と実行するメソッドを定義できます。他にどんなイベントがあるかは下記にまとまっています。自分の場合には スライスを書き出す際のアクション(ExportSlices)で onExportSlices を実行するようにしています。

他のアクション https://developer.sketchapp.com/guides/action-api/ https://developer.sketchapp.com/reference/action/

compress-assets.js

ディレクトリやファイル名に半角スペースが含まれている場合のエスケープ処理が上手に書けなかったのが悔しいところでした。もっと良い感じに書けると思うのですが。。

assets/package.json

pngquantjpegoptimはassets下のpackage.jsonでインストールの指定をしています。

Bitmap Compressor と SVGO Export はどちらもやっていることも似ていたのでとても参考になりました。

Bitmap Compressor https://github.com/BohemianCoding/sketch-image-compressor

SVGO Export https://github.com/BohemianCoding/SketchAPI/tree/develop/examples/svgo-export

必要な作業を終え、下記コマンドを叩くと無事にSketchにプラグインがインストールされていました 🎉

$ cd awesome-image-compressor
$ npm run build

作ったプラグインはskpmツールを使って簡単にパブリッシュもできます。下記コマンドを実行するだけですが、自動で公式のプラグインディレクトリに Pull Request も作られてしまうので注意してください。

$ skpm publish

Sketch plugins are listed in a GitHub repository: https://github.com/sketchplugins/plugin-directory.

To add your plugin to the list, open a PR with the information about your plugin. Once it is merged, your plugin will appear here: https://sketchapp.com/extensions/plugins/

If you use skpm, the first time you publish a plugin using skpm publish, it will automatically create the PR for you.

パブリッシュした結果、公式にリストしてもらえました😃

(左端)

実際に作ったプラグイン(使ってみてください)

apkサイズ最適化の結果

52.9MB → 30.7MB 🎉 結果、apkサイズを40%程度減らすことができました!!

Before
After

終わりに

今回はminSdkVersionの関係でWebPの採用は見送りましたが、近い将来WebPを採用してさらにapkサイズを減らすことをエンジニア & デザインチームで検討しています。

WebP https://developer.android.com/studio/write/convert-webp

  • LossyなWebPは Android 4.0 (API level 14) 以上
  • Lossless and Transparent WebPは Android 4.3 (API level 18) 以上

mixi developers

ミクシィグループのエンジニアやデザイナーによるブログです。

Naoya Watanabe

Written by

Designer at mitene.us, mixi, Inc.

mixi developers

ミクシィグループのエンジニアやデザイナーによるブログです。