j2objcをXcodeに統合する方法
こんにちは。フロントエンドエンジニアのらくさんです。
もうだいぶ時間が経ってしまいましたが、以前JavaのソースコードからJavaScript / Objective-Cのソースコードを生成するという記事を書きまして、その中でj2objcを使用しました。
今回はこのj2obcをXcodeに統合してみます。Xcodeへの統合方法は http://code.google.com/p/j2objc/wiki/XcodeBuildRule にも書かれていますが、この記事では多少アレンジしてあります。 j2objcのバージョンはこの記事の時点で0.8.2です。前回の記事では0.5.6でしたが、その後も活発に開発が続いていて、以前は時々変換に失敗することがあったのですが着実に改善されています。
目次
必要なもの
- Mac
- Xcode
- j2objc
j2objcの入手
ここから j2objc-0.8.2.zip をダウンロードし、適当な場所に展開してください。この記事では /opt に展開しています。
1 |
[sourcecode lang="text"] $ cd /opt $ unzip ~/Downloads/j2objc-0.8.2.zip $ cd j2objc-0.8.2 $ ls cycle_finder include j2objc j2objcc lib man $ pwd /opt/j2objc-0.8.2 [/sourcecode] |
あとでXcdoeにj2objcのパス(上の例では /opt/j2objc-0.8.2)を設定しますので、他の場所に展開した場合は以降の該当箇所を読み替えてください。 j2objcをソースコードからビルドする場合は、前回の記事を参考にしてください。
Xcodeプロジェクトの作成・設定
プロジェクトの作成
Xcodeで通常通りにプロジェクトを作成します。j2objcはデフォルトではARCを使用しませんが、ここではARCを使ってみます。プロジェクト作成時に「Use Automatic Reference Counting」をチェックしてください。
Javaのソースコード
次のJavaのソースコードを使用します。
1 |
[sourcecode lang="text"] package com.sonicmoov.lab; public class HelloJ2ObjC { public void sayHello() { System.out.println("Hello"); } public int sum(int a, int b) { return a + b; } @Override protected void finalize() throws Throwable { System.out.println("finalize"); super.finalize(); } } [/sourcecode] |
作成したプロジェクトディレクトリのすぐ下に java というサブディレクトリを作ってjavaのソースツリーとします。
1 2 3 4 5 6 7 8 9 |
[sourcecode lang="text"] HelloJ2ObjC ├── HelloJ2ObjC ├── HelloJ2ObjC.xcodeproj └── java └── com └── sonicmoov └── lab └── HelloJ2ObjC.java [/sourcecode] |
プロジェクトの設定 (Build Settings)
ユーザー定義設定を二つ追加
J2OBJC_DIR: /opt/j2objc-0.8.2 JAVA_SRC_DIR: java J2OBJC_DIRはj2objcのパス、JAVA_SRC_DIR はJavaのソースツリーへのパスです。
Header Search Paths にパスを二つを追加
${J2OBJC_DIR}/include ${DERIVED_FILES_DIR} ユーザー定義設定で追加した J2OBJC_DIR を使っています。${J2OBJC_DIR}/include には、j2objcのJREエミュレーションライブラリのヘッダファイルがあります。 j2objcで変換されたファイルは DERIVED_FILES_DIR が指す場所に書き出されるので、ここもヘッダのサーチパスに追加しておく必要があります。
Library Search Paths に次のパスを追加
${J2OBJC_DIR}/lib ${J2OBJC_DIR}/lib にはj2objcのJREエミュレーションライブラリ(libjre_emul.a)があります。
Other Linker Flags に次の値を追加
-ljre_emul -ObjC -force_load ${J2OBJC_DIR}/lib/libjre_emul.a (少し前のj2objcでは -force_load ${J2OBJC_DIR}/lib/libjre_emul.a が無いとリンクに失敗しましたが、0.8.2では無くても大丈夫でした)
プロジェクトの設定 (Build Rules)
Build Rulesにルールをひとつ追加
Processを「Java source files」、Usingを「Custom script:」にして、次のコマンドを入力します。
1 |
[sourcecode lang="text"] ${J2OBJC_DIR}/j2objc -encoding UTF-8 \ -d ${DERIVED_FILES_DIR} -sourcepath ${JAVA_SRC_DIR} \ --no-package-directories -use-arc ${INPUT_FILE_PATH} [/sourcecode] |
-d オプションと -sourcepath オプションは、javac の同名のオプションと同様の意味を持ちます。
ソースコードに日本語の文字列やコメントが含まれている場合、-encoding オプションを指定する必要があります。ARCを使用する場合は -use-arc オプションが必要です。 また、Output Filesに「${DERIVED_FILES_DIR}/${INPUT_FILE_BASE}.h」と「${DERIVED_FILES_DIR}/${INPUT_FILE_BASE}.m」を追加します。
Objective-Cのソースコード
j2objcで変換したコードを利用するObjective-Cのコードが必要です。
1 |
[sourcecode lang="text"] #import "ViewController.h" #import "HelloJ2ObjC.h" @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; ComSonicmoovLabHelloJ2ObjC *helloJ2ObjC = [[ComSonicmoovLabHelloJ2ObjC alloc] init]; [helloJ2ObjC sayHello]; int sum = [helloJ2ObjC sumWithInt:7 withInt:2]; NSLog(@"%d", sum); helloJ2ObjC = NULL; NSLog(@"end"); } @end [/sourcecode] |
ビルドと実行
ここまでの準備が整ったら、あとは通常のXcodeプロジェクトと同じようにビルドして実行するだけです。実行すると、コンソールには次のように出力されます。
1 |
[sourcecode lang="text"] Hello 2013-07-12 18:35:25.464 HelloJ2ObjC[6914:907] 9 finalize 2013-07-12 18:35:25.468 HelloJ2ObjC[6914:907] end [/sourcecode] |
sayHelloメソッド内で System.out.println(“Hello”) によりHelloが出力されています。 sum(int a, int b)メソッド(Objective-C に変換されたメソッド名は sumWithInt:withInt:)から足し算の結果が正しく返されています。ARCを使用しているので helloJ2ObjC にNULLを代入したときにfinalizeメソッドが呼ばれているのがわかります(endよりも前にfinalizeが出力されています)。
最後に
j2objcをXcodeに統合すると、Xcodeプロジェクトを通常どおりビルドするだけで済むので便利です。j2objcではUIを作ることが出来ませんが、UIとは独立した処理が多い場合には有用なツールとなるかもしれません。
ところで、先日弊社がリリースした花火大会シミュレーター2013夏というアプリがあるのですが、このアプリの一部にj2objcを使っています。このアプリ内で花火のFlashアニメーションを再生している箇所がありまして、Javaで書いたFlash Lite再生エンジンをj2objcで変換して使用しています。Flash再生のような複雑な処理でもj2objcで変換したコードはきちんと動作しますので、現時点でも十分実用になると思います。