目次

はじめに

免責事項
表記関係について
底本について

第1章 Xamarin.Android で始めるクロスプラットフォームモバイルアプリ開発

1.1 Xamarinとは?
1.2 Xamarin.Androidと「ネイティブ」の違い
1.3 Javaの資産をXamarin.Androidで使用する
1.4 C#の利点
1.5 クロスプラットフォームアプリ開発とコードの共有
1.6 Xamarin.Formsとは
1.7 MVVM+Rxによるモダンなアプリケーション開発
1.8 Xamarinによる「クロスプラットフォーム」MVVM+Rxアプリケーション
1.9 オープンXamarin、オープンマイクロソフト
1.10 Xamarin の使いどころ

第2章 できるXamarin.Mac

2.1 Xamarin.Macの世界へようこそ
2.2 最初のアプリケーションを作る
2.3 macOS向けアプリケーションのお作法
2.4 おわりに

第3章 Prism for Xamarin.Forms入門の次の門

3.1 はじめに
3.2 事前準備:Prism画面遷移実装の解説
3.3 XAMLでViewModelのコード補完の有効化
3.4 Prism Template PackのDesignTimeViewModelLocator対応
3.5 ViewとViewModelのAssemblyの分離
3.6 ViewModel 指定のナビゲーション
3.7 DeepLinkにおけるViewModel指定とリテラル指定の共存
3.8 遷移名の属性(Attribute)による指定
3.9 命名規則から逸脱したView・ViewModelマッピング
3.10 まとめ

第4章 画面遷移カスタマイズから取り組むXamarin.iOS

4.1 準備
4.2 基礎編:画面遷移のカスタマイズ
4.3 応用編:スワイプして消せるモーダル
4.4 黒魔術編:画面内のどこからでもスワイプしてポップ
4.5 まとめ

第5章 Xamarin Bluetooth Low Energy インストール編

5.1 なぜ Xamarin で BLE を実装するのか
5.2 BLE の 概略
5.3 Xamarin BLE Plug のインストールとサンプルコード
5.4 終わりに

第6章 開発者のためのXamarin関連リポジトリ集

6.1 Monoのコア コンポーネント
6.2 GUIフレームワーク
6.3 MonoDevelop
6.4 モバイル プラットフォームSDK
6.5 Xamarin コンポーネント/ライブラリ
6.6 モバイル・デスクトップ共通のクロスプラットフォーム ライブラリ
6.7 サンプル集
6.8 非マネージドコード環境との相互運用
6.9 仕様策定
6.10 総括

第7章 Xamarin.Android SDK解説 (rev. 2017.3)

7.1 Xamarin.Androidの基礎
7.2 Xamarin.Android SDK
7.3 Xamarin.Android SDKの仕組み

第8章 Monoでモノのインターネットを目指す

8.1 Mono: クロスプラットフォーム動作する.NET環境
8.2 モバイル環境で多く使われるMono
8.3 もっと貧弱な環境でもMonoを使いたい
8.4 省電力組み込みチップESP32上でMonoを動かしたい
8.5 Monoランタイムの実行に必要なリソース
8.6 リソース消費量の計測用にMonoをビルドする
8.7 組み込み環境向けのMonoランタイム
8.8 Monoランタイムの構造を読解する
8.9 Monoランタイム起動直後の処理
8.10 リソースの種類ごとの消費量調査
8.11 Monoのドキュメントに沿って容量を削減する
8.12 ヒーププロファイル結果からRAM削減余地を探す
8.13 クラスライブラリの削減余地を検討する
8.14 ROM/静的確保RAMの削減余地を探る
8.15 まとめ

執筆者紹介

はじめに

 Essential Xamarinに興味をもっていただき、ありがとうございます。本書は、Xamarinの本筋であるモバイル・アプリケーションの設計・開発技法について、最先端のXamarinアプリケーション開発者が総力を尽くして丁寧にまとめあげた文章を中心に構成された一冊となっています。

 2017年にXamarinアプリケーション開発技術の入り口から最先端の世界までを日本語で読める、希少な存在である本書をおたのしみください。


執筆者代表 榎本 温

免責事項

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

表記関係について

 本書に記載されている会社名、製品名などは、一般に各社の登録商標または商標、商品名です。会社名、製品名については、本文中では©、®、™マークなどは表示していません。

底本について

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



