Code-generates the iOS plugin bootstrap Swift source from the activated
plugins' :ui_components declarations.
The generated file defines one C-callable function, mob_register_plugins,
that registers a factory closure with MobNativeViewRegistry.shared for
each component the host should expose. The host's AppDelegate calls
mob_register_plugins() once, before mob_init_ui(), and from that point
every component the BEAM mounts under a plugin's view_module key resolves
to the plugin's SwiftUI view.
Plain function, no state — call swift_source/1 with the same shape
MobDev.Plugin.activated/0 returns ([{plugin_dir, manifest}]) and you
get back the Swift source string ready to write to disk.
Pre-codegen, each plugin shipped its own @objc class MobXxxPlugin { @objc class func mob_register() } and the host hand-wrote one
[MobXxxPlugin mob_register]; line per plugin into AppDelegate.m. That's
the smoke-test pattern from the 2026-05-28 iOS plugin bring-up. This
module replaces both halves: plugins drop the @objc wrapper and just
ship the SwiftUI struct, and the host always calls a single generated
entry point regardless of how many plugins it has activated.
The mapping from a ui_components entry to a register call comes from
two manifest fields:
ui_components.ios.view_module— the registry key (string match againstMobNode.nativeViewModule); the BEAM derives this fromMob.Component.module_name/1so it must agree with the manifest.ui_components.ios.swift_struct— the Swift struct name to instantiate (StructName(props: props)). Two plugins are free to register differentview_modulekeys that resolve to the same struct, and the struct name need not be derivable from the registry key.
A component without :swift_struct is silently skipped (the
MobDev.Plugin.Validator.validate_plugin/3 step is where authors get told
to add the field); the validator's job is to surface this before build
time. The generator stays purely transform-shaped so the build pipeline
never has to think about missing manifest fields.
Summary
Functions
Returns the full Swift source for the bootstrap file.
Functions
@spec swift_source([MobDev.Plugin.Merge.plugin()]) :: String.t()
Returns the full Swift source for the bootstrap file.
plugins is the activated-plugin list — [{plugin_dir, manifest}] —
same shape MobDev.Plugin.activated/0 returns. Tier-0 (nil-manifest)
plugins contribute nothing. Components missing :swift_struct are
silently dropped: the validator is what nags about that.
The output is stable: components are emitted in the order
MobDev.Plugin.Merge.ui_components/1 lists them (i.e. activation order,
then declaration order within a manifest). Stable output keeps the build
cache hit-rate high.