MobDev.Plugin.Merge (mob_dev v0.6.16)

Copy Markdown View Source

Gathers the contributions of the activated plugins into combined lists the build pipeline consumes.

Pure: every function takes plugins — a list of {plugin_dir, manifest} for the activated plugins — and returns the merged contribution for one build concern (NIFs, permissions, gradle deps, frameworks, native sources, …). Path-bearing declarations are resolved to absolute paths against each plugin's own directory, so contributions from different plugins don't collide or get misresolved. Tier-0 (nil-manifest) plugins contribute nothing.

Discovery (deps → activated → load manifest) is the caller's job; this module is the testable transform once the manifests are in hand.

Summary

Functions

Unique Android permission strings declared across plugins.

Absolute paths of all plugin Android native sources (bridge_kt, jni_source) plus NIF native_dirs — everything the Android build must compile in.

Asset declarations across plugins, with font/image paths resolved to absolute and tagged with :plugin (used by the plugin://<name>/<file> image resolver and the native font-bundling merge).

Fully-qualified Kotlin class names (e.g. "io.mob.bluetooth.MobBluetoothBridge") each activated plugin wants registered at startup. native_build generates a MobPluginBootstrap.registerAll/0 that calls <class>.register() for each, so the plugin's nativeRegister thunk can cache its own jclass + method IDs.

Absolute paths of plugin Android bridge_kt Kotlin sources. native_build copies each into the app source tree (at its package-derived path) before gradle assembleDebug, so the app's Kotlin sourceSet compiles it.

Unique Android gradle dependency strings across plugins.

Host-app obligations the plugin system can't automate (e.g. AndroidManifest fragments — a typed foreground <service>, a FileProvider), tagged with :plugin. The native build prints these so a host author can't activate a plugin and only discover the missing manual step at first feature use.

Unique iOS framework names across plugins.

Absolute paths of plugin Android jni_source files — plain JNI-thunk C (e.g. Java_<pkg>_<Class>_nativeDeliver*) that the build compiles into the app .so without a NIF-init libname (unlike nif_sources/1). Fed to the build's -Dplugin_jni_sources arg.

Lifecycle declarations across plugins, each tagged with :plugin.

Migration declarations across plugins, with :migrations_dir resolved to an absolute path and tagged with :plugin + :repo_namespace.

Absolute paths of each plugin C-family NIF's primary source — entries with no :lang, lang: :c (<module>.c), or lang: :objc (<module>.m, compiled as Objective-C so iOS plugins can drive Apple frameworks like CoreLocation).

Like nif_sources/1 but restricted to NIFs the given platform compiles.

Combined NIF entries across all plugins, with :native_dir resolved to an absolute path. Shape matches MobDev.StaticNifs entries (:module plus the plugin's native source dir), so the result can be fed straight into StaticNifs.resolve/1.

Notification handlers across all plugins, flattened in plugin-then-declaration order (first match wins at dispatch), each tagged with :plugin.

Merged iOS plist_keys across plugins (later plugins win on conflict).

Static screen declarations across plugins, each tagged with :plugin.

Settings declarations across plugins, each tagged with :plugin.

Cross-compiled C++ static-archive contributions (lang: :cpp_archive) across plugins, resolved for one platform.

Absolute paths of all plugin iOS Swift source files.

Combined ui_components entries across plugins.

Absolute paths of each plugin zig NIF's primary source (NIFs whose manifest entry has lang: :zig).

Like zig_nif_sources/1 but restricted to the given platform (see nif_sources/2).

Types

plugin()

@type plugin() :: {Path.t(), map() | nil}

Functions

android_permissions(plugins)

@spec android_permissions([plugin()]) :: [String.t()]

Unique Android permission strings declared across plugins.

android_sources(plugins)

@spec android_sources([plugin()]) :: [String.t()]

Absolute paths of all plugin Android native sources (bridge_kt, jni_source) plus NIF native_dirs — everything the Android build must compile in.

assets(plugins)

@spec assets([plugin()]) :: [map()]

Asset declarations across plugins, with font/image paths resolved to absolute and tagged with :plugin (used by the plugin://<name>/<file> image resolver and the native font-bundling merge).

bridge_classes(plugins)

@spec bridge_classes([plugin()]) :: [String.t()]

Fully-qualified Kotlin class names (e.g. "io.mob.bluetooth.MobBluetoothBridge") each activated plugin wants registered at startup. native_build generates a MobPluginBootstrap.registerAll/0 that calls <class>.register() for each, so the plugin's nativeRegister thunk can cache its own jclass + method IDs.

bridge_kt_sources(plugins)

@spec bridge_kt_sources([plugin()]) :: [String.t()]

Absolute paths of plugin Android bridge_kt Kotlin sources. native_build copies each into the app source tree (at its package-derived path) before gradle assembleDebug, so the app's Kotlin sourceSet compiles it.

gradle_deps(plugins)

@spec gradle_deps([plugin()]) :: [String.t()]

Unique Android gradle dependency strings across plugins.

host_requirements(plugins)

@spec host_requirements([plugin()]) :: [%{plugin: atom(), requirement: String.t()}]

Host-app obligations the plugin system can't automate (e.g. AndroidManifest fragments — a typed foreground <service>, a FileProvider), tagged with :plugin. The native build prints these so a host author can't activate a plugin and only discover the missing manual step at first feature use.

ios_frameworks(plugins)

@spec ios_frameworks([plugin()]) :: [String.t()]

Unique iOS framework names across plugins.

jni_sources(plugins)

@spec jni_sources([plugin()]) :: [String.t()]

Absolute paths of plugin Android jni_source files — plain JNI-thunk C (e.g. Java_<pkg>_<Class>_nativeDeliver*) that the build compiles into the app .so without a NIF-init libname (unlike nif_sources/1). Fed to the build's -Dplugin_jni_sources arg.

lifecycle(plugins)

@spec lifecycle([plugin()]) :: [map()]

Lifecycle declarations across plugins, each tagged with :plugin.

migrations(plugins)

@spec migrations([plugin()]) :: [map()]

Migration declarations across plugins, with :migrations_dir resolved to an absolute path and tagged with :plugin + :repo_namespace.

nif_sources(plugins)

@spec nif_sources([plugin()]) :: [String.t()]

Absolute paths of each plugin C-family NIF's primary source — entries with no :lang, lang: :c (<module>.c), or lang: :objc (<module>.m, compiled as Objective-C so iOS plugins can drive Apple frameworks like CoreLocation).

Convention: for a manifest entry %{module: :foo_nif, native_dir: "priv/jni"} the source is <plugin_dir>/priv/jni/foo_nif.c (or .m for lang: :objc). This is the <name>.c pattern the build.zig templates already use for project-level NIFs (c_src/<name>.c), extended to plugins. Returned paths feed the build's -Dplugin_c_nifs arg; build.zig derives the NIF name from the basename and applies -DSTATIC_ERLANG_NIF_LIBNAME=<name> so ERL_NIF_INIT emits the static-init symbol the driver table references (and adds -fobjc-arc for .m sources).

nif_sources(plugins, platform)

@spec nif_sources([plugin()], :ios | :android | :all) :: [String.t()]

Like nif_sources/1 but restricted to NIFs the given platform compiles.

A NIF entry with platform: :ios | :android is only compiled on that platform; an entry with no :platform is compiled everywhere. Lets a cross-platform plugin ship an iOS C/ObjC NIF and an Android NIF for the same module without the iOS source (which may reference iOS-only symbols) ending up in the Android build, and vice-versa. :all keeps every entry.

nifs(plugins)

@spec nifs([plugin()]) :: [map()]

Combined NIF entries across all plugins, with :native_dir resolved to an absolute path. Shape matches MobDev.StaticNifs entries (:module plus the plugin's native source dir), so the result can be fed straight into StaticNifs.resolve/1.

notification_handlers(plugins)

@spec notification_handlers([plugin()]) :: [map()]

Notification handlers across all plugins, flattened in plugin-then-declaration order (first match wins at dispatch), each tagged with :plugin.

plist_keys(plugins)

@spec plist_keys([plugin()]) :: map()

Merged iOS plist_keys across plugins (later plugins win on conflict).

screens(plugins)

@spec screens([plugin()]) :: [map()]

Static screen declarations across plugins, each tagged with :plugin.

Generator-produced screens (spec-v2 :screens_generator) are folded in separately by the runtime-manifest codegen; this is the static :screens half.

settings(plugins)

@spec settings([plugin()]) :: [map()]

Settings declarations across plugins, each tagged with :plugin.

static_archives(plugins, platform \\ :all)

@spec static_archives([plugin()], :ios | :android | :all) :: [map()]

Cross-compiled C++ static-archive contributions (lang: :cpp_archive) across plugins, resolved for one platform.

Unlike nif_sources/2 (a single source build.zig compiles inline), a :cpp_archive NIF is a set of C++ sources cross-compiled into a libNAME.a by MobDev.Plugin.CppArchive and static-linked into the app — the path for heavyweight NIFs like the Nx/Eigen CPU backend (Eigen headers, RTTI/exceptions, per-arch CXXFLAGS) that don't fit the single-source model.

Each returned spec has :sources (absolute) and :includes resolved: a plugin-relative string becomes absolute against the plugin dir, while a {:dep, name, subpath} token is passed through unchanged for the build to resolve against Mix.Project.deps_path/0 (Eigen/Fine live in the plugin's deps, not its own tree, and this module stays Mix-free/pure). CXXFLAGS and :nm_symbol pass through; the entry is tagged with :plugin.

swift_files(plugins)

@spec swift_files([plugin()]) :: [String.t()]

Absolute paths of all plugin iOS Swift source files.

ui_components(plugins)

@spec ui_components([plugin()]) :: [map()]

Combined ui_components entries across plugins.

zig_nif_sources(plugins)

@spec zig_nif_sources([plugin()]) :: [String.t()]

Absolute paths of each plugin zig NIF's primary source (NIFs whose manifest entry has lang: :zig).

Same <plugin_dir>/<native_dir>/<module>.zig convention as the C path, but fed to the build's -Dplugin_zig_nifs arg and compiled via addZigObject. Unlike C, no -DSTATIC_ERLANG_NIF_LIBNAME is needed — the zig source names its own export fn <module>_nif_init() directly. The plugin source reaches mob-core bindings via the named imports @import("erts") / @import("jni") that build.zig wires for plugin zig objects.

zig_nif_sources(plugins, platform)

@spec zig_nif_sources([plugin()], :ios | :android | :all) :: [String.t()]

Like zig_nif_sources/1 but restricted to the given platform (see nif_sources/2).