第1章 Xamarin.Android で始めるクロスプラットフォームモバイルアプリ開発

 Xamarinはモバイルアプリ開発ツールであることから、.NET/C#系の開発者であってもAndroidやiOSアプリの(いわゆる「ネイティブ」の)開発知識が必須であると筆者は考えています。逆に、Androidアプリ開発者がXamarinを使うこともまた容易であり不思議なことではないのです。この章は、主にAndroidアプリ開発者の方に、Xamarinについて知ってもらうことを目的としています。

 まず、Xamarin/Xamarin.Androidとは何か、そして主要な開発言語であるC#や.NETフレームワークの強力な言語・ライブラリ機能について触れます。さらに通常のAndroidアプリ開発とXamarinを使ったアプリ開発はどこが違って、どこが同じなのかを説明します。

 さらに、今日のモバイルアプリ開発では、データバインディング、MVVM、Reactive Extensions(Rx)といった、マイクロソフトが源流となっている手法が広く用いられています。Xamarinを使うと、MVVMパターンとRxを使用し、大部分のコードを共有できるAndroid/iOS両対応アプリケーションを開発できます。如何にしてコードを共有するか、できない場合にどのような解決策が用意されているかについて解説します。

 もし「マイクロソフトだから」や「.NETってSIer()が使うやつでしょ」といった理由で今まで避けてきたのなら、本章を通してその誤解が少しでも解ければ幸いです。

1.1 Xamarinとは?

 Xamarinとは、元企業名/現在はブランド名であり、開発ツールキットや開発者向けサービスの名前でもあります。ここでは、開発ツールキットとしてのXamarinについてひととおり触れ、本稿の主題であるXamarin.Androidについて解説します。

Xamarinとは何か

 開発ツールキットとしてのXamarinとは、主に「Xamarin.Android」、「Xamarin.iOS」、「Xamarin.Mac」を指し、これらは公式サイトでは「Xamarin Platform」に分類されています。1

 このツールキット群が提供する唯一にして最大のことは、「各プラットフォームのAPIをC#から呼び出せるラッパーの提供」です。

 たとえば、AndroidならばActivity、iOSならばViewControllerなど、本来ならばJavaやObjective-C/Swiftから呼び出して使うAPIを、C#から呼び出して使用できます。

 つまり、Xamarin.AndroidやXamarin.iOS自体は、クロスプラットフォームでコードを共有できるツールキットでもなんでもありません。単なる「それぞれのプラットフォームの薄いラッパー」です。

 Xamarin.AndroidやXamarin.iOSは、.NETフレームワークのOSS実装である「Mono」の上で動作します。コード共有は、このMonoが複数のプラットフォームに対応していること、またPCL(Portable Class Library)という同一のバイナリを複数プラットフォームが使用できる仕組みの恩恵です。これについては「1.5 クロスプラットフォームアプリ開発とコードの共有」で詳しく説明します。

 Xamarin Platformの上位層には「Xamarin.Forms」という、ユーザーインターフェースも共通化できるフレームワークがあります。これについては「1.6 Xamarin.Formsとは」で説明します。

Xamarin Platformという呼称

 Xamarin.Android、Xamarin.iOSといった「プラットフォームのAPIの薄いラッパー」を提供するツール群は、過去に「Xamarin Native」と公式サイトで記載されていました。しかし、「Native」という単語の曖昧さが嫌われてか、現在の公式サイトにはこの表記は見られません。国内外のXamarinの発表資料では現在も「Xamarin Native」という呼称が使われていたり、最近では「Xamarin Traditional」を使っている資料もあるようです。できればどれかに統一して欲しいと思いますが、個人的には「Xamarin Platform」に一票!です。

Androidアプリ開発者から見たXamarin.Android

 Mono上で動作するXamarin.Androidの動作の仕組みについては、本書の代表でもある @atsushieno 氏による「インサイドXamarin2」にて詳しく解説されています。Xamarinの中の人による詳解なので、これ以上の説明はまったく不要ですが、筆者の解釈で描いた図をひとつだけ紹介します。

図1.1: AndroidネイティブとXamarin.Androidの構成

 図1.1は、ネイティブとXamarin.Androidでの構成と実行形式の違いを示したものです。AndroidアプリはJavaVM(DalvikやART)上で動作しますが、Xamarin.Androidでは、JavaVMに加え、C#コード(からコンパイルされた中間言語=MSIL)を解釈、実行するMonoVMが並行して動作します。MonoVMを含むランタイムは、(リリースビルドでは)アプリに同梱され、動作します。

 ここでは、Androidアプリ開発者がXamarin.Androidでアプリを開発してみたならば、という視点で、Xamarin.Androidについて説明してみます。

Getting Started

 Xamarin.Androidでアプリを開発するには、統合開発ツールであるVisual Studio for MacまたはXamarin Studio(macOSの場合)、Visual Studio 2015(Windowsの場合)を使用します。Androidアプリ開発者のみなさんはきっとMac使いなので、ここではVisual Studio for Macを使って説明しましょう。

