2013/07/31

Titanium Mobile Android ダイエット

先日Twitter上で、Android 用の Ti アプリのサイズが大きいのでなんとかしたいって話があって、@uk1124
[Titanium]APKのサイズを小さくする方法で結果をレポートしてくださった。
今回はこの補足です。

まず、@isis331 のいうandroid/builder.pyを修正する方法では、ディストリビューション用のapkでは何の効果もありません。
なぜかというと、Ti SDK 3.1.1 GAで生成されるディストリビューションのパッケージには、デフォルトでは、ARMv5(armeabi)とARMv7(armeabi-v7a)のコードしか含まれないからです。
では、x86を含めるにはどうするかというと@infosiaさんの指摘されたtiapp.xml の<abi>で、allを指定する必要があります。これで、ARM用2つに加えてx86も含まれることになります。
反対にarmeabiだけを指定すれば最小サイズのものが出来上がります。

さて、android/builder.pyを修正する方法が有効なのは、ディトリビューション用ではなく手元でテストする場合に生成されるapkに対してです。"Install to Android Device"等のコマンドで、ビルドされたときには、全てのabiが含まれた状態でビルドされます。この場合には、android/builder.pyを修正して、必要なabiだけ配列に入れておけば、最小限のサイズのapkが生成されます(x86を省けば、8.7Mから6.2M程度になります)。
デバイスへの転送速度が気になる向きには、有効な手段かも知れません。

(注)
apkの中身は、zipとして解凍してlibs以下のフォルダをみれば、確認できます。



2013/07/15

RoboVM first step

RoboVM は、Java で書かれたコードを iOS, Mac OS X, Linux 上で実行するための環境を提供してくれます。VM という名前になっていますが、新手の Java Virtual Machine ではありません。Java バイトコードをネイティブコードにトランスレートするコンパイラがその実体です。実行時には、ネイティブコードだけのアプリが実行されることになります。
Java 由来の API が簡単に使えたり、Objective-C へのブリッジもあるので、Javaコードから iOS のフレームワークを呼び出すことも可能です。
現在リリース版のバージョンが 0.0.2 ということで、出来立ての状態ですが、仕組みがおもしろいのと、Android アプリとのコードの共通化への取り組みの一環として、非常に興味深い環境です。

導入方法は
RoboVMのIntroduction

Hacking on RoboVM / Building from source
にありますが、若干記述が古くなっています。
Mac OS X 10.7 での、導入から、Hello, world までのはまりどころを以下にメモしておきます。

RoboVM が使うコンパイラ環境の導入


Java SE JDK 7
Xcode 4.6.2 + command line tools
LLVM 3.2
が必要です。
Java SE JDK 7 については Oracle のサイトからインストーラをダウンロードして導入しますが、それだけだと、OS X 10.7 に付属の Apple 提供の JDK 6 を指したままになっているので、適宜 ~/.bash_profileに

export JAVA_HOME=export JAVA_HOME=$(/usr/libexec/java_home)

などとして、JDK 7 を指すように変更が必要です。

LLVM については、homebrew などでインストールされたものだと、RoboVM がコンパイルするときなぞのエラーとなります。
RoboVM は、
clang+llvm-3.2-x86_64-apple-darwin11.tar.gz
を仮定しています(これ以外だとうまく動作しないようです)ので、素直に RoboVM の Introduction の指示に従って、導入するのが良いでしょう。RoboVM が /opt/ 以下の llvm を見に行くので、シンボリックリンクとして
/opt/llvm
を作成しておかなければなりません。このディレクトリは homebrew の管理とは無関係なので、RoboVM 専用だと思っておけば、問題は生じないでしょう(homebrew の場合、/usr/local/ 内に /usr/local/Cellar/ へのシンボリックリンクを作って管理しています)。
Xcode についての注意点として、複数の Xcode を導入して Xcode.app のアプリ名をXcode462.app などとリネームしている場合です。この場合、iPhone シミュレータが起動できないなど、不具合を生じるので、Xcode.app という名前のままである必要があります。

tar.gzからの導入

