目次

はじめに

本書の構成について
免責事項
底本について

第1章 Embeddinator-4000の設計と実装

1.1 Embeddinator-4000とは何か?
1.2 Embeddinator-4000の使い方
1.3 Embeddinator-4000の前提となるXamarinプラットフォームの仕組み
1.4 Embeddinator-4000のユースケース
1.5 まとめ

第2章 Xamarin.Macアプリケーションの配布方法

2.1 はじめに
2.3 App Storeでの配布
2.4 App Store外での配布
2.5 配布方法の選択
2.6 証明書と署名
2.7 パッケージ
2.8 まとめ

第3章 Plugins for Xamarin & Unit Test

3.1 はじめに
3.2 Plugins for Xamarin 概要
3.3 Plugins for Xamarinの仕組み
3.4 Bait and SwitchとUnit Test
3.5 その他注意事項
3.6 まとめ

第4章 MonkeyFest2017 参加レポート

4.1 あらまし
4.2 Call For Paperへの応募
4.3 採択まで
4.4 セッションの準備
4.5 イベント
4.6 まとめと所感
4.7 Appendix

第5章 世界を広げるMicrosoft Cognitive Services

5.1 Microsoft Cognitive Servicesとは?
5.2 Microsoft Cognitive Servicesの利用開始とサンプルコード
5.3 終わりに

第6章 IL2Cプロジェクト

6.1 IL2Cとは何か?
6.2 IL2CのProsとCons
6.3 IL2Cプロジェクトを始めた背景
6.4 IL2C設計上の留意点
6.5 IL2Cの実装
6.6 IL2Cの展望
6.7 まとめ

著者紹介

はじめに

 Extensive Xamarinは、前著「Essential Xamarin」に続くクロスプラットフォーム開発環境Xamarinについての解説書です。前作がXamarinの最新情報をもとに基本を押さえる内容でしたが、2018年1月現在Xamarin関係の商業書籍が増えてきた中、本書では前作を踏まえて「総論ではない」「一歩先の」「深い」話をまとめています。

 本書には、Xamarinが「外側に出ていく」ための記事を収録しています。.NETのコードをJavaやObjective-Cのプロジェクトで使用する「Embeddinator-4000」の解説、Xamarin.Macアプリケーションを作成した後に誰もが悩むであろうその配布方法、クロスプラットフォーム開発の可能性を拡大する「Plugins for Xamarin」の基本やDIコンテナを用いたユニットテスト手法、「Microsoft Cognitive Service」にXamarinを繫げるための道筋、そして変わり種として海外のXamarinカンファレンスに出てセッショントークをこなすためのさまざまなTipsが、この1冊にまとめられています。

 本書の読者のみなさんが、Xamarinの技術やXamarin技術者の可能性の広がりを感じとることができれば、さらには自ら実践までできるようになれば幸いです。

執筆者代表 榎本 温

本書の構成について

 本書はTechBooster1が公開しているFirstStepReVIEW2を利用しています。

免責事項

 本書に記載された内容は、情報の提供のみを目的としています。したがって、本書を用いた開発、製作、運用は、必ずご自身の責任と判断によって行ってください。これらの情報による開発、製作、運用の結果について、著者らはいかなる責任も負いません。

底本について

 本書は技術系同人誌即売会「技術書典3」で頒布された『Extensive Xamarin』の内容をもとに加筆・修正を行ったものです。


第1章 Embeddinator-4000の設計と実装

1.1 Embeddinator-4000とは何か?

 「Embeddinator-4000」は、Mono上で動作するライブラリやXamarinで作成されたライブラリを、各プラットフォームで使用できるライブラリとしてパッケージできるようにする、相互運用のための技術です。アプリケーションは全体としてはプラットフォームネイティブで作成しつつ、必要に応じてMonoやXamarinで実装した機能を「呼び出す」ことができるようになります。

 (なお、本稿では特に省略せずにEmbeddinator-4000と記述しますが、「e4k」などと表記されることもあります。)

