Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

Introduction

Slide 3

Slide 3 text

Embeddinator-4000とは?

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

どうやって使うのか? ● 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

Slide 7

Slide 7 text

何が出来上がるのか?

Slide 8

Slide 8 text

どんなライブラリが生成されるのか? (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);

Slide 9

Slide 9 text

どんなライブラリが生成されるのか? (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); }

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

Xamarin.Android の基礎

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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コードが実行される

Slide 18

Slide 18 text

(図解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側が 呼ぶもの

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

Embeddinator-4000

Slide 22

Slide 22 text

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を使う

Slide 23

Slide 23 text

(図解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()

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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をサポートし、事前コード生成を必要としない唯一の選択肢(今回は重要ではない)

Slide 27

Slide 27 text

考察

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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