Xamarinの新しい話とMonoの深い話 @ dotnetConfJapan2016

セッションの詳細が決まった頃にはとっくに満員になっていて書いてもしょうがないと思って粛々と登場したのですが、表題のイベントで会社の先輩(自称)としゃべってきました。視覚的な情報は 先輩 がまとめています。って仕事早いな!

blogs.msdn.microsoft.com

本当はMonoの深い話だけのつもりだったのですが、結果的にむしろMonoの話はわたしのほうが丸投げするかたちになってしまいました。スライドには、わたしが補足で作ってきたもののしゃべる機会が無かった「Monoつうのは本来だな…」という話題が含まれています。

本当はLinkerの歴史(Moonlightの頃からある)とか実装の使われ方とかも説明したかったのですが、ちょっと時間的に無理でしたね。Miguelが本家dotnetconfで紹介していたAdvanced Linkingはこの辺にソースがあるので、興味ある方はどうぞ。Nugetizer 3000の話も尻切れトンボになっちゃいましたね…

2人セッションの準備のために、事前にMiguelのセッションの内容を説明していたのですが、あのセッション、そこそこ難しい話をしていたのですね。1人でしゃべるのであればそこまで意識しなかったであろう(というかしゃべるつもりすらなかった)根本的な仕組みの話も、ちゃんと説明せなあかんのだろうなあという気付きを得ました。

そんなわけで、主に(というかほとんど)「漫才たのしかったです」「Eテレでしたね」みたいな感想をいただいたのも、実のところ概ね予想通りで、初めての試みで手探りでしたが悪くはなかったのかなと思います(…って書いてて気づいたけど漫才はこの前もやった気がしますね…!)

そんなわけで次は(他に入らなければ)準備中のイベントでDeep Diveなネタを今までどおり単独で話すことになると思います(反省の色がまるで無い)。決まったらまたお知らせします。

Long Live, Xamarin

これはいわゆる「転職ブログエントリ」みたいなノリで書いていますが、まあご存知の方はご存知の通り、転職ではありません。

日本時間ではもう7月になってしまいましたが、今日、Xamarinが正式に最後の営業日を迎えます。

設立から5年と2ヶ月弱、わたしが在籍していたのは4年と11ヶ月でしたが、こうして過ぎ去ってみると、あっという間であったように思えてきますね。5年前には、わたしはまだ所在不明の国籍不明ですらなかったわけで、5年間というのがいかに短いようで長い間であったか気付かされます。5年前なんてAndroid 3.xの時代だったんですよね。

わたし自身は、今後も、業務としては同じXamarinチームのまま、所属としてはMicrosoftで仕事するということになります。

Xamarinがどんな5年間を経てきたのかは、もう 十分すぎる くらい*1 書かれた と思うので、ここで繰り返すことはしませんが、いい機会だと思うので、Xamarinみたいな会社で仕事するって、どんな感じだったのか、思いつく感じで書いてみようと思います。

Xamarinは、もともと世界中に散らばっていたXimianが母体になって出来たMonoチームから誕生したこともあって、わたしのように各国に1人、2人くらいしかいないメンバーが数多く存在していました。こういったメンバーは、Novell時代のように現地法人があるわけではないので、個別にXamarinの国際メンバーとして仕事することになります。建前上は正社員ではない扱いですね。仕事は以前と何も変わりませんでしたが。基本的に自宅で作業するわけですが、近所のコワーキングスペースにブースを借りて仕事しているメンバーもいました。もちろんカフェもワークスペースです。

作業時間も主に日が暮れてから集中的に始まり(それくらいから欧州メンバーが仕事を始める、ただしこちらは間に晩飯あるいは「昼飯」が入る感じ)、丑三つ時くらいまで、遅いとすっかり太陽が出てから寝る感じです。まあやる気のない時はさっさと切り上げますが。