Download the latest RoboVM release から tar.gz をダウンロードして、/opt/ 以下の展開すれば良いのですが、本家の説明では、バージョン番号毎に管理して /opt/robovm としてシンボリックリンクを作ることになっています。しかし、これだとうまく働きません。現行バージョン(0.0.2)では実行時にシンボリックリンクの解決ができていないようなので、 /opt/robovm 以下に bin, lib, license の各ディレクトリの実体が来るように展開します。

IDEの利用/Eclipse プラグインの導入

RoboVM での開発には Eclipse が使えて便利です。
http://download.robovm.org/eclipse/
から導入できますので、Help >Install New Software から導入します。

ソースからの導入

より本格的には、ソースから導入していろいろ実験的なことをするのもいいでしょう。

Git
CMake 2.8.8
Maven 3
が必要です。
本家の説明では、
JDK 6 or newer
が必要となっていますが、JDK 6 の場合は、途中でコンパイラーがパースエラーを起こしていまします。JDK 7 を使うのがいいでしょう。
ソースは
robovm/robovm
から入手できます。
working copy のディレクトリから
vm/build.sh

でライブラリが生成できます。
mvn clean install

でインストール用のコンポーネントが生成できますが、pom.xml が JDK 6 用になっています。先に述べたようにパースエラーとなりますので、
      <plugin>
        <groupid>org.apache.maven.plugins</groupid>
        <artifactid>maven-compiler-plugin</artifactid>
        <version>2.3.2</version>
        <configuration>
          <source></source>1.7
          <target>1.7</target>
          <debug>true</debug>
          <optimize>true</optimize>
          <showdeprecations>true</showdeprecations>
          <encoding>UTF-8</encoding>
        </configuration>
      </plugin>

の "1.6"の箇所を"1.7"と修正の上実行します。
dist/target/ 以下に
robovm-0.0.3-SNAPSHOT.tar.gz
ができますので、これを”tar.gzからの導入”の手順で導入します。

RoboVM 本体と Eclipse のプラグインのバージョンが一致している必要があるようなので、あわせて、プラグインもビルドして導入する必要があります。
robovm/robovm-eclipseからソースを入手し、
mvn clean install
でビルドできます。

Hello World

Eclipse の File > Project ... から RoboVM > RoboVM Cocoa Touch Project を選択します。


プロジェクト名を"HelloWorld"などとします。

src が空のプロジェクトが作成されますので、メインクラスを作成します。メインクラスの名前はプロジェクト名と同じものでなければなりません(パッケージはdefault packageを使用します)。


メインクラスのスーパークラスを

org.robovm.cocoatouch.uikit.UIApplicationDelegate.Adapter
とするのが RoboVM アプリのお作法です。ちょうど、Objective-C での開発で UIApplicationDelegate の サブクラスを作成しなければならないことに対応しています。

HolloWorld.javaの中身はたとえば以下のようにします。

import org.robovm.cocoatouch.coregraphics.*;
import org.robovm.cocoatouch.foundation.*;
import org.robovm.cocoatouch.uikit.*;

import org.robovm.cocoatouch.uikit.UIApplicationDelegate.Adapter;


public class HelloWorld extends Adapter {

    private UIWindow window = null;
    private int clickCount = 0;

    @Override
    public boolean didFinishLaunching(UIApplication application,
            NSDictionary launchOptions) {

        final UILabel label = new UILabel();
        label.setFrame(new CGRect(70.0f, 121.0f, 191.0f, 37.0f));
        label.setText("Hello World!");
        label.setBackgroundColor(UIColor.clearColor());
        label.setOpaque(true);


        window = new UIWindow(UIScreen.getMainScreen().getBounds());
        window.setBackgroundColor(UIColor.lightGrayColor());
        window.addSubview(label);
        window.makeKeyAndVisible();

        return true;
    }

    public static void main(String[] args) {
        NSAutoreleasePool pool = new NSAutoreleasePool();
        UIApplication.main(args, null, HelloWorld.class);
        pool.drain();
    }
}

実行するには、プロジェクトのサブメニューから Run > から実行環境を選びます。
初回は、ビルドなどに時間がかかるようですが、2回目以降は若干時間がかかるものの耐えられないほどではありません。
iOS Simulator App (iPhone)での結果は以下のようになります。



さて、環境が整ったので、暇を見て本格的なアプリを作ってみようと思います。