Visual Studio for MacとXamarin Studio

 2016年11月にPreview版が公開されたVisual Studio for Macは、2017年6月に正式リリースされました3。その実体はXamarin Studioに.NET Standard対応やAzure連携の機能を追加して外観を変えたものです。しばらくの間は両者が並行して存在する模様ですが、Visual Studio for Macが正式リリースとなったことで、Xamarin Studioは今後収束していくと予想されます。これからXamarinアプリ開発を始めるならば、Visual Studio for Macを使用しましょう。

 Visual Studio for Mac(以下Visual Studioと略)を起動して、「New Project...」を押すと、プロジェクトのテンプレート選択ダイアログが表示されます。左サイドバーの「Multiplatform」には、AndroidとiOSアプリを同時開発するためのプロジェクトテンプレートが並んでいますが、もっともシンプルにXamarinでAndroidアプリを作成する場合は、「Android-App」から「Android App」を選択します。

図1.2: プロジェクトのテンプレート選択ダイアログ

 続いて、プロジェクトの設定ダイアログで、プロジェクト名などを入力します。ここでは「FirstXamarinApp」としましょう。

図1.3: 作成するプロジェクトの設定ダイアログ1

 次に、プロジェクトの保存ディレクトリや、gitによるバージョン管理を使用するかを選択します。

図1.4: 作成するプロジェクトの設定ダイアログ2

 「Create」ボタンを押すと、プロジェクトが生成されます。

図1.5: 作成されたプロジェクト

 ちなみにXamarinをデフォルトインストールしていれば、Intel HAXMを使用した高速エミュレータも作成されます。図1.5の上部に見える「Android_Accelerated_x86」がそれで、このままメニューから「Run-Start Without Debugging」を実行すれば、Androidエミュレータが起動し、アプリが実行されます。

図1.6: アプリを実行したAndroidエミュレータ

Android StudioとAndroid SDKを共有したい

 Androidアプリ開発者であれば、すでにAndroid Studioとそれが使用するAndroid SDKをインストール済みでしょう。そのAndroid SDKをXamarinでも使用することは可能です。Xamarinのインストール時に既存のSDKを選択してもよいですし、インストール後にVisual Studioのメニュー→Preference→Projects→SDK Locations-Androidでディレクトリを変更することでも可能です。ただしSDKを共有する場合、Android SDKを最新に更新した時に、それがXamarinではまだ対応できていないバージョンである可能性があることに留意してください。

 Xamarinが「Xamarin用に」Android SDKをインストールするのは、Android SDKのアップデートはGoogleの気まぐれで行われ、事前情報も得られないことから、Android SDKの更新によりXamarinが動作しなくなるトラブルを避けるためであるとのことです。

作成されたプロジェクトの構成

 Visual Studioのソリューションツリー(あるいはFinderやエクスプローラで)で、プロジェクトの構成を見てみましょう。

リスト1.1: プロジェクト構成(抜粋)

/FirstXamarinApp
    FirstXamarinApp.csproj
    MainActivity.cs
    /Assets
        AboutAssets.txt
    /Properties
        AndroidManifest.xml
        AssemblyInfo.cs
    /Resources
        /layout
            Main.axml
        /values
            Strings.xml
        …

 Androidアプリ開発の経験者であれば、これを見ただけで「Xamarin.AndroidはAndroid SDKの薄いラッパーである」の意味が判ると思います。そう、MainActivity.csはAndroid StudioではMainActivity.javaであり、layout/Main.axmlvalues/Strings.xmlは、それぞれ画面のレイアウト、リソース文字列のXMLファイルそのものです。

 MainActivity.csを開いてソースコードを見てみましょう。これは、ボタンを押すとボタンに表示される数値が1ずつ加算されていく、という簡単なプログラムです。

リスト1.2: MainActivity.csの例

  1: using Android.App;
 2: using Android.Widget;
 3: using Android.OS;
 4:
 5: namespace FirstXamarinApp
 6: {
 7:     [Activity(Label = "FirstXamarinApp",
 8:         MainLauncher = true,
 9:         Icon = "@mipmap/icon")]
10:     public class MainActivity : Activity
11:     {
12:         int count = 1;
13:
14:         protected override void OnCreate(Bundle savedInstanceState)
15:         {
16:             base.OnCreate(savedInstanceState);
17:
18:             // Set our view from the "main" layout resource
19:             SetContentView(Resource.Layout.Main);
20:
21:             // Get our button from the layout resource,
22:             // and attach an event to it
23:             Button button = FindViewById<Button>(Resource.Id.myButton);
24:
25:             button.Click += delegate { button.Text = $"{count++} clicks!"; };
26:         }
27:     }
28: }

 ActivityOnCreateFindViewByIdなど、Android SDKのクラス、メソッド名がそのままC#から使用できていることに注目してください。些細な違いは、C#のルールにならって

 ・メソッド名は大文字から始まる

 ・setter/getterメソッドはプロパティに置き換えられる

 ・イベントリスナーの設定(setOnClickListener)はイベント構文(Click +=)に置き換えられる

