GenericJam

GenericJam

Proposed Plugin System for Mob - BEAM Mobile Framework

Plugin System for Mob

Mob is growing by leaps and bounds! I realize now we will not be able to accommodate all the functionality people would want in the main framework itself. It is designed to be extensible. The build system should be able to handle plugins now.

The idea for the plugins is similar to React Native plugins. This is more than coincidence because React Native and Mob have similar architectures, with Mob being a bit simpler. The native code in Kotlin/Java, Swift/ObjC, C is likely very close to what Mob would need. The main difference is the logic is in Elixir, not JS and the distribution is hex.

One of the upsides of the similarity is we could migrate many of these to Mob which would be a big boost to the ecosystem. There are ~150-200 that land in this ‘native heavy’ category that would be very attractive to use such as date pickers, etc. that translate to native elements.

So you’d have the Android native code in /android and the iOS native code in /ios. You could have one sided plugins that only land on one platform.

I’ve brainstormed a pretty extensive document on this with Claude. Here’s the shorter summary:

Mob Plugins: Manifest Schema Proposal

Three design choices anchor this proposal. First, the manifest is data, not code — mob_dev reads priv/mob_plugin.exs at compile time rather than having plugins call register_plugin at runtime. Static, inspectable, validatable; closer to mix.exs than to Phoenix’s runtime route registration. Second, activation is explicit and separate from installation, borrowed from how iOS entitlements work: a framework supporting capability X doesn’t mean your app uses X without explicit declaration. This mitigates supply-chain risk by ensuring mix deps.get can never silently modify your app’s permission set. Third, the schema scales with plugin tier rather than being exhaustive everywhere — small plugins write three fields, large plugins write a dozen sections, and the shape of the manifest doesn’t make trivial plugins look heavy. Underlying all of this: Hex is the substrate, so versioning, dep resolution, security posture, and hexdocs publication come free, and static linking is required (no dlopen) to stay App-Store-compatible.

The schema spans five tiers. Tier-0 is a pure Elixir Hex package needing no manifest at all. Tier-1 adds NIFs and per-platform native sources — Kotlin bridge files, Swift files, Gradle deps, frameworks, permissions, plist keys. Tier-2 introduces :ui_components for new render-tree node types with paired SwiftUI views and Composables. Tier-3 layers on :screens, :migrations, and :assets for plugins that ship entire mini-applications. Tier-4 adds :lifecycle, :settings, and :notifications for embedded sub-apps with supervised children, persisted user settings, and push notification handlers. Required top-level fields are just :name, :mob_version, and :plugin_spec_version; everything else is independently optional.

Installation is deliberately two-step. Adding a plugin to deps and running mix deps.get makes it resolvable but does not merge native code, permissions, or plist keys. Activation requires an explicit entry in config :mob, :plugins in mob.exs. mob_dev prints the diff at compile time so users see exactly what’s being added — permission set changes are never silent. mix mob.add_plugin wraps both steps plus optional interactive setup prompts where plugin authors guide tier-3/4 integration (e.g., “Register MobChatKit.MessageListScreen in your App.navigation/1?”). The standard flow always works; the convenience command is not a required entry point.

Validation runs at two stages and fails loud. mix mob.validate_plugin checks the plugin in isolation: paths exist, files parse, version requirements are valid, and single-platform UI components are flagged as warnings (the #1 React Native plugin pain point). mob_dev then re-validates at compile time across all activated plugins — no duplicate component atoms, no colliding screen routes, no migration namespace collisions, all activated plugins present in deps. Hot-pushability is computed automatically from which sections are populated: tier-0 hot-pushes fully, tiers 1-2 require a native rebuild, tiers 3-4 are partial (Elixir hot-pushes; native does not). Forward compatibility is handled via :plugin_spec_version, letting the schema evolve without breaking existing plugins — bump the integer, support both versions in mob_dev for a migration window, deprecate.

Any comments or questions are appreciated.

Where Next?

Popular in RFCs Top

benlime
In the last couple of days I was playing around with LiveView, function components and animations. I ended up with a little prototype whi...
New
pknoth
Built on top of boruta | Hex, I am on the way to creating a standalone OAuth 2.0/OpenID Connect server thinking of a lightweight Keycloak...
New
christhekeele
TL;DR: I’m planning on building a library, inspired by Vapor, to make configuring Elixir applications more straight-forward; in an approa...
New
ca1989
Hi all, this week I played a bit with Phoenix and Elm. I ended up with this POC: https://github.com/carlotm/elmex The repository cont...
New
bennydreamtech23
So recently I have been looking for ways to improve my workflow in elixir and I saw all the commands I need to run to setup a project and...
New
Overbryd
Polyglot-Ex Rust and wasmex bindings for polyglot. State: Pre-release Hi there, I am starting a thread for my humble bindings library ...
New
wolf4earth
Every protocol you’ve shipped assumes the spec doesn’t change during the connection. This one doesn’t. Code is typed, composable, content...
New

Other popular topics Top

vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
AstonJ
Seen any cool LiveView demos, sample apps or examples? Please post them here! :003:
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
dblack
I’ve got an issue with an app and I’ve no idea of how to troubleshoot it. I’m hoping someone here might have seen something similar. I p...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New

We're in Beta

About us Mission Statement