日本法人は無いので、給料もコンサルティング費用みたいな感じで毎月請求します。当然ながら源泉徴収もないので、2〜3月には自分で確定申告します(そして毎年のように担当者に戸惑われる)。そうすると事前にIBANなどを通知していた日本の銀行の口座にUSDから変換された日本円(ryが入ってくる感じです(もちろんUSDの口座にふりこんでもらっても良かったでしょう)。

Xamarinのオフィスは、ボストンから始まって(Ximianのスタート地点です)、ほどなくサンフランシスコに営業拠点を設置しました。Miguelはボストンで開発をリードし、Natはサンフランシスコでその他をリードする、というやり方です。実際にはサンフランシスコにも少なからず開発者がいました。Formsチームはだいたいあちらにいます。

わたしは年に1回くらいミーティングに行く程度ですが(それにしてはサンフランシスコオフィスに遊びに行く機会が多かった気がする)、アメリカのベンチャー企業のオフィスなので、日本の退屈なオフィスとは全然雰囲気が違います(日本にも居心地の良さそうなオフィスは増えてきましたが)。

あと、リモートメンバーが少なからずいるので、オフィスの近くにアパートを借りていて、日々誰かしら関係者がそこに寝泊まりしていたものです(今どうなっているのか知りませんが)。特にボストン方面からは、行くたびに「長期滞在していけばいいのに」みたいに言われたものでした(実際春先頃にそうするつもりでもあったのですが、DroidKaigiで忙しかったのと、その直後に買収のドタバタがあったわけで…)。米国に移住するメンバーが、部屋探しの間しばらく泊まっているなんてこともよくありました。

勤務条件も、緩やかなものでした。「みんな年に4週間の休みがある。」「体調が悪かったら休め。休暇を使う必要はない。」といった感じで、2週間くらいは外国旅行に出るメンバーはそこそこいました(米国メンバーは1週間程度しか休まないワーカホリックも少なくないですが)。わたしはというと、大して旅行に出ることもなく12月の半分くらいを休みにして、好き放題コードやら無駄に長いブログやらを書いて過ごすみたいな感じでした。後半になるとBambooHRみたいなのを導入して、結局そのシステムが「ざっくり休む」みたいなのを前提としていなくて、普通に休みを数える普通の会社になった感はあります。人数も増えて、「普通の」会社から流れ込んでくる人も増えたということですね。

あとは、わたし個人では、Xamarinにいる間に、台湾で現地の開発者コミュニティなどと交流して過ごすようになりました(もちろん仕事はネットワークさえあればどこでも出来るわけです)。台湾は開放文化(オープンソース文化)に積極的で、日本よりもおおらかなので(日本に比べて格段に足の引っ張り合いがない文化です)、わたしもいずれ日本を見捨てて台湾で過ごそうかとも思っているのですが、あまり真面目に中国語を勉強せずに片言だけで過ごしてきたこともあるので、その辺は今後の課題でしょうか。

オープンソースの.NETに興味があるコミュニティは、あちらではさらに小さく、MonoやXamarinだけでなくその辺も広めようとしたこともあったのですが、割と道なき道を歩いている感はありましたというかあります。この辺はMS台湾でも広げていきたいようで、わたしも積極的に支援していこうと考えています。コミュニティ活動は、これまでも基本的に業務外で回せていたので、今後もそうしていきたいところです(日本法人から面倒な横槍が入らなければ、ですが…わたしとしては社内外を問わず「日本も台湾も支援する」か「どちらも支援しない」かの二択です)。他のアジア諸国までは、現時点では手をのばせていません。大陸のMSなんかは台湾法人から見ても「よくわからん」そうで…

…というわけで、後半は振り返りというか今後みたいな話になってしまいましたが、まあこんな感じで、国外企業の仕事も適当にできるものだと思います。英語は…まあ読み書きはさすがにそれなりに出来ないと厳しいですが、英会話は全然ダメなレベルから入っても(少なくとも首の皮がつながっている程度には)何とかなっているので、まあ何とかなるのではないでしょうか。他の人にも是非チャレンジしてもらえればと思います。

*1:これはほとんど自分の話だけど

Xamarin.Android SDK解説 @技術書典 & @YAP(achimon)C Asia Hachioji etc.

これからしばらくの間、アジアでXamarin.Android SDKを紹介する活動が(わたしとしては)多くなりそうです。

まず、6/25(土)の技術書典で新しく発行される、TechBoosterの "AZ異本 grimoire of android" にひとつ寄稿しました(Xamarinで書けという(圧)がかかったともいう)。

techbooster.github.io

表紙のヤバさがヤバい。

5月に書いていたのですが、たいへん新しいネタで、書いていく傍らで変更がどんどん加えられ、動いているとされていたものが動いていないとか、いろいろチャレンジングな状況でした。でもまあ一応「この辺はあまりブレないだろう」というラインを中心に、基礎から内部的な解説まで、いろいろまとめています。

30ページくらいあって、同人誌の原稿としてはけっこう長々と書いたと思います。ただ、これでもだいぶ書くべきを端折っているんですよね…(力尽きて)。本当ならXamarin.Android徹底解説という題にするつもりだったのですが、全然徹底しなかったので、そこは外しました…

ちなみに、わたし技術書典のスタッフとしても動いていて、当日も現場にいる予定なので、ぜひ遊びに来てやってください。

techbookfest.org

おまけですが、6/9に、台北のFLOSSのグループH4で、技術書典や(原稿書きに使っている)Re:VIEWがどういうものなのか、という紹介をしてきたので、これもついでに上げておきます。(ざっくり10分程度のトークです)

speakerdeck.com

それから、その翌週の7/2(土)に、今度はYAP(achimon)C Asia Hachioji in Shinagawaという、どこなのかよくわからないイベントで、そのXamarin.Android SDKの解説セッションをやります。

yapcasia8oji-2016mid.hachiojipm.org

YAPC Asiaの後継イベントだけど、今度はごく少人数(というか基本的に1人?)でイベントを回すそうで、なかなか大変そうなところですが、会場に品川MS神社を借りてMS信者のおまいらがおまいりできるそうですので、興味がありましたらぜひ聞きに来てください。

本当は↑の執筆内容をもとに、念入りに話したいところではあるのですが、30分だけなので、いろいろ簡素な(でも平易ではない)内容になると思います。できればデモも動かしたいのですが、SDK本体の完成度次第と言ったところでしょうか(!)

最後に、8/27に、Microsoft台湾のコミュニティマネージャの人に相談されて、あちらのMVP Summitのようなもので、同じくXamarin.Android SDKの話をしてくることになっているのですが、これは内容的にはYAP*Cとほぼ同じにしようと思っています(時間は40分あるのですが、英語になるので密度は多分下げざるを得ないでしょう)。これも興味がありましたらぜひ来てください(台北ですが)。

JXUG#13 rejected meetup

#JXUG13 の参加申込み状況がえらいことになってますね。

jxug.connpass.com

参加したいけど出来ない感じの皆さんは残念ですね。

せっかく興味がある人が多い「ように見える」のに何もしないのはちょっともったいないので、前日の公開ですが、参加したかった皆さんのうち、Xamarinに興味がある方がいたら、適当に来てもらえれば相談などに乗る集まりをやろうと思います。個人的には以下のような目的だと面白いかもしれないと思いますが、目的を特定するつもりはありません(とりあえず、どれもJXUGではやらなそうなことです)

  • (xamarin-android、xamarin-macios、Xamarin.Forms)をビルド/ハックしてみる
  • Xamarin Workbooksで遊んでみる
  • Xamarin Forms Previewerで遊んでみる

場所は、わたしが上記の集まりに冒頭だけ参加しないといけないこともあるので、会場であるMicrosoft品川オフィス(いわゆるSGT)の2階にある cafe de crieあたりがいいかと思っています。もしいっぱいだったら周辺のカフェのどこかにします。(Twitter/@atsushieno でお知らせします) 誰も来なければ1人でもくもく作業していると思います。目印にこいつを置いておくので、適当に探して下さい。

時間も、適当ですが、上記の都合で、13:30スタートくらいだといいかなと思っています。

注意点ですが、Xamarin platformsはビルド時に大量のダウンロードを必要とするものです。自宅等で必要なセットアップを済ませてから来て下さい。

  • Xamarin Workbooks、Xamarin Forms Previewerを使うには、alpha previewが必要になります。
  • xamarin-android:
    • githubからxamarin-androidを --recursive でcloneしておく (特に、monoのチェックアウトが必要になるので、時間がかかる)
    • make prepareAndroid SDK / NDKのダウンロードをすませておく(現状ローカルにあっても使われません)
  • xamarin-macios:
    • githubからxamarin-androidを --recursive でcloneしておく(fsharpやllvmが必要になる)
    • Xcode 7.3以降が必要になるので、アップデートしておく(4GBくらいある)
  • Xamarin.Forms:
    • 一度コードをチェックアウトした後ビルドを行っておきましょう。中でXamarin.Androidコンポーネントを参照している部分があって、それら は内部的にAndroid SDKのサイトから依存関係のパッケージをダウンロードします。これがけっこう待たされるはずです。
    • フルビルドにはVisual Studio 2015が必要ということになっています(WP/UWPなどWindowsにしか無いものがあるため)。また、VS2015の追加アドインが必要になるようなので、README.mdをチェックして追加しておきましょう。

何か注意事項を思いついたら追記していきます。

オープンソース化されたXamarin.Androidの概要

追記: この辺の詳細はEssential Xamarin -Yin/陰-で一章使ってまとめてあるので、興味のある方はどうぞ。

何がオープンソース化されたのか

Xamarin Evolve 2016で、以下のリポジトリがMITライセンスで公開されました。

XamarinComponentsは、どちらかといえば(以前からある)pluginsの内容を吸収した、他リポジトリにリンクする、ポータルのようなかたちになっています。

今回オープンソース化されたのは、Xamarin platform SDKという部分で、これは一言で言えば「スタンドアローンで実行可能なリリースビルドのアプリケーションをビルドできる環境」になります。ビルドして実行するコードは提供するよ、それ以上の開発環境は提供しないよ、ということですね。Xamarin Studioはオープンソースになっていません(言うまでもないですがMonoDevelopは昔からオープンソースです)。アプリケーションをデバッグ実行したい場合は、相変わらずプロプラエタリのXamarin StudioかVisual Studioを使う、ということになります(ちとがっかり)。

これに伴って、Xamarin.iOSもXamarin.AndroidもXamarin.Formsも、大幅なリポジトリの再構成を余儀なくされており、またプロプラエタリコードの切り離し作業もおこなわれているので、率直に言えば開発者もまだ何が起こっているのかよくわからない状態です。ビルドも公式にはMacしかサポートされておらず、他のメンバーがせっせと壊したLinuxビルドを試行錯誤して直す作業をわたしがやったりしていました(というか今でもしている感じですね)。

ともあれ、今公開されてあるソースは、昔からあるやつのコードとは多少違うものだ、ということです。

そんなわけで、ソースが公開されたので、今回はこれまで詳しく書いていなかったXamarin.Androidの細かい部品について、ちまちまと書いていこうと思います。あんまり読みやすくまとめようという感じではなく、思いついたことを書き並べている感じです。

xamarin-androidの使い方

(この1行は後で消しますが)現状ではビルドされるファイルが不足していて、動かせる環境にないのですが、それでは目的が達成できていないので、今後数日のうちに修正されていくと思います。

Xamarin.Android SDKを使うには、コンソールからプロジェクトのcsprojをビルドするしかありません。

xamarin-androidリポジトリをチェックアウトすると、tools/scripts/xabuild というスクリプトがあり、これが必要な環境変数などをセットアップしつつxbuildを呼び出すように作られています。xbuildの代わりにこれを使うと良いです。(もちろん、無償化公表前のXamarin.Androidとは異なり、コンソールからビルドするのにProfessionalライセンスを必要とするようなことは、もはやありません。)

基本的には、MSBuildタスクを含むXamarin.Android.Build.Tasks.dllが、xbuildがMSBuild extension DLLを解決するパス(MSBuildExtensionPaths)に存在していれば、あとはXamarin.Androidのプロジェクトをビルドするために必要なXamarin.Android.{CSharp|FSharp}.targetsファイルがそのDLLの中に含まれるEmbeddedResourceとして解決されて、Xamarin.Android固有のタスク(BuildApkなど)を処理できるようになるはずです。

最新Xamarin.Androidの構成要素

monoランタイム

monoランタイムはxamarin-androidのgit submoduleとしてチェックアウトすることになります。

Xamarin.Androidは内部的にNDKでビルドしたmonoランタイムを使用するため、アーキテクチャ依存のネイティブライブラリ libmonosgen-2.0.so を含むことになるわけですが、公表時点でのxamarin-androidは、(あろうことか)デフォルトではarmeabiでのみビルドされます。まあこれはAndroid開発者のことを全く理解していないAndroidチームのやる気の無さの表れというよりは、OSS化の方針が決まってからEvolveまでほとんど時間がなかったからというのが大きいです。

xamarin-android内部では、この embedded mono runtime とAndroidプラットフォームを結びつける libmonodroid.so が使われています。xamarin-android自身は、monoランタイムとJNIのinteropを実現しているわけではなく、Androidアプリケーションのブートストラップの過程でmonoランタイムを初期化して利用可能にするためのコードなどが含まれています(Java.Interopモジュールの登場以前はこの辺は一体化していたのですが、Java.Interopの導入以降は、そういう構成になったようです)。

バインディング作成ツール

OSS版Xamarin.Androidには、Androidプロジェクトを新規作成するためのツールは含まれていません(!)が、IDEが無くても、バインディング ライブラリは、自前で作成することができます(!!)。

バインディング ライブラリは、Xamarin.Androidにおける機能の一部にすぎませんが、Mono.Android.dllはこのバインディング ライブラリをサポートする機能に基づいて作られているものであり、Xamarin.Androidの根幹を成す機能であると言えます。

バインディングDLLはどのように作成されているのでしょうか? 基本的な流れは、次のようになっています。

  • jar2xml: Javaライブラリ(jar)を解析して、API定義XMLを生成する
  • generator: API定義に対する修正を適用しながら、C#ソースを生成する
  • csc/mcs: C#ソースをビルドする

最初の部分では、膨大なAPI定義のXMLを生成します。C#コードをAPI定義とするXamarin.iOSとは全然違いますね。なぜこんな設計になっているかというと、これはもともと必要ないはずのツールだったのです。Android AOSPにはXMLベースのAPI定義が含まれており、Android 3.0がクローズドソースで公開されるようになるまでは、Xamarin.AndroidはAOSPのXML定義を解析するツール(generator.exe)のみを使用していました。それがクローズドソースのandroid.jarが登場するようになり、このままでは対応できない状態がいつまで続くか分からなかったので、jarファイルを開いて解析できるツールが必要になった、というわけです。

また、この頃からAndroid supportライブラリなどが登場し、外部ライブラリのAPIを簡単に使えるようにするための汎用的な仕組みが求められてきていました。そのため、それまでandroid.jarだけを相手にしていれば良かっただけのバインディング生成ツールに、さまざまな修正を加えてそれなりに一般化することになりました。この時点で、たとえば、generatorはjarだけでなくDLLも解析しなければならなくなっています(APIの階層構造を把握するためには、全てのjarが必要になるわけですが、依存ライブラリのjarは無いかもしれないですし、そもそもバインドされていないかもしれませんし、DLL上では全く別の名前になっているかもしれません)。

既にそれまでの時点でgeneratorはかなり複雑化していたところに屋上屋を架すことになって、今は割と「誰も触りたくない」部品になっています。残念ながら今のところこれを書き直す計画はありません。

class-parse: 新しいAPI抽出ツール

実は、この最初の部分については、次回リリースから選択肢が増えます。この選択肢は、バインディング プロジェクト ファイル(.csproj。F#はバインディングライブラリの作成ではサポートされていません)にMSBuildプロパティAndroidClassParserで制御できます。そこには、次の値のいずれかを指定します。

  • jar2xml
  • class-parse

jar2xmlJavaのリフレクションとバイトコード操作ライブラリASMを使用して作成されていましたが、class-parseC#で実装されています。jar2xmlが抱えていた絶妙な問題として、Javaリフレクションによって取得されるAPIは、そのコードを実行しているJVMに束縛されてしまう、というものがあります(.NETのSystem.Reflection APIと同じような問題ですね)。Mono.Android.dllには、本来android.jarに無いはずのJava7のAPIへのバインディングが含まれている、というバグがあって、これを解決するのはjar2xmlでは根本的に無理があった(出来なくはないが設計が全く異なるものになる)、というわけです。IKVMのコードを使いまわしたり、javapの出力を利用してはどうか、といったアイディアがいくつか出てきましたが、最終的にC#で書かれたシンプルなバイトコードパーサーを作って終わりということになりました。

もっとも、class-parseが銀の弾丸となったわけでは全くありませんでした。jar2xmlに知らないうちに頼りきっていたわれわれが直面した問題は、バイトコード解析だけではきちんとしたクラス階層の処理ができない、ということです。たとえば、Javaではpublic型をnon-public型から派生できるわけですが、java.lang.reflectはそれをうまく隠してくれていたわけです。class-parseは愚直なパーサーで、その辺りを全く解決しませんでした。

class-parseの開発時は、jar2xmlの出力フォーマットとの互換性も全く気にしていなかったため(generator.exeも拡張してclass-parseフォーマットもサポートすればいい、程度に考えていました)、生成されたXMLに対してさらにMetadata.xmlなどによってAPI定義を修正しなければならないという問題もありました。

また、AOSP由来のXMLでは、派生クラスでオーバーライドされた実装メソッドなどの情報は含まれていませんが、class-parseは愚直なバイトコードパーサーなので、その辺の事情を全く考慮しません。つまりclass-parseの出力は情報の構成が変わってしまっているわけで、そのままgeneratorに渡したわれわれが目にしたのは、大量のコンパイルできないC#コードでした。

結局のところ、今まで通りgeneratorに仕事してもらうためには、class-parseの出力を変換して正常化しなければなりませんでした。以上のような問題をまとめて解決するために、新たにapi-xml-adjusterというツールが作成されました。これは、class-parseの情報をもとにクラスの階層構造を解決して適切な修正を加えつつ、API XMLの構造を変換する役割を分担します。

generator

generatorは以上のような過程を経て生成されたAPI定義XML (バインディング ライブラリ プロジェクトをビルドすると、obj/* 以下に、api.xmlというファイルが生成されるはずです)をもとに、指定されたMetadata API fixup(Metadata.xmlなど)を適用して、クラス階層構造を構築し、インターフェース メソッドなどを抽象クラスで適宜追加し、プロパティやイベントにメンバーを変換・追加して、最終的なDLLのソースを生成します。コードの生成はTextWriter.WriteLineで行っています。いちいちCodeDomなんて使っていません(CodeDomはResource.designer.cs/.fsの生成時に使っています)。

ここ数ヶ月の間に追加された地味な機能のひとつに、Android Annotationsのサポートがあって、たとえばRequirePermissionなどのアノテーションJavaソースに追加してビルドしてさらにきちんとaarにパッケージされたものについては、それを読み込んだ上で対応するattributeを追加するようにしたはずなのですが、肝心のandroid.jarに対応するAndroid SDKのplatform-tools/api/annotations.zip の内容が、いつまで経ってもLollipopの内容のままで止まっていて、たとえばandroid.media.midiAPIに対応するIntDefなどが追加されないままなので、Google仕事しろと思いながら日の目を見ない機能のひとつとなっています。

あとさらに細かすぎて伝わらない追加機能として、同じくAndroid SDKのplatform-tools/apiにある api-versions.xml を読み込んで、ApiSinceというattributeを生成するようにしたのですが、IDE側でこれに対応するメッセージが表示されているかどうかは未確認です(出るようにする、とは言っていました)。使っているAPIがminSdkVersionで指定したバージョンにに無く、コード上でバージョンチェックも通していないと、実行時エラーになってしまうので、簡単に回避できるようにはしたいですよね。

MSBuildタスク

Xamarin.AndroidMSBuildタスク…というより正確には一連のタスク群ですが…は、xbuildあるいはMSBuildでXamarin.Androidのプロジェクトをビルドするために必要なもので、Xamarin.Android.Build.Tasks.dllに含まれています。

このMSBuildタスク群の中には、Androidアプリケーションのプロジェクトで使われるAaptやBuildApkといったタスクの他、Binding projectのためのJarToXmlやBindingsGeneratorといったタスクも含まれています。

ただ、これまでの製品版と大きく異なる部分があって、fast deploymentなど、デバッグビルドのために存在していたタスクが、根こそぎプロプラエタリコードに持って行かれています(つまり、xamarin-androidには含まれていません)。やれやれですね。最新のプレビュー版にはInstant Runのcold swap相当のコードも実装してあるので、そこも公開されていると少し面白かったのですが。

ライブラリ

Mono.Android.dll

Mono.Android.dllは、複数のAndroidプラットフォームに対応する、やや特殊なバインディング ライブラリです。基本的に、サポートするAPI LevelごとにMono.Android.dllをビルドするのですが、それぞれのAPI Levelのandroid.jarの単純なバインディングを生成しているのではなく、それぞれのAPI Level以下のAPI定義をマージした上で、それに対するバインディングを生成しています。これは、Java言語のVMCLIでは、存在しないメソッドを解決するやり方が微妙に異なり、異なるプラットフォーム間でのandroid.jar(に対応するDalvikバイトコード)では生じない問題が、Mono.Android.dllでは生じることになるため、メソッドの定義を適宜前方互換にしてやるひつようがあるためである、と説明されています。

(その副作用で、いつまで経っても邪魔なOrg.Apache.Http*が消えない、といった問題を抱えています。)

以上のような理由などもあって、Mono.Android.dllのビルドは次のように、いくつかの点で特殊な構成になっています:

  • API定義XMLは、生成済みのものがリポジトリに含まれています。
    • API定義XMLは、それぞれのAPI Levelについて、class-parseとapi-xml-adjusterを使用して生成しますが、ビルド時には必要ありません(この辺りをハックしたい人や、新しいAPI Levelの登場時にそのサポートを追加したい人がやります)
  • Mono.Android.dllのビルドでは、まずapi-mergeが呼び出され、生成済みのAPI定義XMLがマージされ、その次にgeneratorがソースを生成し、最後にmcsがC#ソースをコンパイルします。
  • Mono.Android.dll用のメタデータXMLではなくCSVファイルになっています(!) これはXamarinのチーム内ではもともと使われていたフォーマットが、前述のような歴史的な理由で公開ツールとなった時に、仕様の不安定なCSVフォーマットは公開せずにXMLにするという決定が下されたためです。これはgenerator内部でXML形式に変換されて処理されます。

Mono.Android.dllのソースはgithub上の xamarin-android リポジトリにありますが、これは(名前から推測できる通り)Xamarin.Androidの(OSS版の)中心的なリポジトリです。Java.Interopやmonoをsubmoduleにしており、libmonodroidと呼ばれる、Androidアプリケーションのライフサイクル上で動作するmonoのホスティング環境を、Androidの各CPUアーキテクチャごとにビルドします。これには非常に時間がかかります。monoをひとつビルドするだけでも時間がかかるのに、それを(ランタイムだけとはいえ)アーキテクチャごとに行っているわけです。

5/4追記: ↑は現在は正確ではないかもしれません(libmonodroidがarmeabiのビルドしか行っていないため、多分こちらもarmeabiのみ)

xamarin-android リポジトリのソースは、大別して3つに分けられます。

  • ライブラリ (src/Mono.Android, src/Mono.Android.Export)
  • msbuildタスク
  • ビルドツール (ライブラリのソースを生成するツールなど)

Java.Interop.dll

Xamarin.Androidは、前回のstableリリースから、内部的な構成を大きく変えて、Mono.Android.dllの内部で、新しくJava.Interop.dllというライブラリを参照しています。ただし、公開APIの観点では、特に変更はありません。この新しいDLLは、Android APIバインディングを含まず、JNIを通じたJava APIの呼び出しを実現するために必要な機能だけを含むライブラリです。

Java.Interop.dllは、ほぼJNI呼び出し部分を最適化するために新規開発されたものであり(README.mdには「これはセカンドシステム症候群だ」と明言されています)、アプリケーション開発者が気にするべき部分は基本的にありません(もともと、このリポジトリは、メイン開発者が実験的な遊び場として使っていたという側面が大きいです)。

github上の Java.Interop リポジトリには、Java.Interop.dllと、これに基づくバインディングを作成するためのビルドツールの機能を実装するDLLがいくつか含まれています。現状、このリポジトリには、実際の製品で使われていない実験的なコードも数多く含まれているので、ここで全てを説明することはしません。

Java.Interopに含まれるソースは、大別して2つに分けられます。

  • ライブラリ。src/Java.Introp がその中心となる、Java.Introp.dllをビルドするためのプロジェクトです。
  • 公開ビルドツール用ライブラリ。Java APIバインディングを生成するためのツール(generator.exeなど)の機能を実装しているライブラリが、ここに含まれます。

この他に、ビルド時にしか使用しないツールなども含まれているのですが、重要性は低いので省略します(JNIEnvクラスの大量のメンバーを自動生成するツールなどがあります)。

Java.Interopは、開発者が何を思ったのかMSBuildの仕組みだけで全てビルドできるように複雑なビルドスクリプトをセットアップしたのですが、Windows上ではビルドしないわ、Linuxビルドも壊れているわ、Android SDKダウンロードまでスクリプト化したもののエラー トラッキングなどがまともに出来ないわ、カスタムSDKセットアップの柔軟性は微塵もないわで、端的に言ってこのビルドスクリプトは失敗作です。が現状それしかないので我慢するしか無い。

それはさておき、Java.Interop.dllがあると何が出来るかというと、たとえば、このコア部分だけを再利用したまま、全く別のAPIマッピング理論に基づくバインディングDLLを構築して使用することができます。当然ながら、そうすると過去の遺産は使えなくなるわけですが、support-v*ライブラリなどは自分でビルドすることもできるため、多くの人にとっては、あまり問題にならないでしょう。特にXamarinが提供してきたGoogleのライブラリに対するバインディングは、ソースが公開されることが期待されていますXamarinComponentsリポジトリでソースが公開されています。

(今のところ、XamarinでMono.Android.dllのAPIを抜本的に差し替える予定はありません。)

もちろん、Xamarin.AndroidAndroidアプリケーションを作るためのものであり、Androidアプリケーションは、Androidアプリケーションのライフサイクルに従ったものでなければなりません。既存のMono.Android.dllを使用しなくても、その根本に変わりはありません。

Xamarin.AndroidのN previewとJava8サポートについて

Google I/Oが近づいていますが、それに先立ってAndroid N previewが公開されていますね。既にpreview 2で、今後も5週間ごとにプレビューが出続けるというので、最新版Androidへの対応もだいぶやりやすくなったなという感じです。

そんなわけで、Xamarin.AndroidのMono.Android.dllも、OSS版xamarin-androidとXamarin.Androidの最新preview版は、最新のN preview 2まで対応しています。

Android N APIの最大の特徴は、Java8に対応したことですが、Xamarinユーザーにとっての恩恵はほぼ無いでしょう。

恩恵は無いのですが、Java8サポートは極めて難しい問題をもたらしました。インターフェースのデフォルトメソッドです。当初、N preview 1が登場した後、Mono.Android.dllはこれらについてもメソッドを生成していました。しかし、C#Javaとは異なり、デフォルトメソッドをサポートしません。当然ながら、インターフェースで定義されたメソッドは実装しなければならないことになります。Javaではこれは「やってもいいし、基本やらなくていい」ことなのに、C#になったとたん「やらなければならない」ことになるのは大変です。Java.Util.Iteratorなど、ごく基本的なインターフェースに、突如大量のメソッドが追加されて実装しなければならなくなったわけです。しかしインターフェースでAPIを定義しないと、誰も実装をオーバーライドできないことになります。

しばらく考えましたが、これはいくら何でもメソッドを追加するわけにはいかない、ということで、今のところ、デフォルトインターフェースメソッドは生成しないことにしました。通常のインターフェースメソッドでこういう「省略」を行うと、アプリケーション開発者がバインディングクラスの派生クラスを定義した時に生成するAndroid Callable Wrapper (ACW)が必要なインターフェースメソッドを生成せず、javacがコンパイルエラーを起こすことになるわけですが、インターフェースデフォルトメソッドの場合には問題になりません。

必要であれば、多少ややこしいコードを書く必要がありますが、手作業で追加することも一応可能です。

この辺は、OSS版xamarin-androidのrepoでRFC状態になっているので、何かしら意見があれば書いておいて下さい。

Java 8 Interface Binding · Issue #25 · xamarin/java.interop · GitHub

個人的には、まだどこにどう需要が出てくるかわからない現状で、中途半端なバインディング生成機能を実現したくない派です。現状ほぼメリットないし。

ちなみに、Android SDKでJava8が必要となるソースをコンパイルする際には、javacではなくjackという新しいGoogleコンパイラーを使用する必要がある(ということになっている)ことになっているのですが、

gfx.hatenablog.com

Xamarin.Androidが内部的に生成するコードはJava8の文法を使用しませんし、Java8のjavacをそのまま使っていても問題ないはずです。

JavaバイトコードをDalvikに変換するdx(dx.jar)には、--no-strictというオプションがあって、これを指定しないとJava8のバイトコードは拒絶されてしまうのですが、Xamarin.Androidでは内部的にこれを指定してdxを呼び出しています。

また、java8が問題になるのはproguard(およびそれを内部的に使用するmultidexのツールmainDexClasses)で、この古いツールはJava8に対応していないので、Xamarin.Androidではproguardの使用が指定されていたら、Java7にフォールバックします(実のところ、proguardの中身をいじって、参照されているデフォルトメソッドも全部スキャンするようにしてしまえば良いわけで、それほど対応が難しいとは思えないのですが、Googleはjackへの移行を促進するために政治的に非対応にしているんじゃないかと邪推しています)。

以上、インパクトがありそうでない、ちょっとしたXamarin.Android小ネタでした。

Xamarin Workbookの起源とインスタント実行の系譜

しばらく前、2月の半ば頃のことになりますが、MiguelがThe Evolution of Interactive C#というブログポストを投げていました。

The Evolution of Interactive C# - Miguel de Icaza

奇しくもわたしがDroidKaigi 2016でInstant Runについてのセッションを行う直前に公開されたもので、まあ幸い誰も気づかなかったと思いますが、完全にセッションのオチのネタバレだったんですね。 どうネタバレだったのかはスライドの最後の方を見てもらえれば分かると思いますが、

speakerdeck.com



最後に触れているContinuous Coding、けっこう新しいネタだったので、誰も知らなかったと思いますが、先のMiguelの投稿でも触れられているんですね。

(そういえば、このセッション資料、先日のGoogle Developers Summit TokyoでもGoogle Japanの人に紹介していただいたそうです。インスタント実行とは関係のない文脈だと思いますが、いずれにしろ役に立つネタで良かった^2)

さ て、先の投稿でWorkbookについて言及していることに気付きましたか? 実はシークレットでも何でもなかったんですね。まあ、せっかくなので、Miguelが書いたネタを日本語でなぞってみようと思います。

Xamarin Evolve 2014で発表されたXamarin Sketches、皆さん覚えているでしょうか?

atsushieno.hatenablog.com



Sketches はIDEのpane上に描画されたREPL環境で、XcodeのPlaygroundによく似ていますが(と言ってもそれを誰でも使えるかたちで実現した のはXamarinが先なんだよね、みたいな話は↑のエントリで説明してあります)、この時のcanvasは確かXamarin.Macがベースになって いて、Miguelはこれを「みんなが実際にやりたかったことは、単独のスケッチを実行することじゃなくて、アプリケーションを実際に動かしながら描画す ることだったから、あまり便利じゃなかった」と回想していますね。そして、それで作られたのがXamarin Inspectorだった、というわけです。

blog.xamarin.com


Inspector は、その名の通り、UI要素の内容をinspectするために作られたものですが(それ自体はTest Cloudの要素でもあるXamarin.UITestや、そもそもAndroid SDKにはhierarchy viewerなんかも同じですね)、その内容を動的に書き換える機能もREPLの統合によって実現しています。Inspectorが面白いのは、UI要素 をクエリする部分と描画する部分を切り分けていて、描画する部分は基本的にHTML Canvasでやっているんですね。

https://developer.xamarin.com/guides/cross-platform/inspector/Images/mac-3d-view-small.png



Inspectorはまだプレビューですが、基本的にこの辺りのプロジェクトは全て繋がっているわけです。

ところで、ハッカーの皆さんには割とよく知られていると思いますが、Jupyter Notebookというプロジェクトがありますよね。

Try Jupyter!


Jupyter Notebook、かつてIPython Notebookとして公開されていたプロジェクトですが(Miguelの先の投稿でIPythonって書いてあることに気付きました?)、まあ、要する に、これらは皆同じ「markdownの中に埋め込まれたREPL」の系譜です。Workbookの発想そのものは、特に新しいものじゃないんです。

Xamarin Workbook、面白いので、みんなこれを使ってドキュメントを書くといいと思います。と言いたいところなんですが、Workbookは Inspectorの一部で、Inspectorはオープンソースじゃないんですよね…まあ、コードが実行できなくても、サンプルコードフラグメントがド キュメントに含まれていて、それが実行可能だというのは有用なので、手元で動かせればいいという人はぜひ使ってみて下さい。

この Workbookも、Continuous Codingも、基盤として使用しているのはInspectorです。特にContinuous Codingはソースが公開されているので、使おうと思えば誰でも使えるということがみてとれるかと思います。けっこう夢がひろがりんぐだと思いませんか? (無理ですかそうですかそうですね。。)