かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

Xamarin.AndroidからJavaのネイティブライブラリ(jarね)を使おう

お題の通りやってみようと思います。

今回挑戦したのは癖のなさそうな、Apache CommonsのLangです。ここからjarをダウンロードしました。

Lang – Download Apache Commons Lang

バージョンは現時点で最新の3.4にしました。

前提知識としてBindings Libraryというものがあるということだけ知ってたので、そのプロジェクトを作ります。

f:id:okazuki:20160809215019p:plain

プロジェクトを新規作成するとJarsという名前の、いかにも怪しそうなフォルダができるのでそこを見てみます。そうすると、AboudJars.txtというテキストがあって、こういうことが書いてあります。

This directory is for Android .jars.

There are 2 types of jars that are supported:

== Input Jar ==

This is the jar that bindings should be generated for.

For example, if you were binding the Google Maps library, this would
be Google's "maps.jar".

Set the build action for these jars in the properties page to "InputJar".


== Reference Jars ==

These are jars that are referenced by the input jar.  C# bindings will
not be created for these jars.  These jars will be used to resolve
types used by the input jar.

NOTE: Do not add "android.jar" as a reference jar.  It will be added automatically
based on the Target Framework selected.

Set the build action for these jars in the properties page to "ReferenceJar".

つまりJarsフォルダあたりにjarファイルつっこんでプロパティウィンドウでInputJarやReferenceJarを設定すればよろしいということっぽいですね。ということで、ダウンロードしたcommons-lang3-3.4.jarをJarsフォルダにコピーして、ビルドアクションをInputJarにします。(というかソリューションエクスプローラーにぽとっと落としたらそうなってました)

ビルドすると、めでたしめでたし…なのかと思ったらコンパイルエラーだらけになりました。

f:id:okazuki:20160809215602p:plain

今日は自動生成はあきらめて、AndroidのプロジェクトにJarを追加して、ビルドアクションをAndroidJavaLibraryに変更して、以下のコードでisEmptyを呼び出せることだけ確認しました。

IntPtr classHandle = IntPtr.Zero;
JNIEnv.FindClass("org/apache/commons/lang3/StringUtils", ref classHandle);
var method = JNIEnv.GetStaticMethodID(classHandle, "isEmpty", "(Ljava/lang/CharSequence;)Z");
string emptyString = "";
var handle = CharSequence.ToLocalJniHandle(emptyString);
try
{
    var result = JNIEnv.CallStaticBooleanMethod(classHandle, method, new JValue(handle));
    button.Text = result.ToString();
}
finally
{
    JNIEnv.DeleteLocalRef(handle);
}

俺たちの戦いは、これからだ!!!