Android・iOS対応のクロスプラットフォームライブラリ、Intel Multi-OS Engine(MOE)

libGDX的にも推奨していそうなIntel Multi-OS Engineについて。
https://github.com/libgdx/libgdx/wiki/Setting-up-your-Development-Environment-(Eclipse,-Intellij-IDEA,-NetBeans)


Intel Multi-OS Engineを使えばJava or Kotlinでクロスプラットフォームのアプリが作成可能とのこと。

前回のMobile Open JDK9の話に続き、調査してみようと思います。
[AndroidもiOSにも対応、Mobile OpenJDK 9について](http://qiita.com/yyYank/items/aca543e1d549508bd0bd)


## Intel Multi-OS Engineとは

Intel Multi-OS Engineはあの「インテル入ってる」でおなじみ？な
Intelが開発しているクロスプラットフォーム用のライブラリです。

OSSです（というのをIntelもアピールしています）。
[https://multi-os-engine.org/](https://multi-os-engine.org/)

GitHubにorgもあります。
[https://github.com/multi-os-engine](https://github.com/multi-os-engine)

略すと"moe"なので"萌え"とかそういうの言う人にはCore2Duo投げつけましょう。


## プラグインが提供されているIDE

Eclipse, IntelliJ IDEA, Android Studio。

おそらくIDEプラグインに過ぎないので、
Gradleビルドが出来るIDEであれば(IDEでなくても)利用可能だと思います。
Gradle推しっぽいですが、Mavenプラグインも準備しているようです。
[https://github.com/multi-os-engine/moe-plugin-maven](https://github.com/multi-os-engine/moe-plugin-maven)


## 開発環境の必要スペック

Mac

* macOS 10.11以上
* メモリ4 GB以上(8 GB以上オススメ)
* Apple Xcode 7.3以上
* Xcode Command Line Tools
* iOS 8 SDK以上
* Oracle JDK8以上
* Android Studio 2.1以上
* Android SDK API level 9以上


Win


* Windows 7 OS x64以上
* メモリ4 GB以上(8 GB以上オススメ)
* Oracle JDK8以上
* Android Studio 2.1以上
* Android SDK API level 9以上
* Windows用Apple iTunesアプリ
* iOSを試す場合はSSHでMac端末にアクセス


## 仕組み

Multi-OS EngineのランタイムはAndroidのランタイムであるARTがベースになっています。
ARTはiOSでもパフォーマンスを出すフィーチャーをいくつか持っています。

* AOT(Ahead-of-time)コンパイルによるパフォーマンス改善
* Androidで利用可能なライブラリ群の利用により、クロスプラットフォームアプリ開発を簡単に
* GCでメモリ管理をエンハンス可能



![https://doc.multi-os-engine.org/multi-os-engine/2_Introduction/Introduction.htmlより引用](https://doc.multi-os-engine.org/_images/intro2.png)

[https://doc.multi-os-engine.org/multi-os-engine/2_Introduction/Introduction.htmlより引用](https://doc.multi-os-engine.org/multi-os-engine/2_Introduction/Introduction.html)


ということで、Androidで書いたアプリがそのままiOS用のアプリケーションとしてMOEプラグインによってビルド可能です。
下図はAndroid Studioを例に出していますが前述の通り、IDEは問いません。Gradleプラグインが用意されていますので、GradleプロジェクトであればIDEは関係無いですからね。

![](https://doc.multi-os-engine.org/_images/intro1.png)
[https://doc.multi-os-engine.org/multi-os-engine/2_Introduction/Introduction.htmlより引用](https://doc.multi-os-engine.org/multi-os-engine/2_Introduction/Introduction.html)


## iOSのUIデザインはどうするか

UI部分は通常のiOS開発と同じようにXcodeなどでつくる必要があります。
ただし、libGDXなどクロスプラットフォーム対応のゲームエンジン上であればそこまでUI差分はないですが。各プラットフォームのデザインガイドを意識する必要のあるアプリ開発であれば、UI作成はプラットフォームごとに作成が必要そうですね。

Nat4JというライブラリでネイティブとJavaのブリッジをしてUIをバインドするみたいです。
[Nat/J: Interoperability with Native Code](https://doc.multi-os-engine.org/multi-os-engine/6_natj/natj_interoperability/NatJ_Interoperability.html)


## 試す前の事前準備

事前準備として、僕の場合はIntelliJ IDEAを利用しているため、moeのIDEプラグインを導入しました。

Prefrences>Plugin>Browse Repositories...>「multi-os」と検索で出てきます。
![multi-os.png](https://qiita-image-store.s3.amazonaws.com/0/122413/37325f1b-f33b-7c23-f001-af60578f1471.png)




## Getting Started(Java)


サンプルコードがGitHub上にアップロードされています。


* Java
[https://github.com/multi-os-engine/moe-samples-java](https://github.com/multi-os-engine/moe-samples-java)


サンプルコードを落としてきます。
```
git clone https://github.com/multi-os-engine/moe-samples-java.git
```


### 中身を探る

中身を見てみます

```
$ ls
Calculator		LocalizedString		SimpleChart
CurrencyConverter	MuseumMap		SpeakHere
FastJNI			NOTICE.txt		Taxi
HelloMaven		Planets			TheElements
InAppPurchase		README.md		TicTacToe
```

いくつかサンプルアプリが入っているんですね。とういか、README.mdを見ればそのあたり書いてあります。
とりあえず、今回はCalculatorを動かしてみます。


Calculatorアプリの構成はこんな感じです。

```
yank-no-MacBook-Pro:Calculator yy_yank$ tree
.
├── android
│   ├── build.gradle
│   └── src
│       └── main
│           ├── AndroidManifest.xml
│           ├── java
│           │   └── org
│           │       └── moe
│           │           └── samples
│           │               └── calculator
│           │                   └── android
│           │                       └── CalcActivity.java
│           └── res
│               ├── layout
│               │   └── calc_activity.xml
│               ├── mipmap-hdpi
│               │   └── ic_launcher.png
│               ├── mipmap-ldpi
│               │   └── ic_launcher.png
│               ├── mipmap-mdpi
│               │   └── ic_launcher.png
│               ├── mipmap-xhdpi
│               │   └── ic_launcher.png
│               ├── mipmap-xxhdpi
│               │   └── ic_launcher.png
│               ├── values
│               │   ├── colors.xml
│               │   ├── strings.xml
│               │   └── styles.xml
│               └── values-v21
│                   └── styles.xml
├── build.gradle
├── common
│   ├── build.gradle
│   └── src
│       └── main
│           └── java
│               └── org
│                   └── moe
│                       └── samples
│                           └── calculator
│                               └── common
│                                   ├── CalcOperations.java
│                                   ├── CalcOpsTypes.java
│                                   └── CalculatorAdapter.java
├── gradle
│   └── wrapper
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── ios
│   ├── build.gradle
│   ├── src
│   │   └── main
│   │       └── java
│   │           └── org
│   │               └── moe
│   │                   └── samples
│   │                       └── calculator
│   │                           └── ios
│   │                               ├── Main.java
│   │                               └── ui
│   │                                   └── AppViewController.java
│   └── xcode
│       ├── ios
│       │   ├── Assets.xcassets
│       │   │   ├── AppIcon.appiconset
│       │   │   │   ├── Contents.json
│       │   │   │   ├── Icon-60@2x-1.png
│       │   │   │   ├── Icon-60@2x-2.png
│       │   │   │   ├── Icon-60@2x.png
│       │   │   │   ├── Icon-76-1.png
│       │   │   │   ├── Icon-76-10.png
│       │   │   │   ├── Icon-76-11.png
│       │   │   │   ├── Icon-76-12.png
│       │   │   │   ├── Icon-76-2.png
│       │   │   │   ├── Icon-76-3.png
│       │   │   │   ├── Icon-76-4.png
│       │   │   │   ├── Icon-76-5.png
│       │   │   │   ├── Icon-76-6.png
│       │   │   │   ├── Icon-76-7.png
│       │   │   │   ├── Icon-76-8.png
│       │   │   │   ├── Icon-76-9.png
│       │   │   │   ├── Icon-76.png
│       │   │   │   ├── Icon-76@2x-1.png
│       │   │   │   ├── Icon-76@2x-2.png
│       │   │   │   ├── Icon-76@2x.png
│       │   │   │   └── Icon-83.5@2x.png
│       │   │   ├── Contents.json
│       │   │   └── MOELogo.imageset
│       │   │       ├── Contents.json
│       │   │       └── moe-logo-200x200.png
│       │   ├── Base.lproj
│       │   │   ├── LaunchScreen.storyboard
│       │   │   └── Main.storyboard
│       │   ├── Info.plist
│       │   └── main.cpp
│       ├── ios-Test
│       │   ├── Info.plist
│       │   └── main.cpp
│       └── ios.xcodeproj
│           └── project.pbxproj
└── settings.gradle

47 directories, 57 files
```

androidディレクトリ=androidプラットフォーム固有、iosディレクトリ=iosプラットフォーム固有、common=共通部分でしょうね。
それぞれがGradleのmoduleとして扱われています。


Androidの方はCalcActivity.java、iOSの方はAppViewController.javaというクラスが用意されています。
これがそれぞれのUI部分です。Android側に関しては特筆することはありません。
フツーにAndroidで開発している時同じです。iOSの方は色々特徴があります。

クラスヘッダだけみても結構特徴があります

```java:AppViewController
@org.moe.natj.general.ann.Runtime(ObjCRuntime.class)
@ObjCClassName("AppViewController")
@RegisterOnStartup
public class AppViewController extends UIViewController {
```

* ObjCRuntimeアノテーションでランタイムをObjective-C指定している
* ObjCClassNameアノテーションでObjective-Cのクラス名を指定している
* RegisterOnStartupアノテーションでiOSランタイムへの登録タイミングを指定している
* UIViewController.javaを継承している

UIViewControllerはiOSが提供するAPIで、それをwrapしたものをMulti-OS Engine側で用意していたものです。
UIViewControllerの詳細はAppleのAPIリファレンス参照のこと。
[UIViewController - API Reference](https://developer.apple.com/reference/uikit/uiviewcontroller)

ソースも軽く見てみて欲しいのですが、UIButton、UIColor、UILabelなどもMulti-OS Engine側で用意しているため普通に利用できています。
viewDidLoadメソッドにて描画処理を行っています。イベントハンドリングなどもiOS開発に携わっている方なら違和感なく表現されているのではないでしょうか。


肝心のcommonの部分はAndroid、iOSどちらのプラットフォームでも利用されるロジックが入っています。
今回で言えばCalculatorアプリのコアである四則演算のロジックですね。


### Androidで動かしてみる

とりあえず、Androidの実機を持っているので./gradlew android:installDebugします。

```
23:52:08: Executing external task 'installDebug'...
Configuration on demand is an incubating feature.
Incremental java compilation is an incubating feature.
:android:preBuild UP-TO-DATE
:android:preDebugBuild UP-TO-DATE
(中略)
:android:installDebug
Installing APK 'android-debug.apk' on 'SHV35 - 6.0.1' for android:debug
Installed on 1 device.

BUILD SUCCESSFUL

Total time: 41.502 secs
23:52:52: External task execution finished 'installDebug'.

```

無事アプリがインストールされました。


Calculatorという名前の通り、電卓ですね。

![Screenshot_20170207-235347.png](https://qiita-image-store.s3.amazonaws.com/0/122413/5cf08fc9-a270-6dd6-046a-03c7d4467278.png)



### iOSでも動かしてみる


僕はiOSの実機は持っていませんが、MacBook ProなのでSimulatorで動かすこととします。
まず、Simulatorを起動しておきます。なんでも良いです。


./gradlew ios:moeLaunch -Pmoe.launcher.simulators=XXXXX(SimulatorのID)とやってやります。

しばらくすると起動します。Simulator遅いけど。

XXXXXの部分にはSimulator>Hardware>Manage Deviceで見ることの出来るSimulatorのidentifierです。
これにより、Simulatorと紐付けることができます。

![simulator-identifier.png](https://qiita-image-store.s3.amazonaws.com/0/122413/4e5e11f6-02e3-82f5-68af-d09207c05e55.png)


はい、動きました！


![ios-moelaunch.png](https://qiita-image-store.s3.amazonaws.com/0/122413/c0c9dfd6-8758-8ef9-f91a-c999a430cafd.png)



ipaファイルを作りたいとかいう場合は開発チームとかprovisioning profileの設定とか色々ありますよね。
そういう場合はios/build.gradleに関連の設定を書いてやる必要があります。


```
moe {
    signing {
        // String, ID of the development team.
        developmentTeam

        // String, path to the provisioning profile or UUID.
        provisioningProfile

        // String, name of the provisioning profile (new in Xcode 8).
        provisioningProfileSpecifier

        // String, name of the signing identity
        signingIdentity
    }
}
```


詳しくはこちらに書いてますので、ご参照下さい。

[https://github.com/multi-os-engine/moe-plugin-gradle/blob/master/README.md](https://github.com/multi-os-engine/moe-plugin-gradle/blob/master/README.md)

## Getting Started(Kotlin)


こちらもサンプルコードがGitHub上にアップロードされています。

* Kotlin
[https://github.com/multi-os-engine/moe-samples-kotlin](https://github.com/multi-os-engine/moe-samples-kotlin)


大体すでに説明してしまったのでネタ切れ感がありますが、サンプルアプリがちょっと違います。

```
$ ls
KotlinCalculator	KotlinRssReader		README.md
KotlinMuseumMap		NOTICE.txt
```

これも例のごとくREADME.mdに詳細が書いてあるのでご参照下さい。
KotlinCalculatorの中を見てみましたが、コードはjavaのサンプルと同じ内容でした。Gradleの構成も同じ。android、ios、commonとなっています。
ただ、Kotlinでガッとかかれています。おそらくIDEのコンバートを使ったんではないかと思われます(IntelliJ IDEAではJavaからKotlinにIDEが変換してくれます)。


## コミュニティもちゃんとある

discussion出来る場もちゃんと用意されています。

[Multi-OS Engine Forum](https://discuss.multi-os-engine.org/)
2017/2現在メジャーバージョーンがすでに出ており、RoboVMからの乗り換えも多い感じで、すでにユーザーが多いです。
議論も結構進んでいてハマりどころは調べればなんとかなりそう。

ドキュメントもきっちりしている印象です。
[https://doc.multi-os-engine.org](https://doc.multi-os-engine.org)

## まとめ

* Intel Multi-OS Engineは結構よく出来ている
* ARTベースなのでAndroidは普通に今まで通り
* iOSはJavaからnativeに変換してiOSランタイムで動くようにしている
* Android/iOSプラットフォームのアプリがJava or Kotlinのコードで作れる
* 現在メジャーバージョンでコミュニティも出来てきている
* ドキュメントも割りとある
* 各IDE(IntelliJ IDEA、Eclipse、Android Studio)のサポートもある
* ビルドツールのプラグインもある(Gradle、Maven)

結構良い感じなんじゃないかなあと思います。


## 参考URL

* [http://nosix.hatenablog.com/entry/2016/11/01/233212](http://nosix.hatenablog.com/entry/2016/11/01/233212)
* [https://www.infoq.com/jp/news/2015/08/multi-os-engine-ios-android](https://www.infoq.com/jp/news/2015/08/multi-os-engine-ios-android)
* [http://www.isus.jp/smartphones/working-with-persistent-storage-part-1/](http://www.isus.jp/smartphones/working-with-persistent-storage-part-1/)
* [https://doc.multi-os-engine.org/multi-os-engine/2_Introduction/Introduction.html](https://doc.multi-os-engine.org/multi-os-engine/2_Introduction/Introduction.html)
* [https://www.xda-developers.com/intels-multi-os-engine-lets-you-make-android-or-ios-apps-using-java/](https://www.xda-developers.com/intels-multi-os-engine-lets-you-make-android-or-ios-apps-using-java/)
* [https://multi-os-engine.org/start/](https://multi-os-engine.org/start/)
* [https://github.com/multi-os-engine/moe-plugin-gradle/blob/master/README.md](https://github.com/multi-os-engine/moe-plugin-gradle/blob/master/README.md)



## 追記


MOEは2017/02現在、バージョンは1.xですが、
バージョン2.xではLLVMのビットコードサポートが入るらしいです。
[@snakemanさん](https://twitter.com/snakeman)情報ありがとうございます！

その関連で調べていると
フォーラムでDoes multi-os-engine have a roadmap?というやりとりを見つけました。
[Does multi-os-engine have a roadmap?](https://discuss.multi-os-engine.org/t/does-multi-os-engine-have-a-roadmap/79/7)

ここから分かることとして

* RoboVMとパフォーマンス的な違いは無い(Intelのチームのbenchmarkによると)
* MOE 2.xではLLVMベースのバックエンドがMOEのARTに搭載されbitcodeをサポートする予定
* MOE 1.xのランタイムライブラリはApache Harmony(Android M)
* MOE 2.xのランタイムライブラリはAndroid N
* Androidのライブラリを使っているのはiOSとAndroidのプラットフォームでMOEのコードを少なくするため


ということです。Roadmapもありました。2.xは今年にはリリースされるようなのでこちらも楽しみですね。

[MOE Roadmap 2016 - 2017 Winter](https://multi-os-engine.org/blog/2016-12-05-moe-roadmap/)