Code-generates the Android ui_components registrations spliced into the
generated io.mob.plugin.MobPluginBootstrap — the Android analog of
MobDev.Plugin.IOSBootstrap.
Before this module existed the manifest's ui_components.android entry was
data nobody consumed: every host had to hand-register the plugin's Compose
factory in MainActivity.onCreate, and a host that forgot rendered the
component as nothing — MobNativeViewRegistry.render returns silently on
an unknown key (mob_scene3d-q03, the chopaat repro). Now
MobPluginBootstrap.registerAll(this) — which every generated/adopted
MainActivity already calls before setContent — also registers the
activated plugins' composables, so a declared component either works or
fails loudly:
Resolvable entries are auto-registered. The registry key comes from
ui_components.android.view_module, falling back toui_components.ios.view_module(both platforms share the key — it is the Elixir module name with dots → underscores, what the BEAM sends as the node'smoduleprop). The Compose factory isui_components.android.composable: used as-is when fully qualified (contains a.), otherwise qualified with the package ofandroid.bridge_class(the composable ships in the plugin'sbridge_kt, which declares that package). A typo'd composable fails the Gradle Kotlin compile — loud, at build time.Unresolvable-but-declared entries get a loud placeholder. A bare
composablewith nobridge_classto derive a package from (the hand-copied tier-2 workflow, where the host pastes the factory into its own source) registers a placeholder that renders a red "Missing native component" tile and logs an error. A host that follows the documented workflow — registering the real factory inMainActivity.onCreateafterregisterAll(this)— overwrites the placeholder; a host that forgot sees the tile instead of silence.Malformed entries fail the build. An android-backed component with no resolvable registry key (or no
composableat all) is returned in:errors;MobDev.NativeBuildraises with the message. The manifest is the bug, so build time — next to the manifest — is where it surfaces.
MobNativeViewRegistry lives in the app package (MobBridge.kt), which
io.mob.plugin code cannot import by name at authoring time — the reason a
plugin bridge's own register() can't do this. Codegen can: the caller
passes the discovered app package and every reference is emitted fully
qualified.
Pure, no I/O: classify/1 takes the activated-plugin list
([{plugin_dir, manifest}], the MobDev.Plugin.activated/0 shape) and
ui_source/2 renders the Kotlin. Output order is activation order, then
declaration order within a manifest — stable output keeps builds
reproducible.
Summary
Functions
Buckets the activated plugins' android-backed ui_components into
auto-registrations, loud placeholders, and build errors (see moduledoc).
Kotlin for the ui_components half of MobPluginBootstrap, or nil when
there is nothing to register (so plugin-less and UI-less builds emit a
byte-identical bootstrap to before this feature).
Types
Functions
@spec classify([MobDev.Plugin.Merge.plugin()]) :: classified()
Buckets the activated plugins' android-backed ui_components into
auto-registrations, loud placeholders, and build errors (see moduledoc).
Components without an :android map (iOS-only) contribute nothing here —
the validator's single-platform warning is what nags about those.
@spec ui_source(classified(), String.t()) :: %{call: String.t(), body: String.t()} | nil
Kotlin for the ui_components half of MobPluginBootstrap, or nil when
there is nothing to register (so plugin-less and UI-less builds emit a
byte-identical bootstrap to before this feature).
Returns %{call:, body:} — call is the statement registerAll runs,
body the member functions spliced into the object. app_package is the
host app's Kotlin package (where MobBridge.kt defines
MobNativeViewRegistry); every registry reference is emitted fully
qualified against it.