などです。

AndroidManifest.xml は書くな、定義せよ

 リスト1.1には、おなじみのAndroidManifest.xmlがあります。しかし、このファイルを開いてみるとわかりますが、ほとんど何も記述されていません。ではここに書くべきアプリケーション情報やIntent-Filterなどはどこに記述するのでしょうか?

 Xamarin.Androidでは、これらの情報はクラスの属性として定義します。リスト1.2をもう一度見てください。MainActivityに付与されている[Activity(Label = "FirstXamarinApp", MainLauncher = true, Icon = "@mipmap/icon")]がそれです。また、applicationタグに対する設定をするには、Applicationクラスを拡張したクラスの属性を付与します。属性とAndroidManifest.xmlとの関連は公式サイト4に詳しく記述されています。

1.2 Xamarin.Androidと「ネイティブ」の違い

 これまで見てきたように、Xamarin.Androidでは、Android SDKのAPIをそのまま使用できます。XamarinのPR資料などで「APIが100%使えます」などと紹介されているのは間違いではありません5。しかし、Androidのアプリ開発で重要なのはSDKだけではありません。ここでは、Xamarin.Androidと「ネイティブ」のAndroidアプリ開発で使用されるツール群の「無視できない違い」について説明します。

統合開発環境

 Android Studioは、とても素晴らしい統合開発環境(以下、IDEと略)です。Visual Studio for Windows6は「最強のIDE」とも呼ばれていますが、残念ながらAndroidアプリ開発に最適化されたAndroid Studioには及びません。特に画面レイアウトのプレビューは、Visual Studioのそれは「おまけ」と思ってよく、Xamarin.Androidを使っていても、画面レイアウトのためだけにAndroid Studioを使用することがある程です7

 多くのC#erは、Visual Studio for Windows向けの有償の拡張機能である「JetBrains Resharper(R#)8」を好んで使用しています。しかしAndroid Studioも同じJetBrains社のIntelliJ IDEAをベースとしており、Androidアプリ開発者の皆さんは、R#が提供する機能の一部を日常的に(無料で!)使用しています。

 Visual Studio for Mac/Xamarin Studioは、MonoDevelop9にXamarin用のAddinが加わったものであり、十分な機能と生産性を持ってはいますが、やはりAndroid Studioほどの開発効率の高さは持ち合わせていません10

 総じて、「Xamarin.Androidで使うIDEは、Android Studioよりは若干劣る」といえます。

新しいIDE、JetBrains Rider

 そのJetBrainsが現在開発中なのが「JetBrains Rider11」という新しい.NET用のIDEです。クロスプラットフォーム対応12、Xamarinのアプリ開発もサポートし、R#のエンジンも搭載しています。2017年6月現在、EAP(Early Access Program)にて誰でも試すことができ、Xamarin.Android、Xamarin.iOSのプロジェクトもビルド、実行、デバッグできます。

 キーボードショートカットなどの定義がほぼ同じなので、Android Studioの利用者は入りやすいと思います。筆者もすでに「C#コードエディタ」として使用していますが、今後のリリースが楽しみです。

Gradleビルドシステム

 Gradleビルドシステムは、Androidのアプリやライブラリ開発の非常に重要な要素のひとつです。Androidデータバインディングや、Product Flavor、Android-APT(Annotation Processing Tool)を使用したライブラリなどは、Gradleによるビルド時にコード生成させることで実現しています。

 Gradleビルドシステムや*.gradleファイルは、Xamarin.Androidでは使用できません。Xamarin.Androidでは、.NET/Monoの世界で培われて来た「msbuild13」「xbuild14」ビルドシステムを使用します。通常これらはIDEの陰に完全に隠れているので直接触れることはありませんが、もしあなたがビルド時に何か特別なことをしたい場合は、これらについて学ぶ必要があります。どちらもXMLによるタスクの記述が必要なので、その点でも利用者を苦悩させるでしょう。

パッケージ管理システム

 ネイティブのAndroidアプリ開発ではライブラリ開発者は、maven、JitPackといったリポジトリにライブラリを登録し、利用者は*.gradleファイルに利用パッケージを記述することで、ライブラリを自動でダウンロード、組み込むことができます。

 Xamarin.Android用(というか.NET製)のライブラリは、「NuGet」と呼ばれるパッケージマネージャーから提供されることがほとんどです。ライブラリ開発者は、NuGetにライブラリを登録し、利用者はNuGetから使用したいライブラリを選択してプロジェクトに登録します。通常は、Visual StudioなどのIDEに付属しているNuGetパッケージマネージャーでライブラリを追加・削除しますが、ライブラリの情報はNuGetのウェブサイト15から閲覧できます。