「Xamarinをネイティブで使う」いろいろな技術

 Xamarinの世界では、特に2017年になって「ネイティブのコードを使う」ための技術がいくつか登場し、混乱を招きやすい状態になっているので、少し整理しましょう。


1) Native Embedding(Xamarin.Forms)

 これは、Xamarinネイティブ(プラットフォーム固有)のコントロールをXamarin.FormsのLayoutの子として追加できるようにした技術です。これによって、Xamarin.Formsの共通コントロールをPCLとして(bait and switchのような技術を使用して)パッケージしなくても、直接プラットフォーム固有のコントロールとして埋め込めることになります。

2) Forms Embedding(Xamarin.Forms)

 これは、Xamarin.FormsのページをXamarinネイティブ(プラットフォーム固有)のUIコントロールとして追加できるようにした技術です。ちょうどNative Embeddingとは逆向きの機能だといえます。Xamarin.Formsで書いてしまったビューがあるけど、どうしてもXamarinネイティブのプロジェクトで使いたい、という場合に、逃げ道として採用できる技術です。

3) Embeddinator-4000 (.NET Embedding)

 本章で論じる技術はこちらで、Xamarinプラットフォーム用に書かれたコードを、プラットフォームネイティブ言語のライブラリとして利用できるようにするものです。Xamarin.Formsと直接の関係はありませんが、Xamarin.FormsはXamarinプラットフォーム上で動作するライブラリであり、基本的にはEmbeddinatorの対象となるものです(ただし2017年11月の時点で公開されているバージョン0.3.0ではPCLの参照解決はうまくできていません)。


 2017年11月に行われたMicrosoft Connect(); 2017ではEmbeddinator-4000のことを「.NET Embedding」という馴染みのない表現で紹介されていましたが、これがどれくらい通用するかはまだ分からず、この混乱にさらに拍車をかけそうな気もするので、本稿ではEmbeddinator-4000の呼称を用いることにします。

アプリケーションと実行環境のバンドル

 .NETが誕生し発展してきたWindowsの世界ではあまり一般的ではありませんが、ネイティブコードに変換しないタイプのプログラミング言語とその前提となる実行環境では、その上で動作するアプリケーションをネイティブアプリケーションとしてパッケージして配布する仕組みが、しばしば用意されています。

 これらの全てではありませんが、このようなパッケージ化の技術の多くは「実行環境をアプリケーションに同梱して配布する」仕組みになっています。実行環境がプロプラエタリーで自由に配布できない場合(ここでは「ランタイムが自由なソフトウェアで、かつ実行時にプロセスがランタイムと一体になるために、自由なソフトウェアとして配布されることを避けたい場合」なども含みます)は別として、一般的にはこのアプローチがもっともシンプルです。

 Monoの世界には、mkbundleというツールが存在しており、monoランタイムとmscorlib.dllなどのフレームワークアセンブリ、アプリケーションのアセンブリをまとめて、実行時にこれらを展開してロードする仕組みが以前から備わっていました。つまり、表層的には、.NETアプリケーションをネイティブアプリケーションであるかのように振る舞わせることが可能だったのです。

 また、iOSに関しては、Xamarin.iOSはマネージドコードをAOT(事前)コンパイルによってネイティブコードに変換して実行するものであり、これはマネージドコードをネイティブライブラリそのものに変換する技術です。(この点では、同じObjective-Cを基盤とする技術でも、Xamarin.iOSとXamarin.Macは大きく異なりますが、特にデスクトップ・フレームワークで動作するXamarin.MacはMonoのデスクトップアプリケーションと同じであり、特別に難しいことは何もありません。)

 Embeddinator-4000の場合、この観点では、Mono/Xamarin向けライブラリは、ネイティブライブラリとしてmonoランタイムと一緒にパッケージされて配布できるようになったものである、といえます。

