Save 37% off PRO during our Black Friday Sale! »

[JXUG#4] 2015-04-11 Binding Java Library

[JXUG#4] 2015-04-11 Binding Java Library

Session slides for Japan Xamarin User Group meetup #4


Atsushi Eno

April 11, 2015


  1. Binding Java Library

  2. Agenda Javaバインディング ライブラリについて知る • Javaバインディングって何? • どうやって作るの? • ハマりどころと解決策

  3. atsushieno 某X社の中の人 XA開発者(かろうじて) mono開発者 (一応)

  4. Javaバインディングって何?

  5. Libraries in Xamarin.Android land Android Native Stack (kernel, libc, opengl,

    android fx etc.) Android Fx Java API Dalvik/ART VM libmonodroid Mono.Android API Other Java Libs System* OpenTK Other .NET Libs Java Bindings
  6. Java Binding Essentials Monodroid VM Zygote (Java) Process Java API

    Java Binding Start callback C# code java code JNI JNI
  7. How to FIND Java Binding • Xamarin component store •

    NuGet packages • monodroid-samples • github (project search)
  8. jar2xml* How Java Binding is Built .jar api.xml *.cs *.dll

    *.cs *.cs generator mcs/csc metadata fixup additional *.cs reference *.dll reference *.dll
  9. Javaバインディングの作り方

  10. Java Binding Project: How to Create Project>New>Java Binding Library Add

    Java libraries Add References (if any) Add JavaDocIndex (optional)
  11. Dependency Resolution b.jar class C2 extends a.C1 { ... }

    ABinding.dll public class C1 { ... } a.jar api.xml BBinding.dll public class C2 : A.C1 { ...} a.jar class C1 { ... } b.jar
  12. 注: res/*がある場合はLibraryProject[Zip|Properties] Java Library and Typical Item Type Java/non-UI Library

    *.jar (w/o res/*) EmbeddedJar Old Android Library zipped *.jar + res/* → LibraryProjectZip LibraryProjectProperties New Android Library *.aar LibraryProjectZip
  13. [補] *.jar + res/* Doable only for Java libraries that

    don't have res/* .jar doesn't contain res/* ! ResourceNotFoundException if you do this regardless. Build Item Type: mostly EmbeddedJar
  14. [補] Android Library Project Outcome Android Library Project... built with

    ant or Eclipse ADT (!) Add its build results as the target (bound) Java library. Two approaches to achieve that: 1) : LibraryProjectProperties build item created by "android update project -p ." add it ONLY AFTER you built it (ant debug)
  15. [補] Android Library Project Outcome 2) *.zip: LibraryProjectZip build item

    Archive the OUTCOME of the build. a bit messier to build compared to C1), but you can distribute it in your project. (i.e. your library users don't have to build it.) (Gradle? ... expect those libs to create .aar)
  16. Java Library Build Item Types pure Java Library .jar bind

    API embedded EmbeddedJar ! embedded InputJar no need to bind API embedded EmbeddedReferenceJar ! embedded ReferenceJar new Android Library .aar embedded (always) LibraryProjectZip old Android Library .jar + res/ embedded (always) LibraryProjectZip LibraryProjectProperties
  17. [補] Build Item Type Details EmbeddedJar You'd mostly like to

    use it. C# API is generated for this, and the jar is embedded in the dll. EmbeddedReferenceJar NO C# API is generated, but it is embedded in the dll. Useful for jar dependencies.
  18. [補] Build Item Type Details InputJar C# API is generated

    for this, but the .jar is NOT embedded in the dll. Useful for <uses-library /> Manifest element based Java libs, or libraries that you cannot freely distribute by embedding to the .dll. Old Google Maps used it. Kindle libraries can be this too. ReferenceJar neither (useful under very limited situation e.g. java dependencies when generating "ACW")
  19. [補] Library Reference via Web [assembly:Java.Interop.JavaLibraryReference] [assembly:Android.IncludeAndroidResourcesFrom] [assembly:Android.NativeLibraryReference] They are

    used to download dependencies when resolving Java libraries from . dll. Not (well) documented yet. Xamarin uses it for GooglePlayServices binding.
  20. [補] XA Android Library (which is very different from Binding

    Library...) You can also embed .jars and res/* in XA (non-binding) Library project. • AndroidJavaLibrary • AndroidExternalJavaLibrary (referenced when compiling sources, but NOT embedded in the final .apk) • AndroidResource, AndroidAsset
  21. Java Bindingをビルド

  22. Project>New>Java Binding Library Add Java libraries Add References >>> errors

  23. Why? JavaとC#は違う。完全な対応はできない。 • ジェネリクスの違い (erased generics vs. reified generics) •

    継承の制限の違い (public class extends nonpublic class etc.) • etc. XAがAPIを.NET寄りに加工する処理の副作用 generatorのバグ xsd.exeやwsdl.exeと同じ。何でも処理できるはずはない。
  24. jar2xml* How to Deal with It? .jar api.xml *.cs *.dll

    *.cs *.cs generator mcs/csc metadata fixup additional *.cs reference *.dll reference *.dll
  25. Metadata.xml ... to "fix" "api.xml" <add-node> <attr>...</attr> <remove-node> @path by

    XPath See: API Metadata Reference XPathは生成されたソースの型/メンバーのコメント上にも生成されている
  26. Additions/*.cs バインドに失敗した型を手作業で追加 (生成されるコードはpartial = 混合可能) hack: ビルド → コンパイルに失敗するコードを改変して追加 →

    <remove-node> バインディングで使用するAPIはfairly stable (古いバインディングも動作する程度に)
  27. How to Find the Causes Warnings / Errors e.g. Warning:

    FxDG Violation → 後でコンパイルエラー MSBuild output (JarToXml task, GenerateBindings task) - verbose (/v:diag)
  28. General Tip とりあえず <remove-node /> で消す ただし… • 使いたいAPIが(巻き添えを食って)消える •

    missing dependencies → errors 消してもいいもの • obfuscated API (通常は自動的にバインド対象外) • internal API(ただしものによってはpublic APIに…)
  29. Fix Inconsistent Type Access 対策1: <attr path="/path/to/NonPublicBase" name="visibility">public</attr> 余計なメンバーが別のビルドエラーを誘発する可能性はある 対策2:

    <attr path="/path/to/Derived" name="extends">PublicAncestor</attr> <add-node>(members in nonpublic class)</add-node> これは祖先でも可。大概めんどくさい。 package; class FileBackupHelperBase { ... } public class FileBackupHelper extends FileBackupHelperBase
  30. Fix Inconsistent Member Access 対策: <attr path="/path/to/class" name="visibility">protected</attr> C#でpublicにアクセスできなくなるが、.NETでは無理。Additionsで対応できる。 class

    Foo { protected void x () { ... } } class Foo { protected virtual void X () { ... } class Bar extends Foo { public void x () { ... } } class Bar : Foo { public override void X () { ... }
  31. Dealing with Variants and Generics class Foo { public Object

    x () { ... } } class Foo { public virtual Object X () { ... } class Bar extends Foo { public Integer x () { ... } } class Bar : Foo { public override Integer X () { ... }
  32. Dealing with Variants and Generics implements java.util.Comparator<> class Comparator<T>

    { abstract int compare (T t1, T t2); } class Comparator { int Compare (Object o1,Object o2); } class DisplayNameComparator { int compare (ApplicationInfo a1, ApplicationInfo a2) { ... } } class DisplayNameComparator { int compare (ApplicationInfo a1, ApplicationInfo a2) { ... } }
  33. Dealing with Variants and Generics 対策: パラメータの "managedType" またはメソッドの "managedReturn":

    <attr path="/path/to/method" name="managedReturn">Java.Lang.Integer</attr> 注: "type" や "return"を変更しない! (JNI呼び出しがおかしくなる)
  34. Property get/set Inconsistency set-only Base, get/set Derived ... 対策: <attr

    path="/path/to/base/method" name="generateDispatchingSetter">true</attr> public class Base { public void setXxx(int x) { ... } } public class Base { void SetXxx (int x) { ... } } public class Derived { public int getXxx() { ... } public void setXxx(int x) { ... } } public class Derived { public int Xxx { get { ... } set { ... } } }
  35. Enums and Color Xamarin API: int → enum, int →

    Android.Graphics.Color 基本的にオーバーライドは検出できることになっている が、たまに検出しない場合がある (インターフェース メンバーがenum/Colorを使っている etc.) 対策: use managedType / managedReturn
  36. Name Collision on EventArgs 対策: OnXxxListener に "argsType" を使用 <attr

    path="/path/to/interface" name="argsType">XxxEventArgs</attr> package: namespace: Com.Facebook.Android interface Facebook.DialogListener { void onComplete(Bindle values); void onError(DialogError de); } interface IDialogListener { ... } public class CompleteEventArgs { ... } public class ErrorEventArgs { ... } interface Facebook.ServiceListener { void onComplete(Bindle values); void onError(DialogError de); } interface IServiceListener { ... } public class CompleteEventArgs { ... } public class ErrorEventArgs { ... }
  37. Deriving iface from generic iface android.content.EntityIterator extends java.util.Iterator<Entity> これは対応不能 (API

    limitation) interface Iterator<E> { ... E next (); } interfaceIterator { ... Java.Lang.Object Next (); } interface EntityIterator { // Entity next (); } interface EntityIterator { // what Next() should return? // JLO? Entity? // cannot be overloaded. }
  38. Namespace / Type Name conflicts Java package: all lowercase .NET

    namespace: PascalCase Problem: android.view.View -> Android.View.View 対策: <attr path="/path/to/package" name="managedName">YourNS</attr>
  39. Name Conflict by PascalCasing 対策: いずれかに "managedName" を適用 public class

    Foo { public final int FOO_BAR; public int getFooBar(); } public class Foo { public const int FooBar; public int FooBar { get; } }
  40. Beautifying Managed API • 適切な名前をつける (managedName) ◦ valid PascalCase: namespace

    ActionBarSherlock ◦ 'System', 'Android' などはC#コーディングの妨げになる ▪ namespace Dalvik.SystemInterop • 適切なイベント名 (eventName) ◦ → Android.App.Dialog.Key Android.App.Dialog.KeyPress • 適切なEventArgsクラス名 (argsType) ◦ Android.Media.MediaDrm.OnEventListener → EventEventArgs MediaDrmEventArgs
  41. Beautifying Managed API • asyncメソッドを追加 - "generateAsyncWrapper" を "true" に

    <attr path="/api/package[@name='android.accounts']/interface [@name='AccountManagerFuture']/method[@name='getResult']" name=" generateAsyncWrapper">true</attr>
  42. [補] Packaging binding libraries NuGet common to other .NET profiles.

    you can publish as you'd like. Component Store needs to come up with docs and samples. needs approval by Xamarin.
  43. [補] Binding feature history Mono.Android.dll etc. were from api.xml (using

    generator). api.xml was part of AOSP (Android Open Source Project). But it WASN'T at some stage - Honeycomb. So, we ended up to create jar2xml. We enhanced these tools to support any Java libraries.
  44. [補] How it affected the product XA used to be

    like "For whatever .NET has better API, we offer them rather than binding Java API" • e.g. no Java collections, no XML API, no apache http API etc. • But w/o those we could not bind arbitrary API. • So, ended up to bring (almost) everything. • At the same time the API "got frozen" to be "stable". • that causes several ugliness... (failed product strategy)
  45. ende