図1.7: NuGetのウェブサイトからXamarinでパッケージを検索した結果

Xamarin Components

 かつてXamarinがNuGetに対応する以前より、「Xamarin Components16」というXamarin専用のコンポーネントストアがありました。こちらには有償のライブラリもいくつか販売されていました。

 マイクロソフトに買収され、このストアは廃止されるのかなーと思っていましたが、なぜか今でもしぶとく生き残っていて、中にはここにしかないライブラリもあります。とはいえ、Xamarin Componentsはもはや活発ではないので、同じライブラリがNuGetとComponents両方にあったら、迷わずNuGetの方を使いましょう。

Google Play services

 ここまで、「Xamarin.Androidでは使用できません」という説明が続いてきましたが、安心してください、Google Play servicesは、Xamarin.Androidでも使用できます。

 Google Play servicesを使用するためのライブラリはXamarinチームから提供されています。前述のNuGetパッケージマネージャーから入手します。

図1.8: NuGetパッケージマネージャーで検索した Google Play servicesライブラリ群

 本家のGoogle Play servicesと同じく17、Xamarin.Android向けのNuGetパッケージも個別のサービスに分かれています。

Android Instant Apps

 Instant Apps18は、Googleが2016年5月に発表、2017年2月に正式リリースしたAndroidアプリの新しい形式で、Webブラウザからリンクをタップしたり、NFCにタッチしたりするだけで、インストールなしにアプリの機能を実行できるようになります。

 その仕組みは、Instant Appsのために機能別に「小分け」された容量の小さいapkが、リンクのタップなどのタイミングでダウンロードされ即座に実行されるものです。ユーザーが「アプリをインストールする」という手間が必要ないため、これまでよりもたくさんの人にリッチな体験を提供できるとして注目されています。

 さてこのInstant Appsですが、Xamarin.Androidでの対応は現状では難しいと予想されます。Instant Appsでは前述の通り「機能別に小分けされた容量の小さいapk」が必要になりますが、その最大サイズは4MBまでとされています19。Xamarin.AndroidはapkにMonoランタイムを同梱しなければならないため、この容量制限はXamarinにとっては不利です。このため、XamarinでInstant Appsが開発できるかは今後も未知数です(が、可能性がゼロでもなさそうです20)。

1.3 Javaの資産をXamarin.Androidで使用する

 Xamarin.Androidは、Android SDKのAPIを100%ラップしているわけですから、その仕組みを使って、自分が開発した、あるいはオープンソースやサードパーティのJava製ライブラリをラップできます。その仕組みは「Binding」と呼ばれており、そうして作られたライブラリを「Bindingライブラリ」と呼びます。

主なBindingライブラリ

 先に紹介したGoogle Play servicesをXamarin.Androidで使用可能にしたものもBindingライブラリです。他にも、Java製の主要なライブラリはすでにBindingライブラリが作成されています。

 ・Square Picasso - https://www.nuget.org/packages/Square.Picasso

 ・Glide.Xamarin - https://www.nuget.org/packages/Glide.Xamarin/

 ・Square OkHttp - https://www.nuget.org/packages/Square.OkHttp3/

 ・LeakCanaryXamarin - https://github.com/valentingrigorean/LeakCanaryXamarin

 ・CallygraphyXamarin - https://www.nuget.org/packages/CallygraphyXamarin/

 ・Lottie - https://www.nuget.org/packages/Com.Airbnb.Android.Lottie/

Bindingライブラリの作成

 Bindingライブラリを自作するには、Binding Libraryプロジェクトを使用するのが簡単です。Binding Libraryプロジェクトを作成するには、新規プロジェクトで、図1.9のように、「Binding Library」を選択します。

図1.9: Bindingプロジェクト作成ダイアログ

 単純なクラスライブラリであれば、作成されたプロジェクトの/Jarsディレクトリにxxxx.jarファイルを追加するだけで、Bindingライブラリになります。

 Java Bindingライブラリについては、公式サイト21やインサイドXamarin22が詳しいので、参考にしてください。また、Objective-C/Swiftで書かれたiOS向けのライブラリをXamarin.iOSで使えるようにするBindingももちろんあります23

