Embeddinator-4000から学ぶXamarinの基礎

24837993455f54c957883ba1f1db7f2d?s=47 Atsushi Eno
August 19, 2017

 Embeddinator-4000から学ぶXamarinの基礎

24837993455f54c957883ba1f1db7f2d?s=128

Atsushi Eno

August 19, 2017
Tweet

Transcript

  1. Embeddinator-4000から学ぶ Xamarinの基礎 atsushieno@pawoo.net

  2. Introduction

  3. Embeddinator-4000とは?

  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
  5. 何が出来るのか • .NET DLLに対応するC/Java/objcバインディングを生成できる • Xamarin.Androidのライブラリ プロジェクトをaarに変換できる ◦ 「Xamarin.Androidのライブラリ プロジェクト」には

    Xamarin.FormsのNative Embeddingも含まれる(!) • Mac, iOS (Objective-C)も実装されている ◦ 公式にはまだAndroidのみ ※「aarって何?」という人向けではない
  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
  7. 何が出来上がるのか?

  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);
  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); }
  10. どうやっているのか これを理解するには、Xamarinの動作原理を理解する必要がある 以下の質問にYesと答えられる人にはすぐ概要が分かる • iOSやAndroidのアプリケーション(iOSならXcode + Objective-C、AndroidならAndroid Studio + Java)が、ど

    のように作られているのかを理解している • それぞれのプラットフォームで、ネイティブライブラリをビルドして使用できる • monoがembedded APIを用意していることを知っている • Xamarinアプリケーションが各プラットフォームの標準に沿っていると知っている
  11. Xamarin.Android の基礎

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

    engineなどに便利
  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#
  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
  15. 標準的なAndroidアプリはどのように作るか • Android Studioで開発するのが一般的 • JavaまたはKotlinでコーディング • ビルドシステムはGradle • 外部ライブラリはjarまたはaar

    ◦ jarはコードだけ、aarはネイティブライブラリとかリソースも ◦ パッケージ管理はMaven (主にjcenterサーバー) • ビルドされるアプリケーションはapk ◦ Javaの*.classはdex (dalvik bytecode)に変換 ◦ apkは(zipalignされた)zipアーカイブ
  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
  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コードが実行される
  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側が 呼ぶもの
  19. Androidアプリはどのように実行されるか AndroidフレームワークはJavaで実装されており、 Zygote(Javaもどき)のプロセスで動く。例外は無い • ユーザーがアプリを起動 • AndroidシステムがZygoteプロセスをfork • ActivityThreadクラスがライフサイクルを制御 •

    AndroidManifest.xmlを読んで初期化処理 ◦ ContentProviderがあれば実行 (onCreate() など) ◦ Applicationを実行 ◦ main launcher Activityがあれば実行
  20. Xamarin.Androidはどう初期化されるのか? • MonoRuntimeProviderというContentProviderで初期化 ◦ 非公式に一般的な方法  Firebaseなどでも使用 ◦ このタイミングでなくても良い(が初期化以前は使えない) ◦ libmonodroid

    ▪ embedded monoの初期化 ▪ 全アセンブリのロード ▪ JNI RegisterNatives()でJava/.NETマッピング • JavaアプリケーションループがアプリのJCWを実行 ◦ (JCW = .NETコードをJNI経由で呼び出すJavaクラス) ※Androidの標準的な仕組みに基づいて実現している
  21. Embeddinator-4000

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

  25. Objective-Cコードの生成 • 今回はAndroidの話をするだけでいっぱいいっぱいなので、割愛 • ツールとしてはobjcgen.exe ◦ MonoEmbeddinator4000.exeとは完全に別物の実装 ◦ だいたいTextWriter.WriteLine()で実装している •

    MacOSをターゲットにしたら、ライブラリまではビルドできた • iOSはまだ調整が必要そう
  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をサポートし、事前コード生成を必要としない唯一の選択肢(今回は重要ではない)
  27. 考察

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

  29. Embeddinator-4000の想定ユーザー(?) • 既存のネイティブアプリでXamarinベースのコードを活用したい人 • 既存のネイティブアプリからXamarinに少しずつコードを移行したい人 • 既存のXamarinアプリからネイティブに土台を移行したい人 • .NET以外の環境でも.NETライブラリの利用を拡大したいライブラリ提供者 ◦

    Azure関連のライブラリとか? ◦ ライブラリはMavenに発行することも検討されている
  30. より開かれたXamarin環境 • Embeddinator-4000は「Xamarinでコードを書くとMicrosoft技術に囲い込まれ る」という懸念を晴らすために存在する技術でもある • Xamarinを宣伝したい時に「でもXamarinで全部書くのはこわい…」となった 時に緩和剤のひとつとして機能する側面がある • 「ネイティブで出来るアレやコレができなくなるから…」と言われてXamarinを 利用できなくなっても、埋め込めるチャンスがある

    • ただし多用には警戒したほうがよい。相互運用の出入り口が多いとメンテナ ンス地獄になる。ツールの完成度に振り回される • まだ出できたばかりのツールだということを忘れない
  31. まとめ • Xamarinのアプリケーションを埋め込む技術はいろいろあってややこし いので、どれの話をしているか意識して聞いたほうが良い • Xamarinは、iOS/Androidアプリケーションにネイティブコードである libmonoを組み込んで相互運用する技術 • Embeddinatorも、.NET APIを(Xamarinと)mono

    embedded API経由で、 相互運用する技術 • レイヤーの重なり方がXamarinアプリケーションと少し違うだけ
  32. 宣伝 本セッションの内容は技術書典 3で頒布する Xamarin同人誌(名称未設定)で解説します (2017/10/22 @秋葉原)