はじめまして。フロントエンドエンジニアのらくさんです。

弊社は、Flash Lite 1.1のSWFをスマートフォンで再生できるようにする、JswfPlayerというサービスを提供しています。私はそのプレーヤー開発を行っています。

JswfPlayerはWebブラウザ上で動作するため、ネイティブアプリで使用するにはWebView内で動かすことになりますが、せっかくネイティブアプリにするならJswfPlayerもJavaやObjective-Cでコードを書きOpenGLで描画を行い高速に動作させたくなります。

しかし、JavaScript/Java/Objective-Cそれぞれにフルスクラッチで開発するのは大変です。そこで、コードを出来るだけ共有する方法を模索しており、最近GWT-Exporterとj2objcを試してみたので使用方法をまとめてみました。(ちなみに、JswfPlayerのネイティブ版を開発する計画は今のところありません…)

GWT-Exporterとは

GWTはご存知の方も多いと思いますが、Google Web Toolkitの略称で「Javaを使ってウェブ用Ajaxアプリケーションを開発できるオープンソースのJavaソフトウェア開発フレームワーク」(Wikipediaより) です。Javaで書いたソースコードのうち、クライアント側で動作するものについてはJavaScriptに変換されて実行されます。

GWT-Exporterは、GWTでJavaScriptに変換されたコードを手書きのJavaScriptから利用できるようにするためのGWTモジュールです。今回はこのGWT-Exporterを使ってJavaからJavaScriptに変換することだけが目的なので、通常のGWTを用いた開発については触れません。

■GWT-Exporterのプロジェクトサイト
http://code.google.com/p/gwt-exporter/

j2objcとは

j2objcは、JavaのソースコードをObjective-Cに変換するツールで、2012年9月にGoogleからリリースされたばかりのものです。まだ開発途上であり頻繁に更新されているようですが、Google内のいくつかのプロジェクトでは使用されているようです。

続きを読む

■j2objcのプロジェクトサイト
http://code.google.com/p/j2objc/

GWT-Exporterの使い方

GWTのインストール

GWTの開発環境はEclipseのプラグインとして提供されているので、Eclipseが必要です。この記事ではEclipse3.7を使用しています。

GWTのインストール方法は割愛します。
私は次のページを参考にしました。

Eclipse を用いた GWT 開発環境の構築方法 – Google Web Toolkit (GWT) 入門

GWTプロジェクトの作成

Fileメニューから「New」→「Other…」を選び、Googleフォルダ内の「Web Application Project」を選択します。
GWTプロジェクトの作成

プロジェクト名とパッケージ名を入力し、「Use Google App Engine」と「Generate project sample」は不要なのでチェックを外します。Finishボタンを押すとGWTプロジェクトが作成されます。
プロジェクト名とパッケージ名を入力

GWT-Exporterのダウンロードとビルドパスの設定

http://code.google.com/p/gwt-exporter/downloads/list
ここから gwtexporter-2.4.0.jar をダウンロードします。

ダウンロードした gwtexporter-2.4.0.jar をプロジェクトに追加し、ビルドパスに設定します。

GWT-Exporterを使用するための設定

Fileメニューから「New」→「Other…」を選び、Google Web Toolkitフォルダ内の「Module」を選択します。
GWT-Exporterを使用するための設定

パッケージ名にはプロジェクト作成時に指定したものを入力します。モジュール名は適当な名前を付けます。Inherited modulesにデフォルトで指定されている「com.google.gwt.user.Uesr」を取り除き、「org.timepedia.exporter.Exporter」を追加します。
パッケージ名

「モジュール名.gwt.xml」というファイルが作成されるので、それを開き、次の3行を追加します。

モジュール名.gwt.xml

上記のentry-pointで指定したクラスを、次の内容で作成します。

  • EntryPointインターフェースを実装する
  • onModuleLoadメソッド内でExporterUtil.exportAll()を呼ぶ