Androidのライブラリに「インスパイア」されたライブラリ達

 Bindingライブラリではありませんが、AndroidのライブラリにそっくりなAPIを提供するXamarin向けのライブラリがあります。

 Stiletto24は、Androidで人気の高いDIコンテナであるDagger25をC#に移植したものです。Daggerは「短剣」、Stilettoも「短剣」です。

 Refit26は、同じくRetrofit27に影響を受けてC#で開発されたREST APIクライアントライブラリです。

1.4 C#の利点

 Xamarinを選択する理由として、クロスプラットフォームでコードを共有できることの他に、単純に「C#が使えるから」という点もあるかも知れません。Java7やObjective-Cはとても冗長で、書いていて楽しいものではありませんでした(少なくとも私は)。今日ではJava8やRetrolambdaあるいはKotlin、iOSアプリ開発ではSwiftと、モダンな言語が使えるようになりましたが、総合的にはまだC#に利点があります。その代表的な例を少し紹介します。

非同期処理(async/await)

 大抵の言語では入れ子になってしまう非同期処理の連続も、async/await構文を使うとフラットに書けます。このコードの可読性の高さは大きな魅力です。

リスト1.3: 非同期処理の例(Java)

  1: private void sendDataAsZip(String srcUrl, String destUrl)
 2:     // 1. データをダウンロードして
 3:     downloadAsync(srcUrl, new DownloadCallBack() {
 4:         @Override
 5:         protected void onDownload(byte[] data) {
 6:             // 2. ZIP圧縮して
 7:             zipAsync(data, new ZipCallback() {
 8:                 @Override
 9:                 protected void onZipped(byte[] zipped) {
10:                     // 3. 別なところに送信
11:                     sendAsync(zipped, destUrl, new SendCallback()
12:                     {
13:                         @Override
14:                         protected void onSent() {
15:                             // 送信完了
16:                         }
17:                     });
18:                 }
19:             });
20:         }
21:     });
22: }

