かずきのBlog@hatena

日本マイクロソフトに勤めています。XAML + C#の組み合わせをメインに、たまにASP.NETやJavaなどの.NET系以外のことも書いています。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

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);
}

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