読者です 読者をやめる 読者になる 読者になる

Xamarin.Android 7.0とJava8とproguard

少し前の話題になりますが、GoogleAndroid 7.0を不意打ちでリリースしてきましたね。

Xamarin.Androidチームでは、もう少し後に出るはずというスケジュール感覚で作業していたので、この不意打ちリリースに嫌な顔をしながら進行中のcycleのリリースにAndroid Nサポートを追加する作業を行っていたわけですが、公式ブログでもXamarin.Android 7.0としてリリースが告知されたようです。

blog.xamarin.com

この辺のversioningは、今回はtarget frameworkに合わせているようですね。

 

さて、Android Nの開発者向けの大きな特徴のひとつにJava8サポートがありますが、その辺でどんなインパクトがあるかは以前まとめた通りです。

atsushieno.hatenablog.com

バインディングまわりではinterface default methodsは現状相変わらず面倒なのですが、まあさすがに今JavaライブラリでAPI定義をJava8依存にしてターゲットをめちゃくちゃ限定することって、そうそう無いと思うんですよね*1。なわけでこの辺は(以前にも書いた通りですが)対応しても少し先送りしたいと思っています。

さて、ひとつ、今すぐ困りそうな問題が残っています。proguard対応です。これも上記エントリで言及したのですが、Android SDKに含まれているproguardは、Java8のバイトコードを処理できません。

ただ、Jack(新しいJava8対応コンパイラ)がproguardの代わりとなって処理できる機能を有しているように見えるものの、Android Studioでわたしが試してみた感じでは、proguardの設定ファイルに基づく処理は、相変わらずproguardが行っているようです。Gradleコンソールには以下のような出力が見えました。*2

ProGuard, version 5.2.1
Reading input...
Reading program jar [/home/atsushi/Desktop/Java8ProguardExperiment/app/build/intermediates/exploded-aar/com.android.support/support-compat/24.2.0/jars/classes.jar] (filtered)

 

このproguard、バージョンが5.2.1なんですね。Android SDK toolsに含まれるproguardは(25.1.7の時点で)バージョン4.7なので、どうやらこっちは使われていないようです。後方互換性のために残されているのでしょう。android-studioのディレクトリの中を探ると、android-studio/gradle/m2repository/net/sf/proguard/proguard-base/5.2.1/proguard-base-5.2.1.jar というファイルが見つかります。こちらが使われていると考えて良いのではないでしょうか。*3

いずれにせよ、Xamarin.Androidで使用しているのは、Android SDKに含まれるproguardなので、これではせっかくJava8に更新したのにproguardで躓いてしまってもったいないし、特に外部ライブラリがJava8でビルドされていると(android-support-v4…をsplitしたやつ…など)、proguardが使えなくなってしまいます。これでは困る。

そんなわけで、とりあえず、自前でビルドしたproguardをバンドルして、xamarin-androidの中でproguardを呼び出している部分で、代わりに呼び出すようにするパッチを作ったのですが、

github.com

proguardってGPLv2で配布されているんですよね。これを取り込んで配布したいかというと、出来れば回避したいので、少しやり方を変える必要があるかもしれません(無いかもしれません。そこはMicrosoftがどう変わったか次第)。

いずれにしろ、この変更が取り込まれてリリースされるまでには、まだ数ヶ月単位で待たないといけないはずなので、それまでの間このproguard問題を回避する方法を書いておこうと思います。proguard.jarのファイルパスは、MSBuildプロパティProguardJarPathで変更できます。なので、プロジェクトをMSBuildやxbuildでビルドするときに、/p:ProguardJarPath=/path/to/your/proguard.jar を指定してやると良いです。*4

コマンドラインでビルドなんかしないYO!という人は、.csprojを編集して、最初の<PropertyGroup>要素の下にでも <ProguardJarPath>/path/to/proguard.jar</ProguardJarPath>を追加しておけば良いでしょう。(git commitするなど、他所に持って行く前に消す必要はありますね)

実のところ、「これで動くはず」という以上の実験をしているわけではないので、これで試してみてダメだったら、わたしに適当に伝えてもらえれば、もう少し見てみます。

*1:ちなみに、Android Nのandroid.jarでは、このデフォルトメソッドが派生クラスでばんばん使われています。API定義上は少なくともJavaの文脈ではbreaking changeにはなっていないはず。

*2:Java8だとjackを使っているはずだけど、どうやってInstant Runとの整合性をもたせているんだろう…?という興味があって試している時に観測しました

*3:見当違いで、IntelliJ IDEAがpure Java環境用に使っているだけの可能性もあります。

*4:proguard 5.2.1のproguard.jarを持っていない人は、自分でソースからビルドするか、Android Studioを入れた後に前述のパスからコピーしてくると良いでしょう。