Scala/JavaでiOSアプリを作るtipsその2

More than 5 years have passed since last update.


概要

これまでxcodeとの連携を手作業で行っていたのですが、これを自動化しました。

プロジェクトのテンプレートはこちらです。

https://github.com/chototsu/mikumikustudio-gdx

今回追加したのはxcodebuildというタスクです。

このタスクを実行すると、xcode_iosというディレクトリにあるxcodeプロジェクトをコンパイルし、自動的にUniversal Static Libraryを作成します。また、xibファイルを解析し、そのJavaバインディングコードをios/generatedディレクトリに自動生成します。


ライブラリ生成

今回作成したのはこのようなプロジェクトです。

スクリーンショット 2014-02-23 21.32.19.png

このプロジェクトの「lib」というターゲットがライブラリ用のターゲットです。ライブラリに含めたいクラスはこのターゲットに入れるようにして下さい。

尚、UIViewControllerのクラスはこのターゲットに含めないで下さい。UIViewControllerのクラスはRoboVM側で生成しますので、こちらに同名のクラスがあると名前が衝突してしまいます。


画面生成

画面はUIViewControllerのサブクラスとして作ります。

スクリーンショット 2014-02-23 21.37.35.png

この時、「With XIB for user interface」をチェックするようにして下さい。

繰り返しますが、ここで作ったクラスはlibターゲットに含めないで下さい。名前が重なって実行時にエラーが発生します。

クラスを作ったら普通に画面を作成し、OutletやActionを作成します。

スクリーンショット 2014-02-23 21.39.19.png

作成出来たら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の内容が変化する事が分かります。

qiita.png


制限

現在はすべての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は十分安定していると言えるでしょう。