Embeddinator-4000でできること

 もちろん、単にmonoランタイムとマネージドコードのライブラリをバンドルするだけでは、そのまま呼び出せるかたちになりません。ネイティブプラットフォーム言語向けのAPIも用意する、というのがEmbeddinator-4000の重要な仕事です。

 当初、Embeddinator-4000はMonoランタイムで動作するデスクトップアプリケーションのみを前提として開発されていましたが、2017年8月の時点でAndroid用のJava APIとiOS/macOS用のObjective-C APIも自動生成できるようになっています。さらに11月の開発中のバージョンではSwiftのコードも生成できるようになっています。ただし、まだプレビュー段階であり、また正式に「使える」ものとされているのはAndroid用のJavaのみです。生成されるAPIおよび実装については、以降の節でもう少し詳しく見ていきます。

1.2 Embeddinator-4000の使い方

ツールをセットアップする

 2017年11月の時点では、Embeddinator-4000はコンソール・ツールであり、ユーザーがコマンドラインから実行して使用することが前提になっています。入手経路は主にふたつあります。


1.NuGetでパッケージをインストールする

 こちらがもっとも一般的な方法でしょう。Visual Studio(for Windows / for Mac)などでプロジェクトを開き、NuGet packagesのダイアログを開いて "Embeddinator" を検索すると出てくるはずです。これを追加して、NuGetパッケージのダウンロードとインストールが成功すると、ソリューションのpackagesディレクトリにEmbeddinator-4000.0.3.0 のようなサブディレクトリが作成されているはずです。これがパッケージの内容を全て含んでおり、tools/MonoEmbeddinator4000.exe などが実行すべきツールとなります。

 本稿執筆時点での最新バージョンは0.3.0です。

2.https://github.com/mono/Embeddinator-4000 をチェックアウトしてビルドする

 Embeddinator-4000はオープンソースであり、ソースからビルドして使うこともできます。ソースをチェックアウトして build.sh を実行するだけで、(ビルドが成功すれば) build/lib/Release/MonoEmbeddinator4000.exe などがビルドされます。ビルドにはCakeが必要で、内部的にはさらにdotnetコマンド(dotnet/cli)を使用しているので、これらが動作することが前提です。

 なお、xamarin-androidと組み合わせて、Linux上でも使うことが可能であるのが理想ですが、xamarin-androidが内部的に使用している xamarin-android-tools というリポジトリのコードが Embeddinator-4000 で使用しているものと適合しておらず、古い製品版Xamarin.Androidのセットアップが必要になっているのが2017年11月時点での現状です(つまりLinux環境ではまだ修正を加えないと使えません)。

 githubのソースは日々開発者がチェックインしているものであり、ビルドしても通らないこともしばしばあります(筆者も本章の初版をまとめていたときは最新のmasterがビルドせずに難儀したものでした)。

ツールを実行してライブラリをビルドする

 コマンドラインツールを実行してライブラリをビルドします。このとき、実は言語によって実行するツールが異なります。CおよびJavaではMonoEmbeddinator4000.exe、Objective-Cではobjcgen.exeとなります。それぞれ次のようなコマンドを実行します。パスはNuGetパッケージでインストールした場合を想定しているので、ソースからビルドした場合は適宜変更してください。

1.C (Linux)

mono packages/Embeddinator-4000.0.2.0.80/tools/Embeddinator-4000.exe
      -platform=Linux -gen=c -c project/bin/Debug/MyLibrary.dll

2.Java (Android)

mono packages/Embeddinator-4000.0.2.0.80/tools/Embeddinator-4000.exe
      -platform=Android -gen=Java -c project/bin/Debug/MyLibrary.dll

3.Objective-C (macOS)

mono packages/Embeddinator-4000.0.2.0.80/tools/objcgen.exe
      -platform=macOS -gen=Obj-C -c project/bin/Debug/MyLibrary.dll

 Objective-Cのobjcgen.exeの例ではplatform引数にmacOSを指定しましたが、iOSを指定することもできます。

 なお、 オプション-cはコンパイラを呼び出してライブラリをビルドするところまで行うためのものですが、Cコンパイラの呼び出しには、WindowsではMSVC、Macではclang、Linuxではgccを利用します。ちなみに、Androidについては、Android NDKを使用してネイティブライブラリをビルドしているので、Linux上で-cを指定しても正しく動作するはずです(ただし、前述の理由により、まだ利用できません)。

