D8コンパイラをXamarin.Android(d15-5以降)で使う

今からだいたい1ヶ月前に、Googleが新しいDexコンパイラd8を紹介していました。

android-developers.googleblog.com

d8Android SDKの既存のツールで言えばdxに相当する機能を実装しています。dxはJava bytecode (*.class)をDalvik bytecode (*.dex)に変換するコンパイラですね。通常はclasses.dexをビルドするために使われています(が、大抵の人は意識していないでしょう)。

Android Studio 3.0のbetaでは既にこのd8を有効に出来ます。既に使えるならXamarin.Androidでも使えるようにしたいところです。ただ、リリース当初はd8のソースが見当たらず、しばらく待っていました。その後、d8がr8のリポジトリに含まれていると教えてもらったので、試しに使ってみたら上手くいきました。

というわけで、dxの代わりにr8を使うようなNuGetパッケージを作っておきました。ソース…と言うほどのものは無いのですが…はここにあります。ちなみにxamarin-androidに加えた変更もかなり小さいものです。

github.com

xamarin-android-d8-build をpackages.config に追加するとインストールできます(このパッケージはまだリスティングに載せていないので、パッケージマネージャのUIで検索しても出てきません)。パッケージをインストールするだけでMSBuildプロパティが追加されるだけで、Xamarin.Androidアプリケーション以外で副作用は無いはずです。

このパッケージですが、実のところXamarin.Androidを製品版から使用している人には使えません。xamarin-androidをmasterからビルドしている人は今すぐ使えます。そうでない人はd15-5ブランチがalpha channelに降ってきてから利用できるようになります。ちなみに今はd15-3がstable、d15-4がalphaですね。

これ自体は大したコードの変更を伴っていないのに、なぜこんな根本的な差し替えが可能なのでしょうか? それは、Xamarin.AndroidMSBuildタスクを読み解くことが出来れば誰にでも出来ます(MSBuildタスクはデバッグビルドのサポート固有の部分以外はgithubで公開されています)。dx.jarを呼び出す部分はCompileToDalvikターゲットであり、CompileToDalvikタスクでコマンドラインを生成しています。ここではdx.jarはDxJarPathプロパティ、その引数はDxExtraArgumentsプロパティで指定されています。

今回のNuGetパッケージはこれらのプロパティをオーバーライドして、同梱のr8.jarを使用するように指定しているだけです。ちなみにdx.jarを使う場合は--dex--no-strictというオプションが必要なので、これらはDxExtraArgumentsのデフォルト値となっています。r8を既存のCompileToDalvikタスクで使うにはこれらが邪魔だったので、消す作業をした、というわけです。

DxJarPathはもともとカスタマイズ可能になっていたので、全体的な変更も些少なものです。

…というわけで、ごく簡単なハックですが、MSBuildタスクをどうやってカスタマイズすればいいか、簡単に解説できるネタだったのでまとめてみました。