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

Embeddinator-4000から学ぶXamarinの基礎

Atsushi Eno
August 19, 2017

 Embeddinator-4000から学ぶXamarinの基礎

Atsushi Eno

August 19, 2017
Tweet

More Decks by Atsushi Eno

Other Decks in Technology

Transcript

  1. Embeddinator-4000から学ぶ
    Xamarinの基礎
    [email protected]

    View Slide

  2. Introduction

    View Slide

  3. Embeddinator-4000とは?

    View Slide

  4. Xamarinをネイティブで使う?
    ● Native Embedding (Xamarin.Forms)
    ○ プラットフォーム固有のコントロールを Xamarin.FormsのLayoutの子として追加
    ● Forms Embedding (Xamarin.Forms)
    ○ Xamarin.Formsのページをプラットフォーム固有の UIコントロールとして追加
    ● Embeddinator-4000
    ○ Mono/Xamarinで書いたコードを、プラットフォームネイティブのコードとして利用
    Xamarin.Forms
    Xamarin Native
    Xamarin Native
    Xamarin.Forms
    Native (objc/Java)
    Xamarin

    View Slide

  5. 何が出来るのか
    ● .NET DLLに対応するC/Java/objcバインディングを生成できる
    ● Xamarin.Androidのライブラリ プロジェクトをaarに変換できる
    ○ 「Xamarin.Androidのライブラリ プロジェクト」には
    Xamarin.FormsのNative Embeddingも含まれる(!)
    ● Mac, iOS (Objective-C)も実装されている
    ○ 公式にはまだAndroidのみ
    ※「aarって何?」という人向けではない

    View Slide

  6. どうやって使うのか?
    ● nugetでembeddinator-4000をインストール
    ● コマンドラインで実行
    ● mono packages/Embeddinator-4000.0.2.0.80/tools/Embeddinator-4000.exe
    -platform=Android -gen=Java -c project/bin/Debug/MyLibrary.dll
    ● mono packages/Embeddinator-4000.0.2.0.80/tools/objcgen.exe -platform=MacOS
    -gen=Obj-C -c project/bin/Debug/MyLibrary.dll
    ● mono packages/Embeddinator-4000.0.2.0.80/tools/Embeddinator-4000.exe
    -platform=Linux -gen=c -c project/bin/Debug/MyLibrary.dll

    View Slide

  7. 何が出来上がるのか?

    View Slide

  8. どんなライブラリが生成されるのか? (C)
    using System;
    public class MyLibrary
    {
    public string Hello (string input)
    {
    return "Hello, " + input;
    }
    }
    #include "glib.h"
    #include "mono_embeddinator.h"
    #include "c-support.h"
    typedef MonoEmbedObject MyLibrary;
    MONO_EMBEDDINATOR_API MyLibrary* MyLibrary_new();
    MONO_EMBEDDINATOR_API const char*
    MyLibrary_Hello(MyLibrary* object, const char* input);

    View Slide

  9. どんなライブラリが生成されるのか? (Java)
    ● Java APIのjarとmonodroidランタイム、アセンブリをassetsに含むaar
    ○ resがまだ含まれていない(困る)
    ● hello worldレベルのaarで約10MB
    package xamarin_forms_core.xamarin.forms;
    import com.sun.jna.Pointer;
    import mono.embeddinator.Runtime;
    ...
    public class Page extends VisualElement
    implements ILayout, IPageController {
    public Page(Pointer object) { super(object); }

    View Slide

  10. どうやっているのか
    これを理解するには、Xamarinの動作原理を理解する必要がある
    以下の質問にYesと答えられる人にはすぐ概要が分かる
    ● iOSやAndroidのアプリケーション(iOSならXcode + Objective-C、AndroidならAndroid Studio + Java)が、ど
    のように作られているのかを理解している
    ● それぞれのプラットフォームで、ネイティブライブラリをビルドして使用できる
    ● monoがembedded APIを用意していることを知っている
    ● Xamarinアプリケーションが各プラットフォームの標準に沿っていると知っている

    View Slide

  11. Xamarin.Android
    の基礎

    View Slide

  12. embedded mono
    ネイティブに組み込んで
    monoを使って.NETコードを
    実行できるCライブラリ
    リフレクションAPIのようなもの
    [doc] embedding mono
    scripting engineなどに便利

    View Slide

  13. monoランタイムによるアプリ起動の流れ
    main()
    mscorlibのロード
    machine.configなどのロード
    AppDomainの生成
    アセンブリのロード
    CILの実行
    この流れは全部mono embedded APIで実装できる
    .NETコードのエントリポイントは Main()とは限らない
    embedded monoなら任意のメソッドから実行可能
    .NETにも同様の機能がある( CLR Hosting)
    ※Silverlight、VSTO
    $mono hello.exe
    Hello, C#

    View Slide

  14. iOS/Xamarin.iOS
    今回はまだサポートされていないし、時間も足りないので省略…
    ● C/objective-c/swiftのコードはclang+llvmでネイティブにコンパイルされる
    ○ 実際に開発者が使うのはXcodeとか、xcodebuildなどのビルドツール
    ● プログラムはmain()から普通に開始
    ● embedded monoは `Mono.framework` になっている = リンクするだけ
    ● ObjCRuntime (C API)とembedded monoの間で相互運用
    ○ Xamarin.iOSのAPIは全てこの応用。 strongly typed iOS-ObjCRuntime API

    View Slide

  15. 標準的なAndroidアプリはどのように作るか
    ● Android Studioで開発するのが一般的
    ● JavaまたはKotlinでコーディング
    ● ビルドシステムはGradle
    ● 外部ライブラリはjarまたはaar
    ○ jarはコードだけ、aarはネイティブライブラリとかリソースも
    ○ パッケージ管理はMaven (主にjcenterサーバー)
    ● ビルドされるアプリケーションはapk
    ○ Javaの*.classはdex (dalvik bytecode)に変換
    ○ apkは(zipalignされた)zipアーカイブ

    View Slide

  16. Androidアプリでnative libsを使う
    ※libmonoはネイティブライブラリ
    ● AndroidはLinuxベースのOS
    ● Android NDKでビルド
    (tools: gcc or clang/llvm, libs: bionic libc etc.)
    ● CPUアーキテクチャごとにビルド
    (armeabi-v7a, aarch64, x86, x86_64, mips)
    【CからのJava呼び出し】
    ((JNIEnv) env)->CallVoidMethod(klass,...)
    ※JNIEnvがメタプログラミングの中心
    【JavaからのC呼び出し】
    boolean native foo(...)
    ※nativeはJavaのキーワード C#の
    extern

    View Slide

  17. Xamarin.AndroidとJava/Androidのやり取り
    ※われわれの Activity.OnCreate() はどう実行されるの
    か?
    ● XAアプリをビルドすると、Javaから.NETを呼ぶため
    のJCW (Java callable wrapper)が生成される
    ○ src/md5XXXXXXXXXXXXX/MainActivity.java みたいな感じ
    ○ mono embedded APIを間接的に呼び出す libmonodroidの
    nativeメソッド呼び出し(JNI)として実装されている
    ● AndroidフレームワークがアプリのJCWを呼び出す
    と関連付けられた.NETコードが実行される

    View Slide

  18. (図解JCW)
    Android
    Activity
    Thread
    APP
    JCW
    Main
    Activity
    (.java)
    onCreate()
    C# App
    Main
    Activity
    (.cs)
    X.A.
    lib
    monodroid
    n_onCreate()
    "OnCreate()"
    var method =
    "GetOnCreate_Landroid_os_Bundle_
    Handler");
    ...
    ...
    mono_runtime_invoke(...);
    Android側が
    呼ぶもの

    View Slide

  19. Androidアプリはどのように実行されるか
    AndroidフレームワークはJavaで実装されており、
    Zygote(Javaもどき)のプロセスで動く。例外は無い
    ● ユーザーがアプリを起動
    ● AndroidシステムがZygoteプロセスをfork
    ● ActivityThreadクラスがライフサイクルを制御
    ● AndroidManifest.xmlを読んで初期化処理
    ○ ContentProviderがあれば実行 (onCreate() など)
    ○ Applicationを実行
    ○ main launcher Activityがあれば実行

    View Slide

  20. Xamarin.Androidはどう初期化されるのか?
    ● MonoRuntimeProviderというContentProviderで初期化
    ○ 非公式に一般的な方法  Firebaseなどでも使用
    ○ このタイミングでなくても良い(が初期化以前は使えない)
    ○ libmonodroid
    ■ embedded monoの初期化
    ■ 全アセンブリのロード
    ■ JNI RegisterNatives()でJava/.NETマッピング
    ● JavaアプリケーションループがアプリのJCWを実行
    ○ (JCW = .NETコードをJNI経由で呼び出すJavaクラス)
    ※Androidの標準的な仕組みに基づいて実現している

    View Slide

  21. Embeddinator-4000

    View Slide

  22. Embeddinator-4000の仕組みの概要
    ● C(など)のコードからMono/XamarinのマネージドAPIを呼び出す
    ● .NETのアプリに含まれるAPIを「C / Java / Objective-Cから呼び出す」APIを
    自動生成してライブラリ化する
    ● 呼び出されたマネージドコードはmono上で実行される(iOSはAOT-ed)
    実は呼び出し層の構成が変わっただけであって、プラットフォーム
    (objc/Java/C)と.NETの相互運用の仕組みであることに変わりはない
    Androidが決め打ちのJCWを呼び出す vs. ユーザーが任意のe4k APIを使う

    View Slide

  23. (図解Embeddinator-4000呼び出し)
    User
    Java
    Code
    e4k
    Java
    API
    Visual
    Element
    .java
    new xamarin_
    forms_core.
    xamarin.forms.
    VisualElement()
    C# App
    Visual
    Element
    (.cs)
    e4k C API
    Xamarin.
    Forms.
    Core.c "get_Height()"
    .getHeight()
    Xamarin_Forms
    _VisualElement
    _get_Height()

    View Slide

  24. Cコードの生成
    生成ツールは部分的にCppSharpを活用して作られている
    C++と{好きな言語環境を入れる }の相互運用の自動化は超絶難易度が高いが
    Cなら簡単(というか、たいてい用意されている)
     PInvoke、JNI、perl XS、python cypes、node-ffi

    View Slide

  25. Objective-Cコードの生成
    ● 今回はAndroidの話をするだけでいっぱいいっぱいなので、割愛
    ● ツールとしてはobjcgen.exe
    ○ MonoEmbeddinator4000.exeとは完全に別物の実装
    ○ だいたいTextWriter.WriteLine()で実装している
    ● MacOSをターゲットにしたら、ライブラリまではビルドできた
    ● iOSはまだ調整が必要そう

    View Slide

  26. Android Javaコードの生成
    ● 「C/C++の呼び出しを行うJavaコード」を自動生成する
    ● JavaとC++のinteropは現在は一般的にJNIベースの煩雑な手作業
    ● Embeddinator-4000のコア: e4k C APIからJNA 呼び出しJavaコードを生成
    ○ JNAのランタイムが実行時にも必要になる(aarに組み込まれる)
    JNA: Java Native Access (com.sun.jna)
    Androidをサポートし、事前コード生成を必要としない唯一の選択肢(今回は重要ではない)

    View Slide

  27. 考察

    View Slide

  28. Embeddinator-4000の利点
    Xamarinアプリケーション開発者にとってのメリット
    ない
    それとは関係なく、CppSharpがあるとネイティブ
    ライブラリの呼び出しが楽になる…かもしれない
    ※rephrase: C++相互運用は激ムズ
    ※Xamarinからネイティブライブラリを大量に呼び出していると便利かも

    View Slide

  29. Embeddinator-4000の想定ユーザー(?)
    ● 既存のネイティブアプリでXamarinベースのコードを活用したい人
    ● 既存のネイティブアプリからXamarinに少しずつコードを移行したい人
    ● 既存のXamarinアプリからネイティブに土台を移行したい人
    ● .NET以外の環境でも.NETライブラリの利用を拡大したいライブラリ提供者
    ○ Azure関連のライブラリとか?
    ○ ライブラリはMavenに発行することも検討されている

    View Slide

  30. より開かれたXamarin環境
    ● Embeddinator-4000は「Xamarinでコードを書くとMicrosoft技術に囲い込まれ
    る」という懸念を晴らすために存在する技術でもある
    ● Xamarinを宣伝したい時に「でもXamarinで全部書くのはこわい…」となった
    時に緩和剤のひとつとして機能する側面がある
    ● 「ネイティブで出来るアレやコレができなくなるから…」と言われてXamarinを
    利用できなくなっても、埋め込めるチャンスがある
    ● ただし多用には警戒したほうがよい。相互運用の出入り口が多いとメンテナ
    ンス地獄になる。ツールの完成度に振り回される
    ● まだ出できたばかりのツールだということを忘れない

    View Slide

  31. まとめ
    ● Xamarinのアプリケーションを埋め込む技術はいろいろあってややこし
    いので、どれの話をしているか意識して聞いたほうが良い
    ● Xamarinは、iOS/Androidアプリケーションにネイティブコードである
    libmonoを組み込んで相互運用する技術
    ● Embeddinatorも、.NET APIを(Xamarinと)mono embedded API経由で、
    相互運用する技術
    ● レイヤーの重なり方がXamarinアプリケーションと少し違うだけ

    View Slide

  32. 宣伝
    本セッションの内容は技術書典 3で頒布する
    Xamarin同人誌(名称未設定)で解説します
    (2017/10/22 @秋葉原)

    View Slide