簡単な使用例

 Embeddinator-4000のライブラリ生成処理が完了すると、対象プラットフォームに対応したAPIを含むライブラリのソースが生成されます。コンパイルも行うようにしていれば、ビルド処理も行われ、Androidならaar、macOSならframeworkやdylib、といった、各プラットフォームに対応するライブラリが出力されます。

 ここではCのAPIを具体的なコードで生成してみましょう。まず次のようなC#ソースを用意します。

public class MyLibrary
  {
      public string Hello (string input)
      {
          return "Hello, " + input;
      }
  }

 極めて単純なHelloメソッドを含むライブラリです。これをcscでコンパイルします。

$ csc -t:library MyLibrary.cs

 このDLLからCのAPIを生成します。-p Windows と指定している部分はとりあえずおまじないと思っていても大丈夫です。(プラットフォーム指定オプションは必須なのにLinuxなどが指定できないため、こう指定しています。)

$ mono --debug /.../MonoEmbeddinator4000.exe --gen=C -p Windows MyLibrary.dll
  Parsing assemblies...
      Parsed 'MyLibrary.dll'
  Processing assemblies...
  Generating binding code...
      Generated: MyLibrary.h
      Generated: MyLibrary.c
      Generated: c-support.c
      Generated: c-support.h
      Generated: embeddinator.h
      Generated: glib.c
      Generated: glib.h
      Generated: mono-support.c
      Generated: mono-support.h
      Generated: mono_embeddinator.c
  Generated: mono_embeddinator.h

 ここでは-cオプションを指定していないため、生成したCソースをコンパイルする作業は行われていません。生成されたMyLibrary.hの内容を抜粋します。(紙面に合わせて適宜改行しています)

MONO_EMBEDDINATOR_BEGIN_DECLS

  typedef MonoEmbedObject MyLibrary;

  MONO_EMBEDDINATOR_API MyLibrary* MyLibrary_new();
  MONO_EMBEDDINATOR_API const char* MyLibrary_Hello(MyLibrary* object, \
      const char* input);

  MONO_EMBEDDINATOR_END_DECLS

 MyLibraryオブジェクトを生成するMyLibrary_new()、そのHelloメソッドを呼び出すMyLibrary_Hello()が定義されていることが読み取れます。FooBar_new()FooBar_instance_method()といった関数は、C言語でよくあるオブジェクト指向のスタイルです。MyLibrary.cにはこの実装が含まれていますが、内容は割愛します。

 実際にこのAPIを使ってみましょう。次のようなCのコードを作成します。

#include <stdio.h>
  #include <MyLibrary.h>

  void main (int argc, char **argv)
  {
     MyLibrary *obj = MyLibrary_new();
     puts (MyLibrary_Hello(obj, argv[1]));
     mono_embeddinator_destroy_object(obj);
  }

 先のヘッダファイルにmono_embeddinator_destroy_object()は出てきませんでしたが、これは自動生成される(というよりコピー出力される)mono_embeddinator.hで定義されています。newに対するdeleteと考えてよいです。

 このソースを含む全体をコンパイルしてみましょう(通常はいったんEmbeddinator-4000に-cオプションを指定してlibMyLibrary.aなどをビルドして使いますが、今回は-cが使えない環境でも利用できることを示すため、ソースから全部まとめてビルドします)。コンパイラはgccでもclangでもその他何でもかまいませんが、monoの開発用パッケージのファイルを使うので少々特殊な引数(pkg-configの実行結果など)が必要です。

$ gcc -I . *.c `pkg-config --cflags mono-2` `pkg-config --libs mono-2` -o app

 これでappという実行可能ファイルが生成されました。実行してみましょう。

$ ./app Hogehoge
  Hello, Hogehoge

 このように出力されれば成功です。

 iOSやAndroidの場合も、これらをソースからビルドすることは可能ですが、Embeddinator-4000がビルドするライブラリを使用したほうが簡単でしょう。

試し読みはここまでです。
この続きは、製品版でお楽しみください。