Javaのソースコード

JavaScriptから呼び出したいクラスは、Exportableインターフェースを実装している必要があります。さらに、@Exportアノテーションをクラスまたはメソッドに指定する必要があります。

また、JavaScript側でのパッケージ名を@ExportPackageアノテーションで指定することができます。

詳しくは下記をご覧ください。
http://code.google.com/p/gwt-exporter/wiki/GettingStarted

既存のJavaコードがあり、それに手を入れたくない場合は Exportable の代わりに ExportOverlay を使うこともできます。今回は後述のj2objcを使用する際にこの方が都合が良いので、こちらを採用します。

JSNI (JavaScript Native Interface)

Java側からJavaScriptを呼ぶことができます。JNIと同様にnative修飾子を付けたメソッドを宣言し、次のように /*-{}-*/ で囲ったコメント内にJavaScriptのコードを記述します。

オーバーレイクラスの方も修正します。

コンパイル

Package Explorer内のプロジェクトを右クリックし、「Google」→「GWT Compile」を選択するとダイアログが出てきます。そのままCompileボタンを押してください。
コンパイル

しばらく待つと次のようなファイルが出来上がります。
ファイルが出来上がり

JavaScriptから呼び出す

コンパイルしてできた「***.nocache.js」というファイルをscriptタグで読み込むと、@Exportアノテーションを指定したクラスやメソッドが使用できます。

j2objc

j2objcのビルド

http://code.google.com/p/j2objc/downloads/list
ここからj2objcのソースコードをダウンロードします。バイナリ版もありますが、私の環境では正常に動作しませんでした。

ビルドには次の環境が必要です。

  • Xcode 4以上
  • Java for OS X
  • Apache Maven

次の手順でビルドします。

Javaのソースコード

GWT-Exporterの解説で使用したHelloクラスにmainメソッドを追加します。また、JSNIで記述していたsayHelloNativeメソッドも書き換えます(詳細は後述)。

j2objcでObjective-Cに変換、j2objccでコンパイル

次のコマンドで上記のHelloクラスをObjective-Cに変換します。

このコマンドによりobjcディレクトリ内(のcom/sonicmoov/example/gwtx/client)に Hello.h と Hello.m が作成されます。

次のコマンドで Hello.h, Hello.m から実行バイナリ hello を生成します。

出来上がったバイナリを実行します。

OCNI (Objective-C Native Interface)

さきほど、JSNIで記述していたsayHelloNativeメソッドを次のように書き換えました。

j2objcは、ネイティブメソッド用のコメントデリミタにGWTのJSNIとは異なる /*-[]-*/ を使用することで、Objective-C、GWT、そしてJava(JNI)で同じネイティブメソッドを共有できるようになっています。

メモリ管理について

JavaからObjective-Cに変換する場合、メモリ管理がどのようになるのか気になるところです。j2objcでは、明示的なリファレンスカウント、ARC、GCの3つから選べるようです。デフォルトは明示的なリファレンスカウントです。

詳細は下記をご覧ください。
http://code.google.com/p/j2objc/wiki/MemoryManagement

まとめ

GWT-Exporterとj2objcの基本的な使い方は以上になります。JavaからJavaScript/Objective-Cに変換できるのは、java.langパッケージとjava.utilパッケージの一部のみのようなので、GWT-Exporterやj2objcがどんなプロジェクトでも使用できるわけではありませんが、ビジネスロジックをJavaで記述しJavaScript/Objective-Cに変換、UI等はそれぞれに書くことで、Webアプリ、Android、iOS間で一部のソースコードを共有できるようになるのではないでしょうか。

今回は非常に単純なコードで試しただけですが、もっと大きく複雑なものでのテストも行いパフォーマンスの計測等も行う予定です。またj2objcはXcodeに統合して使うこともできるようなので、それについても調査し改めて記事にしたいと思います。

あわせて読みたい記事