リスト1.4: 非同期処理の例(C#)

 1: private async void SendDataAsZip(string srcUrl, string destUrl)
 2: {
 3:     // 1. データをダウンロードして
 4:     var data = await DownloadAsync(srcUrl);
 5:     // 2. ZIP圧縮して
 6:     var zipped = await ZipAsync(data);
 7:     // 3. 別なところに送信
 8:     await SendAsync(zipped, destUrl);
 9:     // 送信完了
10: }

 リスト1.3とリスト1.4は、

 1.データをダウンロードする

 2.データをZIP圧縮する

 3.圧縮データを送信する

という非同期処理の連続を、JavaとC#で書いたものです。Javaでは非同期処理の結果をコールバックメソッドで受信するため、どうしてもコードのネストが深くなって可読性が低くなってしまいます。が、C#ではawait演算子を付けて呼び出したメソッド28は非同期で実行されますが、その次の行のコードはSendDataAsZipメソッドを呼び出したスレッドで「継続的に」実行されます。

ラムダ式とLINQ to Objects

 Androidネイティブでのラムダ式は、RetroLambda29の導入や、Java8(とJackツールチェイン30)の有効化によって利用できます。

 Xamarin.Androidの現行バージョンである7.2において利用できるC# 6では標準でラムダ式が使用でき、コールバックやイベントハンドラはもちろん、メソッドの実装にすらラムダ式を適用できるようになっています。

リスト1.5: ラムダ式の例(C#)

protected override void OnCreate(Bundle bundle)
{
    /* 中略 */

    // イベントハンドラ with ラムダ式
    button.Click += (sender, args) =>
    {
        ShowToast("Button clicked!");
    };
}

// メソッド自体もラムダ式で書ける
private void ShowToast(string text) =>
    Toast.MakeText(this, text, ToastLength.Short).Show();

 LINQ to Objectsは、コレクションに対する一般的な操作を集約したライブラリです。AndroidのJavaでは、外部ライブラリ(Lightweight-Stream-API31など)や、Stream API(Java8を有効化すると使用可能)で同様の機能を利用できますが、LINQはそれらよりも豊富な機能を提供します。たとえばLINQは、Intersect(積集合)やUnion(内部結合)などの少し複雑な合成処理も行えます32

リスト1.6: LINQ to Objectsの例(C#)

// 0〜9 を、偶数値だけ抽出して、降順にソートして、値を10倍する
var list = Enumerable.Range(0, 10)
  .Where(x => x % 2 == 0)
  .OrderByDescending(x => x)
  .Select(x => x * 10);
// 結果: 80 60 40 20 0

// ↑の結果と [40, 20, 10] との積集合を取得する
var intersections = list.Intersect(new[] {40, 20, 10});
// 結果: 40 20

LINQ to なになに

 LINQはLanguage INtegrated Queryの略で、「統合言語クエリ」が正式名称ですが、そう呼んでいる人は見たことがありません。LINQ自体は次のようなさまざまなデータソースに対応しており、それぞれ「LINQ to なになに」と命名されています。

 ・LINQ to Objects - 配列やリストなどの「オブジェクト」を操作対象とする

 ・LINQ to XML - XMLドキュメントを操作対象とする

 ・LINQ to SQL - SQL Serverデータベースを操作対象とする

 近年、特にXamarinによる開発では、LINQ to Objects以外を使用することはほとんどないでしょう。LINQにはクエリ式(クエリ構文)という、var addressName = from x in addressList select x.Name;のようにSQLライクに記述できる構文がありますが、こちらもあまり使われていないようです。

型推論と匿名型

 C#ではメソッド内のローカル変数において、変数の型宣言を省略できるvarキーワードが使えます。長いクラス名などを利用するときは、コードの可視性を上げることができます33

リスト1.7: 暗黙型の例(C#)

// Javaでは型宣言は省略できない(ダイヤモンド演算子で右辺は省略できる)
HashMap<String, List<Integer>> dic = new HashMap<>();
TooLoooongYourClass myClass = new TooLoooongYourClass();

// C#ではvarキーワードで型を推論推論させられる(ダイヤモンド演算子は使用できない)
var dic = new Dictionary<string, IList<int>>();
var myClass = new TooLoooongYourClass();

 匿名型は、スコープ内で定義して使えるデータ型です。タプルTupleのようなものですが、より明確にプロパティ名を定義できます。一般的には、LINQのメソッドチェーンの中で一時的に受け渡しされるデータの型としてよく使われます。

 リスト1.8は、["Ito", "Aoki", "Saito", "Takagi"]という文字列のリストから、偶数番目のものだけを抽出するLINQを使ったコードですが、文字列とそのインデックスのペアをnew {Name = n, Index = i + 1}という匿名型のデータを生成して後続に渡し、Where句で匿名型の.Indexプロパティを使用して偶数番目かどうかを判定しています。

リスト1.8: 匿名型の例(C#)

var names = new[] {"Ito", "Aoki", "Saito", "Takagi"}
    .Select((n, i) => new {Name = n, Index = i + 1})
    .Where(x => x.Index % 2 == 0)
    .Select(x => x.Name);
// 結果: Aoki, Takagi

少しNull安全

 リスト1.9とリスト1.10は、ありがちなnullチェックをJavaとC#で比較したものです。C#では、null条件演算子(?.)や null合体演算子(??)を使って、Javaに比べて短いコードで比較的安全にnullを判定できます。

リスト1.9: nullとの付き合いの例(Java)

 1: if (hoge != null) {
 2:     hoge.DoSomething();
 3: }
 4:
 5: String text = "none";
 6: if (hoge != null && hoge.fuga != null) {
 7:     text = hoge.fuga.ToString();
 8: }

リスト1.10: nullとの付き合いの例(C#)

 1: hoge?.DoSomething();
 2:
 3: var text = hoge?.fuga?.ToString() ?? "none";

 ただし、KotlinやSwiftなどのように厳密にNullを区別しているわけではありません。通常のクラスは、常にnullになりえることに注意する必要があります。(プリミティブなデータ型(int, floatなど)や構造体の所謂「値型(ValueType)」は通常nullにはできません。)

C# vs Kotlin

 Kotlin34は、Androidアプリ開発者が今すぐ乗り換えることができる、Javaと非常に親和性の高い言語です。2017年5月、GoogleがAndroidアプリ開発言語に選定したことでも注目度が増しています。モダンな言語仕様で、Androidアプリ開発者に人気の高い言語です。主な特徴は次のとおりです35

 ・セミコロンレスなどの簡潔な構文

 ・async/await - asynchronous coroutineのひとつとして、1.1で搭載予定36

 ・ラムダ式 - 使用可能

 ・型推論と匿名型37- 型推論はvar(再代入可)やval(再代入不可)が使用可能

 ・Null安全 - デフォルトでnull代入不可。smart cast(Flow-Sensitive Type)による簡潔かつ安全なnull判定

 ・パターンマッチで、柔軟な条件判定とデータの抽出が可能

 このように、「言語のモダンさ」だけでいえばKotlinの方が優れています。Androidアプリだけを開発するのであれば、間違いなく積極的に採用していきたい言語です。

 Kotlinはまだ歴史が短いため今後のバージョンアップで後方互換製を重視するのか、あるいはSwiftのように敢えて破壊的変更を伴うバージョンアップによってモダンさを維持するのか分かりません。C#は、下位互換性を維持したままモダンな要素を取り入れる方式で進化してきましたし、今後もそうだと思います。また、JVMに依存するKotlinと違って、.NETフレームワーク/Monoと共に進化できる強みがあります。

Xamarinが対応しているC#のバージョン

 2017年6月現在、C#の最新バージョンは「7.0」です38。Xamarin製品群の最新バージョンはこのC# 7.0に対応しており、Visual Studio 2017やVisual Studio for Macで最新の言語機能を使用できます。C# 6.0まではC#のコンパイラが.NET FrameworkとMonoで異なっていたため、開発環境により最新言語への対応に時間差がありましたが、C# 7.0からはどちらもRoslyn/cscを使用するようになり、今後の言語のバージョンアップ39には、ほぼ時間差なく使用できると期待できます。

1. https://www.xamarin.com/platform

2. http://www.buildinsider.net/mobile/insidexamarin

3. https://www.visualstudio.com/ja-jp/news/releasenotes/vs2017-mac-relnotes

4. https://developer.xamarin.com/guides/android/advanced_topics/working_
with_androidmanifest.xml/

5. https://speakerdeck.com/atsushieno/generics-on-xamarin-products によれば、Java8の新機能である「interfaceのデフォルト実装」をAndroid APIも利用しはじめており、同機能がないC# 7ではそれらのAPIはXamarinには提供されない、つまり厳密にはAPI100%対応ではない、とのことです。

6. Visual Studio for Macとの区別の為にこう書いています。実際にこのように呼んでいる人はたぶん居ません。

7. 画面のレイアウトファイルも拡張子こそ「.axml」ですが中身は同じなので、Android Studioでも使用できます。

8. https://www.jetbrains.com/resharper/

9. Windows、Linuxなどさまざまなプラットフォームで動作するオープンソースのIDE。http://www.monodevelop.com/

10. Android SDKのツール類(SDK Manager、Emulator Manager等)は、Visual Studio for Mac/Xamarin Studioのメニューから呼び出せます。が、SDK ManagerはAndroid Oサポートの関係でSDK Tools r25.3.1に切り替える頃にはスタンドアローン型GUIとしてGoogleから提供されなくなります。Xamarin StudioやVisual Studioで、Android Studioと同様に、SDK Managerの代わりとなる特化したGUIメニューが提供されることが期待されます。

11. https://www.jetbrains.com/rider/

12. もしかしたら、現在難民となっているLinux使用者への助け舟になるのかも知れませんね!

13. https://msdn.microsoft.com/ja-jp/library/dd393574.aspx

14. http://www.mono-project.com/docs/tools+libraries/tools/xbuild/

15. https://www.nuget.org/

16. https://components.xamarin.com/

17. Ver6.4までは全サービスがひとつのライブラリに含まれていましたが、dexファイルの許容最大メソッド数である65,536を超えやすく、ProGuardやMultidexでの対策が必要なケースが多かったため、Ver6.5から現在の分割方式になりました。

18. https://developer.android.com/topic/instant-apps/

19. https://developer.android.com/topic/instant-apps/prepare.html

20. https://twitter.com/atsushieno/status/867436895835377664

21. https://developer.xamarin.com/guides/android/advanced_topics/binding-a-java-library/

22. http://www.buildinsider.net/mobile/insidexamarin/10

23. https://developer.xamarin.com/guides/ios/advanced_topics/binding_objective-c/

24. http://stiletto.bendb.com/

25. http://square.github.io/dagger/

26. http://paulcbetts.github.io/refit/

27. http://square.github.io/retrofit/

28. await演算子はasync修飾子を付けたメソッド内でのみ使用可能です。またawaitを付けて呼び出せるのは、C# 6ではTaskまたはTask<T>を返すメソッドのみです。

29. https://github.com/evant/gradle-retrolambda

30. 2017年3月、Jackツールチェインは非推奨になってしまいました。 https://android-developers.googleblog.com/2017/03/future-of-java-8-language-feature.html

31. https://github.com/aNNiMON/Lightweight-Stream-API

32. http://qiita.com/amay077/items/9d2941283c4a5f61f302

33. JavaでもLombok(https://projectlombok.org/)を導入すると、valキーワードによる型推論が使用可能になります。

34. https://kotlinlang.org/

35. https://developer.android.com/kotlin/

36. 2017年3月にリリースされました。

37. リスト1.8で紹介したようなC#の匿名型の使い方は、Kotlinではタプルや名前付きタプルが同じ役割であろうと思われます(筆者未検証)。

38. https://blogs.msdn.microsoft.com/dotnet/2017/03/09/new-features-in-c-7-0/

39. https://github.com/dotnet/roslyn/blob/master/docs/Language%20Feature%20Status.md 。日本語での解説は https://www.slideshare.net/decode2017/tl06-c-c が詳しいです。

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