In a Flutter federated plugin, what do the app-facing, platform-interface and platform packages each contain, and why split a plugin that way?
answer
- three roles, often three-plus packages
- app depends only on the app-facing one
- abstract Platform class with static instance
- each platform package registers itself
- domain experts add a platform independently
basics
~20 sThe app-facing package holds the public API apps call; the platform-interface package holds an abstract class every implementation extends; each platform package implements it for one platform and registers itself. The split lets platforms ship and version independently.
solid answer
~30 sA federated plugin separates three roles. The **app-facing package** (for example `url_launcher`) is the only one app code imports; it forwards calls to `SomethingPlatform.instance`. The **platform-interface package** (`url_launcher_platform_interface`) declares that abstract class, extending `PlatformInterface` from `plugin_platform_interface`, usually with a default method-channel implementation. Each **platform package** (`url_launcher_android`, `url_launcher_web`, …) declares `implements: url_launcher` in its pubspec, subclasses the interface and sets `instance` in a static `registerWith()`. The payoff: someone with Windows or web expertise can add or fix one platform without touching the others, each package gets its own version and release cadence, and a single uniform interface keeps behaviour consistent across platforms.
go deeper
Know the three package roles by name and that an app imports only the app-facing package.
Explain how a platform package declares implements, subclasses the abstract Platform class and sets its static instance from registerWith() at startup.
Weigh when federation earns its overhead and treat the platform interface as the most change-sensitive package in the set.
Decide package boundaries for a plugin that several teams or outside contributors will extend, including who owns the interface and its release policy.
## What "federated" means A **federated plugin** splits a plugin's API into a platform interface, independent platform implementations of that interface, and an app-facing API that uses whichever implementation is registered for the running platform. When each role lives in its own Dart package, the docs call it a **package-separated federated plugin**; that is the shape every large first-party plugin in `flutter/packages` uses. ## The three roles | Role | Example | Contains | Who depends on it | |---|---|---|---| | **App-facing** | `url_launcher` | The public Dart API; delegates every call to the platform instance | The app | | **Platform interface** | `url_launcher_platform_interface` | An abstract `UrlLauncherPlatform` class plus a default implementation | App-facing and every platform package | | **Platform implementation** | `url_launcher_android`, `url_launcher_ios`, `url_launcher_web`, … | Host code plus a Dart subclass of the interface | Normally only the app-facing package (endorsed) | Key points about each: - The **app-facing package** has no platform logic of its own in the pure form. Its public functions validate and convert their arguments, then delegate to `UrlLauncherPlatform.instance`. Apps import only this. - The **platform-interface package** defines the contract: an abstract class that extends `PlatformInterface`, a static `instance` getter and setter, and methods whose default bodies throw `UnimplementedError`. It usually ships a `MethodChannel…` default so a platform that just uses a channel needs little Dart code. - A **platform package** declares, in its own pubspec, which app-facing package it serves: ```yaml flutter: plugin: implements: thermo platforms: web: pluginClass: ThermoWeb fileName: thermo_web.dart ``` and its Dart class sets `ThermoPlatform.instance = ThermoWeb()` inside a static `registerWith()`, which the tool's generated registrant calls at startup. ## Why split it 1. **Independent expertise.** A developer who knows one platform well can write `thermo_windows` without owning the Android or iOS code. The docs name this as the main benefit. 2. **Independent versions.** A web bug fix releases `thermo_web` alone; apps pick it up through normal version solving without a new release of the app-facing package. 3. **A uniform contract.** Because every implementation subclasses the same interface, all platforms expose the same methods and types. 4. **Smaller blast radius.** A change to one platform's native build cannot break another platform's package. ## The costs - More packages to publish, test and keep in step. The platform interface becomes the most sensitive package: a breaking change there forces every platform package to update. - More indirection when debugging — a call passes through the app-facing package, the static `instance`, and then a platform subclass. - For a small plugin with two platforms and one maintainer, a single package (inline implementations in one pubspec) is often simpler. Federation pays off as platforms, contributors or release cadences multiply. ## How it looks at runtime At build time the tool resolves, for each platform, which package implements `thermo` and generates registrants for it. When the app starts, the chosen platform package's `registerWith()` replaces the interface's default `instance`. From then on, the app-facing API talks only to that instance; app code never names a platform package. ## Misconceptions to avoid - Apps do not import `thermo_android` or `thermo_web` directly for normal use; they import `thermo`. - The platform interface is not optional glue: without it, implementations could drift apart. - Federation is about package structure, not a different transport — the Android package may still talk to its Kotlin code over a method channel or generated Pigeon code.
- Where does the default implementation of a federated plugin usually live, and what is it?In the platform-interface package: its abstract class initialises the static `instance` to a method-channel implementation. Platform packages that only need a channel can rely on it, while others replace `instance` with their own subclass in `registerWith()`.
- Can a federated plugin keep some platforms inside the app-facing package?Yes. An app-facing pubspec may give some platforms an inline `pluginClass` and point others at separate packages with `default_package`. The docs show exactly that mix, for example Android and iOS inline and Windows in a separate package.
Like a power adapter standard: the app-facing package is the plug the appliance uses, the platform interface is the published socket specification, and each platform package is a national adapter built by someone who knows that country's wiring.
saying these in an interview costs you the question
- Apps must import each platform package alongside the app-facing one.
- The platform interface package contains the native Kotlin and Swift code.
- Federated plugins use a different transport than method channels.
- Every plugin should be federated regardless of size.
- Platform packages can change the interface's methods on their own.