2011/12/17

【Titanium Advent Calendar 2011:十七日目】ダイエットしてますか?iOS編

このエントリーは、@astronaughtsさんの企画された「Titanium Advent Calendar 2011」の17日目エントリーとして参加しています。

Titanium Mobileで作ったアプリの問題に、ファイルサイズが大きいことがあります。iOS の場合ちょっとしたアプリでも3MB越えが普通です。これをなんとかしようというのが今回の話です。
いつものように、D.I.Y. & On Your Risk な話なので、実施にあたっては、各自の責任で行ってください。以下の実施例は、Titanium SDK 1.7.5 、XCode 4.2、iOS SDK 5を使っています。


Ti のビルドシステムそれなりに賢いことをしてくれていることを最初にいっておきましょう。キーになるのは、Ti SDK ディレクトリ /Classes/ に含まれる defines.h です。
このファイルは、Simulatorでビルドする場合には、そのままコピーされますが、"Install - iOS Device"や"Deploy Distribute - App Store"の場合、JavaScriptのソースファイルから使用された内部モジュールの情報を収集して、生成されます。


元のdefines.hファイル
(前略)
#define USE_TI_STREAM
#define USE_TI_CODEC
#define USE_TI_UTILS
#define USE_TI_XML
#define USE_TI_ACCELEROMETER
#define USE_TI_API
#define USE_TI_APP
#define USE_TI_CONTACTS
#define USE_TI_DATABASE
(以下略)


Tiビルドシステムが生成したdefines.hファイル
// Warning: this is generated file. Do not modify!
#define TI_VERSION 1.7.5
#define USE_TI_ANALYTICS 1
#define USE_TI_NETWORK 1
#define USE_TI_PLATFORM 1
#define USE_TI_UI 1
#define USE_TI_API 1
#define USE_TI_UISETBACKGROUNDCOLOR 1
#define USE_TI_UITABGROUP 1
#define USE_TI_UIWINDOW 1
#define USE_TI_UITAB 1
#define USE_TI_UILABEL 1 
上の例は、TiStudioがプロジェクト生成時に自動生成されるapp.jsだけの状況でビルドした場合の例です。対応するObjective-Cのソースで、これらのマクロで展開されるコードを切り替える仕組みになっています。よく整理されているようです。
#define TI_VERSION 1.7.5
から
#define USE_TI_API 1
までの行は、有無をいわさず生成されますが、それ以降の部分は、JavaScriptによって何が生成されるか決まってきます。


ビルドするアーキテクチャが違っているので、一概に比較できませんが、"Run As > iPhone Simulator" "Debug As > Debug Simulator" で作られる Debug-iphonesimulatorが 8M であるのに対して、"Deploy Distribute - App Store" で作られるRelease-iphoneosが 5.5M 程度になっています。(もちろん、オーガナイザーでipaに変換した後は、zip圧縮されるのでさらに小さくなります。概ね3.5M)。


Tiはdefines.h をつかって開発者の書いたJavaScriptソースファイルが使っているモジュールを特定して、C言語マクロ USE_TI_XXXXXXX を通じて、コードの削減を行っています。Tiの生成するXCodeプロジェクトはコードに関しては、呼ばれないコードは除外するオプションがついているので、使用する機能が少なければより小さなコードを生成することとなります。
そして、賢いことに、リソースに関しても、必要なものだけ含むようにしてくれているようです。シミュレータ用には、 facebook 用の画像ファイルが、必ず含まれてしまいますが、実機用に関しては、facebook関連のコードがなければ、含まれません。

Tiが賢いことをやってくれていても、まだ大きい、どうにかしたいと思うのが人情です。

Tiの生成するXCodeプロジェクトのビルド対象のアーキテクチャはARMv6+ARMv7となっていて、2つの種類のコードが含まれています。
アーキテクチャによって機種を分類すると
ARMv6:
    1st & 2nd Generation iPod Touch
    iPhone,
    iPhone 3G
ARMv7:
    iPhone 3GS
    iPhone 4
    iPhone 4S
    iPad
    iPad2
    3rd & 4th Generation iPod Touch
となりますが、Tiはそれぞれのアーキテクチャに対して最適なコードを別々に生成しているため、全体のアプリのサイズを大きくしています。そこで
  1. 対象をARMv6アーキテクチャにして、ARMv6,ARMv7で動くようにする(ただしARMv7での最適化がなされない)
  2. 対象をARMv7アーキテクチャに限る
のいずれかの選択をすると、1アーキテクチャになる分アプリサイズが小さくなります。
ビルド後にlipoなどのコマンドラインツールを使ってやる方法もありますが、よりお手軽にするには、XCodeのプロジェクト設定を変える方法があります(細かい手順は省略。実施にあたってはあらかじめオリジナルのバックアップをお忘れなく)。
実際試してみると、
ARMv6のみを選択の*.appサイズ
Debug-iphoneos 3.8M
Release-iphoneos 3.6M
ARMv7のみを選択の*.appサイズ
Debug-iphoneos 3.8M
Release-iphoneos 3.6M
という具合に、かなりサイズ削減できます(ともに同じくらいのサイズになります)。
この削減方法は、Mac OS のユニーバーサルバイナリにまつわるアプリサイズ削減方法と原理は同じです。
さらに、これ以上サイズを削減するには、Titaniumの中心 TiCore(libTiCore.a)に手を入れる必要がでてきそうですが、これは大事(ダイエットどころか、大手術)になりそうなので、今日はここまで...


無関係な小ネタ
PS
最後に、本当はAndroidのほうがアプリケーションサイズについて問題になるケースがあるので、こちらについても書きたかったのですが、V8ベースのv1.8リリースを間近にひかえて、状況が変わってしまう可能性があるので、こちらについてはまた後日ということで...



2 件のコメント:

  1. 実際試してみると、のところ、どっちかがARMv7ですね?
    数値ももしかして違いますか?

    返信削除
  2. ご指摘ありがとう。訂正しておきました。

    返信削除