#概要
これまでxcodeとの連携を手作業で行っていたのですが、これを自動化しました。
プロジェクトのテンプレートはこちらです。
https://github.com/chototsu/mikumikustudio-gdx
今回追加したのはxcodebuildというタスクです。
このタスクを実行すると、xcode_iosというディレクトリにあるxcodeプロジェクトをコンパイルし、自動的にUniversal Static Libraryを作成します。また、xibファイルを解析し、そのJavaバインディングコードをios/generatedディレクトリに自動生成します。
#ライブラリ生成
今回作成したのはこのようなプロジェクトです。
このプロジェクトの「lib」というターゲットがライブラリ用のターゲットです。ライブラリに含めたいクラスはこのターゲットに入れるようにして下さい。
尚、UIViewControllerのクラスはこのターゲットに含めないで下さい。UIViewControllerのクラスはRoboVM側で生成しますので、こちらに同名のクラスがあると名前が衝突してしまいます。
#画面生成
画面はUIViewControllerのサブクラスとして作ります。
この時、「With XIB for user interface」をチェックするようにして下さい。
繰り返しますが、ここで作ったクラスはlibターゲットに含めないで下さい。名前が重なって実行時にエラーが発生します。
クラスを作ったら普通に画面を作成し、OutletやActionを作成します。
作成出来たらsbtからxcodebuildを実行します。
$ sbt
> ios/xcodebuild
するとxibが自動的にnibにコンパイルされ、このようなクラスが生成されます。
package view;
import org.robovm.cocoatouch.uikit.*;
import org.robovm.objc.Selector;
import org.robovm.objc.annotation.BindSelector;
import org.robovm.objc.annotation.CustomClass;
import org.robovm.objc.annotation.TypeEncoding;
import org.robovm.rt.bro.annotation.Callback;
@CustomClass("TestAppViewController")
public abstract class TestAppViewController extends UIViewController {
public TestAppViewController() {
super("TestAppViewController", null);
} protected UILabel label1;
@SuppressWarnings("unused")
@Callback
@BindSelector("setLabel1:")
@TypeEncoding("v@:@")
private static void setLabel1(TestAppViewController self, Selector selector, UILabel label1) {
self.label1=label1;
}
@SuppressWarnings("unused")
@Callback
@BindSelector("getLabel1")
@TypeEncoding("v@:@")
private static UILabel getLabel1(TestAppViewController self, Selector selector) {
return self.label1;
}
@SuppressWarnings("unused")
@Callback
@BindSelector("buttonAction:")
@TypeEncoding("v@:@")
private static void buttonAction(TestAppViewController self, Selector selector, UIButton sender) {
self.buttonAction(sender);
}
abstract protected void buttonAction(UIButton sender);
@SuppressWarnings("unused")
@Callback
@BindSelector("button2Action:")
@TypeEncoding("v@:@")
private static void button2Action(TestAppViewController self, Selector selector, UIButton sender) {
self.button2Action(sender);
}
abstract protected void button2Action(UIButton sender);
}
このクラスはabstractクラスですのでそのままでは使えません。
使うためにはこのクラスを継承したクラスを作成します。
これはScalaの例です。
class TestAppViewControllerImpl extends TestAppViewController {
protected override def buttonAction(sender: UIButton): Unit = {
label1.setText("Hello!!")
}
protected override def button2Action(sender: UIButton): Unit = {
label1.setText("World!!")
}
}
この画面を表示するためにはdidFinishLaunchingでaddSubviewしてやります。
override def didFinishLaunching(application: UIApplication, launchOptions: NSDictionary[_ <: NSObject, _ <: NSObject]): Boolean = {
super.didFinishLaunching(application, launchOptions)
testAppViewController = new TestAppViewControllerImpl
app.getUIViewController.getView.addSubview(testAppViewController.getView)
true
}
実行すると、作成した画面がOpenGLの画面の上に表示される事が確認出来ます。
作成したボタンを押すとlabelの内容が変化する事が分かります。
##制限
現在はすべてのUIButtonのTouch Up Insideアクションにしか対応していません。
その他のアクションはサブクラス側に手作業で追加して下さい。
#TODO
*Objective Cのバインディグを自動生成したい(これはかなり大変そう・・・)。
*xibの全action, outletに対応する。
*maven centralリポジトリに作ったバインディグを登録する。
#終わりに
開発環境が整ってきて、だいぶ作業が捗るようになりました。
Javaのエコシステムを利用してiOSの開発が出来てしまうのは凄い事だと思います。
ちなみに私が公開したアプリ Tiny AR liteは
https://itunes.apple.com/jp/app/tiny-ar-lite/id806062401?mt=8
RoboVMの作者のNiklas Therning氏に世界初のScalaで書かれたiOSアプリとの公式認定を受けております(笑)
当初安定性の心配をしていたのですがユーザー様からの評価では概ね安定しているようで、ほっとしています。
RoboVMは十分安定していると言えるでしょう。