Containers

Sparkling content always runs inside a native container — a platform view that hosts the Lynx runtime. The SDK provides two container modes to fit different use cases.

Two container modes

Full-pageEmbedded
What it isA dedicated screen (UIViewController / Activity) that manages its own nav bar, status bar, and lifecycleA plain view (UIView / FrameLayout) you place inside an existing native layout
Typical useStandard page navigationCards, banners, partial-screen panels, or any native screen that mixes native and Lynx UI
iOS classSPKViewController (via SPKRouter)SPKContainerView
Android classSparklingActivity (via Sparkling.navigate())SparklingView (via Sparkling.createView())

Full-page containers

Full-page containers are the default way to display Sparkling content. The native layer manages the navigation bar, status bar, screen orientation, and loading/error views — you configure them via scheme parameters.

iOS

// Option A: push onto an existing navigation stack
SPKRouter.open(withURL: "hybrid://lynxview_page?bundle=detail.lynx.bundle&title=Detail", context: nil)

// Option B: create and manage the VC yourself
let vc = SPKRouter.create(withURL: url, context: SPKContext())
navigationController.pushViewController(vc, animated: true)

Android

val ctx = SparklingContext().apply {
  scheme = "hybrid://lynxview_page?bundle=detail.lynx.bundle&title=Detail"
}
Sparkling.build(this, ctx).navigate()   // starts SparklingActivity

Configuration via scheme

Full-page containers are configured through URL query parameters. Some common ones:

ParameterEffect
titleNavigation bar title
hide_nav_bar=1Hide the navigation bar
hide_status_bar=1Hide the status bar
trans_status_bar=1Transparent status bar (content extends behind it)
show_nav_bar_in_trans_status_bar=1Keep nav bar visible even with transparent status bar
nav_bar_colorNavigation bar background color
container_bg_colorContainer background color

See Scheme for the full parameter list.

Embedded containers

Embedded containers let you place Sparkling content anywhere inside a native layout. You control the frame, and the container renders Lynx content within it.

iOS — SPKContainerView

// 1. Create and add to your view hierarchy
let spkView = SPKContainerView(frame: containerView.bounds)
spkView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
containerView.addSubview(spkView)

// 2. Load a bundle
let context = SPKContext()
spkView.load(withURL: "hybrid://lynxview?bundle=card.lynx.bundle", context)

Content sizing (iOS)

By default, the container keeps its assigned frame. Set sparkContentMode to let the container resize based on Lynx content:

ModeBehavior
FixedSize (default)Container keeps its frame; Lynx fills it.
FixedWidthWidth stays fixed; height adjusts to content.
FixedHeightHeight stays fixed; width adjusts to content.
FitSizeBoth dimensions adjust to content.

After loading completes, read preferredLayoutSize to get the content's intrinsic size.

Android — SparklingView

// 1. Create via Sparkling builder
val ctx = SparklingContext().apply {
  scheme = "hybrid://lynxview?bundle=card.lynx.bundle"
}
val spkView = Sparkling.build(this, ctx).createView()

// 2. Add to your layout and load
container.addView(spkView)
spkView?.loadUrl()

Lifecycle

Full-page containers

Lifecycle is managed automatically. The SPKViewController / SparklingActivity forwards viewDidAppear / onResume and viewDidDisappear / onPause to the Lynx runtime. No extra work needed.

Embedded containers

Since the SDK has no control over your hosting view controller or fragment, you must forward visibility events manually. If you skip this, the Lynx runtime won't know when to pause timers, animations, or network requests.

iOS:

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    spkView.handleViewDidAppear()
}

override func viewDidDisappear(_ animated: Bool) {
    super.viewDidDisappear(animated)
    spkView.handleViewDidDisappear()
}

Android:

// Fragment.onResume or when the view becomes visible
spkView?.onShowEvent()

// Fragment.onPause or when the view becomes hidden
spkView?.onHideEvent()

// When permanently destroying the view
spkView?.release()

Lifecycle delegate (iOS)

Set containerLifecycleDelegate on the SPKContext to observe loading status. This works for both container modes:

context.containerLifecycleDelegate = self

// Key callbacks:
func container(_ container: SPKContainerProtocol,
               didFinishLoadWithURL url: URL?) { /* loaded */ }
func container(_ container: SPKContainerProtocol,
               didLoadFailedWithURL url: URL?, error: Error?) { /* failed */ }
func containerDidFirstScreen(_ container: SPKContainerProtocol) { /* first paint */ }

Communicating with Lynx

Both container modes support sending events and updating global props at runtime.

Send events

iOS (both modes):

spkView.send(event: "refresh", params: ["key": "value"], callback: nil)

Android (embedded):

spkView?.sendEventByJSON("refresh", JSONObject().put("key", "value"))

Update globalProps

iOS (both modes):

spkView.update(withGlobalProps: ["theme": "dark"])

Android (embedded):

spkView?.updateGlobalPropsByIncrement(mapOf("theme" to "dark"))

Next steps