MobDev.Plugin.IOSBootstrap (mob_dev v0.5.16)

Copy Markdown View Source

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 against MobNode.nativeViewModule); the BEAM derives this from Mob.Component.module_name/1 so 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 different view_module keys 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

swift_source(plugins)

@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.