Flitzdocs
Loader plugins

API reference

The public Kotlin and Swift surface of the loader, the flitz { } Gradle block, and the iOS Info.plist keys.

The loader's surface is deliberately small. Everything not listed here is internal to the AAR or the xcframework and is not part of the contract. There is no configure(...) call: what the loader checks bundles against comes from your host build, which the Flitz SDK prepares (see Compatibility).

Kotlin

Package pl.leancode.flitz.loader, from pl.leancode.flitz:loader-android.

package pl.leancode.flitz.loader

// Entry point for download links. Shows the sign-in (with sign-in), download,
// and error screens, and starts BundleRunnerActivity once a bundle passes the
// loader's checks. Registered in the AAR manifest (exported, singleTask) for
// <scheme>://download links, in the loader's own ":flitz" process and task.
public open class BundleLoaderActivity : AppCompatActivity {
    public companion object {
        // Action of the local-file entry; the path goes in EXTRA_FILE_PATH.
        public const val ACTION_LOAD_FILE: String = "pl.leancode.flitz.loader.action.LOAD_FILE"
        // String extra: the filesystem path of the .flitz to load.
        public const val EXTRA_FILE_PATH: String = "pl.leancode.flitz.loader.extra.FILE_PATH"
    }
}

// Hosts the bundle's Flutter engine and FlutterView, in the ":flitz" process.
// Registered in the AAR manifest with no intent filter. Not launched directly —
// BundleLoaderActivity starts it, and leaving it tears the engine down and
// removes the bundle's extracted files.
public open class BundleRunnerActivity : AppCompatActivity

// The panel. Registered in the AAR manifest (exported) for
// <scheme>://flitz-panel links, in the ":flitz" process and task. Without
// sign-in it finishes at once, showing nothing.
public class PanelActivity : AppCompatActivity

You do not subclass any of these activities, declare MAIN/LAUNCHER on them, or change their process. You interact with the Android loader through the Gradle plugin: apply it and list flavors in flitz { enabledFlavors } — see the Android quickstart.

Your own native code may open a download link or the panel with an explicit intent. Put that code in the loader flavor's source set (for example android/app/src/withLoader/), never src/main: a flavor without the loader has no such classes.

// Open a download link of any scheme; the `download` host decides.
startActivity(
    Intent(this, BundleLoaderActivity::class.java)
        .setAction(Intent.ACTION_VIEW)
        .setData(Uri.parse(downloadLink))
)

// Open the panel (needs sign-in).
startActivity(Intent(this, PanelActivity::class.java))

Leaving the loader — Back, Cancel, or the system back gesture — returns to your activity, or to the panel when the build was started from it.

The flitz { } Gradle block

Registered by the pl.leancode.flitz.loader Gradle plugin on the app module.

Prop

Type

For each active variant the plugin adds pl.leancode.flitz:loader-android at its own version, registers urlScheme for the loader's links, passes the sign-in and panel settings to the loader, moves the launcher to the panel when launch = "panel", and runs an SDK floor check before the build: the build fails when your Flitz SDK is older than this plugin version supports. Invalid sign-in, panel, or launch settings fail the build even when no flavor is active — see Sign-in and the panel and Troubleshooting → Gradle.

Swift

Module FlitzLoader, from FlitzLoader.xcframework (iOS 16.0+, arm64 devices).

// Drop-in app delegate base class; subclass this instead of FlutterAppDelegate.
// Routes the loader's URLs received via application(_:open:options:). A
// download URL — or a flitz-panel URL, with sign-in — hands the app's window to
// the loader and shuts down your app's own Flutter engine.
open class BundleLoaderAppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate {
    // If you override it, return super's result, as Flutter's template does.
    open override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
    ) -> Bool

    open override func application(
        _ application: UIApplication,
        open url: URL,
        options: [UIApplication.OpenURLOptionsKey: Any] = [:]
    ) -> Bool

    // Implemented by the loader; not overridable. Calls registerHostPlugins(with:).
    public func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge)

    // Your app's own plugins, on the engine that renders your UI. Default: no-op.
    // Override and call GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry).
    @objc open func registerHostPlugins(with engineBridge: FlutterImplicitEngineBridge)

    // Called once per bundle engine, right after it starts and before it is
    // shown. Default: no-op. Override and call
    // GeneratedPluginRegistrant.register(with: engine).
    @objc open func registerPlugins(with engine: FlutterEngine)
}

// Drop-in scene delegate base class for UIScene apps. Routes the loader's URLs
// received via scene(_:openURLContexts:) and at launch, forwards the bundle's
// own deeplinks to the running bundle engine, and replays the captured scene
// connection into that engine once it exists. With Launch set to panel, it
// roots the window on the panel at launch.
open class BundleLoaderSceneDelegate: FlutterSceneDelegate {
    open override func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>)
    open override func scene(
        _ scene: UIScene,
        willConnectTo session: UISceneSession,
        options connectionOptions: UIScene.ConnectionOptions
    )
}

// Hands a link or a local file to the loader from your own native code.
public enum BundleLoader {
    // Returns true for a download, flitz-panel, or flitz-auth URL of any
    // scheme, and acts on it one main-queue turn later: the download screen
    // (after the sign-in step, with sign-in), an "Invalid URL" error, or the
    // panel takes the window. Without sign-in a flitz-panel URL is dropped; a
    // flitz-auth URL is always dropped. Returns false, and does nothing, for
    // any other URL. Callable from any thread.
    @discardableResult
    public static func handle(url: URL) -> Bool

    // Loads the .flitz at a file URL one main-queue turn later. A URL that
    // names no readable file shows "Bundle file not found". Callable from any
    // thread.
    public static func load(fileAt url: URL)
}

Notes:

  • Override both app-delegate hooks: registerHostPlugins(with:) for your app's own engine and registerPlugins(with:) for each bundle engine. Do not redeclare FlutterImplicitEngineDelegate or didInitializeImplicitFlutterEngine(_:). The loader cannot reference GeneratedPluginRegistrant (it is generated in your project); without registerPlugins(with:), bundles run with no plugins and method-channel calls fail with MissingPluginException.
  • BundleLoaderSceneDelegate does not install a root view controller — except with Launch set to panel, where it roots the window on the panel. Otherwise your scene delegate or Info.plist still configures the app's initial UI. When you override scene(_:willConnectTo:options:), call super first; with Launch panel, install no root of your own.
  • Both delegates claim only the loader's own URLs — the download, flitz-panel, and flitz-auth hosts on your scheme; any other URL falls through to your own open-URL handling. See the URL scheme.
  • Your own native code opens the panel with BundleLoader.handle(url: URL(string: "<your-scheme>://flitz-panel")!), and hands over a download link the same way.
  • Plugins that rely on FlutterPluginRegistrar.addApplicationDelegate(_:) may not work inside bundles: the bundle engine's registrar is invoked outside the standard app-delegate forwarding chain. We are working on a fix.

Info.plist keys

iOS reads the loader's settings from ios/Runner/Info.plist:

  • The URL type named FlitzLoader — the CFBundleURLTypes entry whose CFBundleURLName is FlitzLoader. Its first CFBundleURLSchemes value is the loader's scheme. Sign-in requires the name.
  • The FlitzLoader dictionary, all of whose keys are optional:

Prop

Type

A broken combination does not fail the build. The app launches into your own UI, and every load and every opening of the panel shows Loader build is broken, naming the first problem — see Troubleshooting → Info.plist settings. For what each level does, see Sign-in and the panel.

On this page