$30 off During Our Annual Pro Sale. View Details »

[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
Tweet

More Decks by Atsushi Eno

Other Decks in Programming

Transcript

  1. Binding Java Library

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

  6. Java Binding Essentials
    Monodroid VM Zygote (Java) Process
    Java API
    Java Binding
    Start
    callback
    C# code
    java code
    JNI
    JNI

    View Slide

  7. How to FIND Java Binding
    ● Xamarin component store
    ● NuGet packages
    ● monodroid-samples
    ● github (project search)

    View Slide

  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

    View Slide

  9. Javaバインディングの作り方

    View Slide

  10. Java Binding Project: How to Create
    Project>New>Java Binding Library
    Add Java libraries
    Add References (if any)
    Add JavaDocIndex (optional)

    View Slide

  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

    View Slide

  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/*
    → project.properties
    LibraryProjectZip
    LibraryProjectProperties
    New Android
    Library
    *.aar LibraryProjectZip

    View Slide

  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

    View Slide

  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) project.properties : LibraryProjectProperties build item
    created by "android update project -p ."
    add it ONLY AFTER you built it (ant debug)

    View Slide

  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)

    View Slide

  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/
    project.properties
    embedded
    (always)
    LibraryProjectZip
    LibraryProjectProperties

    View Slide

  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.

    View Slide

  18. [補] Build Item Type Details
    InputJar
    C# API is generated for this, but the .jar is NOT embedded in the dll.
    Useful for 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")

    View Slide

  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.

    View Slide

  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

    View Slide

  21. Java Bindingをビルド

    View Slide

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

    View Slide

  23. Why?
    JavaとC#は違う。完全な対応はできない。
    ● ジェネリクスの違い (erased generics vs. reified generics)
    ● 継承の制限の違い (public class extends nonpublic class etc.)
    ● etc.
    XAがAPIを.NET寄りに加工する処理の副作用
    generatorのバグ
    xsd.exeやwsdl.exeと同じ。何でも処理できるはずはない。

    View Slide

  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

    View Slide

  25. Metadata.xml
    ... to "fix" "api.xml"

    ...

    @path by XPath
    See: API Metadata Reference
    XPathは生成されたソースの型/メンバーのコメント上にも生成されている

    View Slide

  26. Additions/*.cs
    バインドに失敗した型を手作業で追加
    (生成されるコードはpartial = 混合可能)
    hack:
    ビルド → コンパイルに失敗するコードを改変して追加 →
    バインディングで使用するAPIはfairly stable (古いバインディングも動作する程度に)

    View Slide

  27. How to Find the Causes
    Warnings / Errors
    e.g. Warning: FxDG Violation → 後でコンパイルエラー
    MSBuild output (JarToXml task, GenerateBindings task)
    - verbose (/v:diag)

    View Slide

  28. General Tip
    とりあえず で消す
    ただし…
    ● 使いたいAPIが(巻き添えを食って)消える
    ● missing dependencies → errors
    消してもいいもの
    ● obfuscated API (通常は自動的にバインド対象外)
    ● internal API(ただしものによってはpublic APIに…)

    View Slide

  29. Fix Inconsistent Type Access
    対策1: public
    余計なメンバーが別のビルドエラーを誘発する可能性はある
    対策2: PublicAncestor
    (members in nonpublic class)
    これは祖先でも可。大概めんどくさい。
    package android.app.backup;
    class FileBackupHelperBase { ... }
    public class FileBackupHelper extends FileBackupHelperBase

    View Slide

  30. Fix Inconsistent Member Access
    対策: protected
    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 () { ... }

    View Slide

  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 () { ... }

    View Slide

  32. Dealing with Variants and Generics
    android.content.pm.ApplicationInfo.DisplayNameComparator
    implements java.util.Comparator
    class Comparator {
    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) { ... }
    }

    View Slide

  33. Dealing with Variants and Generics
    対策: パラメータの "managedType" またはメソッドの "managedReturn":
    Java.Lang.Integer
    注: "type" や "return"を変更しない!
    (JNI呼び出しがおかしくなる)

    View Slide

  34. Property get/set Inconsistency
    set-only Base, get/set Derived ...
    対策: name="generateDispatchingSetter">true
    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 { ... } }
    }

    View Slide

  35. Enums and Color
    Xamarin API: int → enum, int → Android.Graphics.Color
    基本的にオーバーライドは検出できることになっている
    が、たまに検出しない場合がある
    (インターフェース メンバーがenum/Colorを使っている etc.)
    対策: use managedType / managedReturn

    View Slide

  36. Name Collision on EventArgs
    対策: OnXxxListener に "argsType" を使用
    XxxEventArgs
    package: com.facebook.android 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 { ... }

    View Slide

  37. Deriving iface from generic iface
    android.content.EntityIterator extends java.util.Iterator
    これは対応不能 (API limitation)
    interface Iterator { ...
    E next ();
    }
    interfaceIterator { ...
    Java.Lang.Object Next ();
    }
    interface EntityIterator {
    // Entity next ();
    }
    interface EntityIterator {
    // what Next() should return?
    // JLO? Entity?
    // cannot be overloaded.
    }

    View Slide

  38. Namespace / Type Name conflicts
    Java package: all lowercase
    .NET namespace: PascalCase
    Problem:
    android.view.View -> Android.View.View
    対策:
    YourNS

    View Slide

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

    View Slide

  40. Beautifying Managed API
    ● 適切な名前をつける (managedName)
    ○ valid PascalCase: namespace ActionBarSherlock
    ○ 'System', 'Android' などはC#コーディングの妨げになる
    ■ namespace Dalvik.SystemInterop
    ● 適切なイベント名 (eventName)
    ○ android.app.Dialog.setOnKeyListener()
    → Android.App.Dialog.Key Android.App.Dialog.KeyPress
    ● 適切なEventArgsクラス名 (argsType)
    ○ Android.Media.MediaDrm.OnEventListener
    → EventEventArgs MediaDrmEventArgs

    View Slide

  41. Beautifying Managed API
    ● asyncメソッドを追加 - "generateAsyncWrapper" を "true" に
    true

    View Slide

  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.

    View Slide

  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.

    View Slide

  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)

    View Slide

  45. ende

    View Slide