Skip to content

Blueprint

Jonathan Pryor edited this page Oct 8, 2021 · 7 revisions

Blueprint

.NET SDK for Android née Xamarin.Android is a set of tooling to create Android apps in C#.

What are the various "pieces" of Xamarin.Android, and what are their relationships with each other?

Relations

App Build Process

TODO

Java Library Binding Process

The Xamarin.Android binding process, broadly speaking, involves three steps:

  1. Parse .class files -- present in .jar and .aar files -- into an XML description. The class-parse utility is responsible for generating this XML description.
  2. Consume the XML description, and generate a set of C# files which bind the types in (1). The Xamarin.Android generator utility is responsible for this.
  3. Compile the C# from (2) into the final assembly.

class-parse and generator are implicitly used as part of the Xamarin.Android @(EmbeddedJar) and @(InputJar) build action within Binding projects, and in .NET for Android via the @(AndroidLibrary) build action, when %(AndroidLibrary.Bind)=True.

See also:

On-Android Process Startup

TODO: Determine of the App Startup AndroidX Library should change how we do things.

TODO: Find some sources to elaborate on the "pre-Xamarin startup" bits.

When the user taps on an App icon on an Android device, the Activity associated with that App is looked up. If a process for that Activity doesn't already exist, a process will be created (somewhere) in Zygote.java, an Application singleton instance is created based on the contents of //application/@android:name attribute within AndroidManifest.xml, and eventually all relevant <provider/>s will be constructed.

This is where xamarin-android enters the picture: during the App Build Process, a <provider/> is always added to AndroidManifest.xml, one per detected process name:

<provider android:name="mono.MonoRuntimeProvider" android:exported="false" android:initOrder="1999999999" android:authorities="com.xamarin.android.helloworld.mono.MonoRuntimeProvider.__mono_init__" />

This XML fragment causes MonoRuntimeProvider to be instantiated, and the Content Provider lifecycle to be started. We don't use <provider/> to actually add a Content Provider; we use it because this was the earliest point we could find during Android process startup through which we could execute code.

When MonoRuntimeProvider.attachInfo() is invoked by Android, xamarin-android has an opportunity to load Mono. This is done via MonoPackageManager.LoadApplication(), which is the primary Java-side startup code path.

MonoPackageManager.LoadApplication() loads various native libraries, including libmonodroid.so. Once libmonodroid.so has been loaded, mono.android.Runtime methods can be invoked, in particular Runtime.initInternal(). Through the glory of JNI native method resolution, Runtime.initInternal() is resolved as the C symbol Java_mono_android_Runtime_initInternal().

Runtime.initInternal() is responsible for preparing the process for managed code execution:

  • Initialize MonoVM
  • Find assemblies included with the App
  • etc., etc.

Once MonoVM has been initialized, Mono.Android.dll is loaded, then JNIEnv.Initialize() is invoked. This gives Mono.Android.dll a chance to perform initialization.

Once Runtime.initInternal() completes, MonoPackageManager.attachInfo() returns, and normal Android app startup resumes.

Primary source code locations:

Pieces

The pieces which make of Xamarin.Android include:

App Runtime

"Glue" code for running apps on Android device, process startup, etc.

Primary source code locations are:

class-parse

class-parse parses .class and .jar files, and produces an XML description of the Java APIs found.

Primary source code locations are:

generator

Create C# bindings from XML description.

Also can optionally attempt to import Javadoc documentation, as imported from java-source-utils, and convert into C# XML Documentation Comments.

Primary source code locations are:

Fast Deployment

Quickly update existing app installs on an Android device, for quick dev inner loops. Part of Xamarin.Android.Build.Tasks.

https://github.com/xamarin/monodroid#commercial-xamarinandroid-dependencies

Java Callable Wrapper Generator

Create Java “stub” code to permit Java-to-managed method invocations. Required for on-device app use. Part of Xamarin.Android.Build.Tasks.

Docs:

Primary source code locations are:

java-source-utils

Java source code parser, using com.github.javaparser.

Exists to improve Java Library bindings in Xamarin.Android/.NET for Android. Bindings in Xamarin.Android frequently hit two common pitfalls:

  1. Lack of parameter names.
  2. Lack of documentation.

Java method parameter names are useful in-and-of-themselves. However, parameter names are also used when turning *Listener interfaces into events, wherein each method parameter becomes an *EventArgs property. See also: Events and Listeners in API Design.

The problem with Java method parameter names is that by default, Java .class files don't contain parameter names. Java .class files can contain parameter names, but only if javac -parameters was used to compile the Java source code, which frequently is not the case. If parameter names aren't present, then names such as p0 are used, which results in very ugly *EventArgs types.

Additionally, Java libraries frequently provide documentation, in the form of Javadoc documentation within Java source code.

java-source-utils parses Java source code, extracting parameter names and Javadoc documentation. The extracted information can then be used by the Xamarin.Android generator utility to provide parameter name information. generator can also attempt to convert the extracted Javadoc documentation into C# XML Documentation Comments.

See also:

java-source-utils is used by Xamarin.Android, via the @(JavaSourceJar) build item.

Primary source code locations are:

Mono.Android.dll

Core binding for the Android API.

Primary source code locations are: