fresnel_ios

The iOS implementation of fresnel.

Apps should not depend on this package directly. Depend on fresnel; the Flutter tool selects this package automatically on iOS.

What it bridges

Dart SwiftUI
GlassSurface .glassEffect(_:in:)
GlassContainer GlassEffectContainer(spacing:)
GlassElementView(id:) .glassEffectID(_:in:)
GlassElementView(unionId:) .glassEffectUnion(id:namespace:)
GlassShape.concentric() ConcentricRectangle
GlassSymbol UIImage(systemName:withConfiguration:)

Why SwiftUI and not UIKit

UIKit's UIGlassEffect renders a material, but has no equivalent of glassEffectID morphing or glassEffectUnion. Bridging SwiftUI through a UIHostingController is the only route to the full material, which is why this package hosts SwiftUI views rather than wrapping UIVisualEffectView.

How the bridge is shaped

The platform view renders only the material. Your content stays an ordinary Flutter subtree composited above it, and the hosting view has isUserInteractionEnabled = false with hitTestBehavior: PlatformViewHitTestBehavior.transparent.

That means text rendering, gesture handling, navigation and accessibility never cross the FFI boundary. Interactive glass is driven by an explicit setPressed call from Flutter's gesture arena rather than by the native view observing touches. It costs one method channel message per press and buys immunity to the whole class of failures — unreliable Navigator.pop, lost provider state, broken hot reload — that comes from letting native views own interaction.

Nothing here replaces Flutter's root view controller.

Two things the container bridge gets right on purpose

Both were found by rendering to a device and looking, not by reading the docs.

Elements are placed with position, never offset. offset translates at render time and leaves the layout frame where it was. GlassEffectContainer derives merge geometry from layout frames, so with offset every element reports the same rect and the whole group fuses into one blob at the origin.

glassEffectUnion is not used. It reconciles members by layout position, and every element here is absolutely placed from a rect Flutter resolved, so a union collapses onto a single member's shape. A union means "fuse at any distance", and distance is what a container's spacing controls — so each union group is rendered in its own nested GlassEffectContainer whose spacing is derived from the group's own bounds. Deriving it beats a large constant: spacing also sizes the shared sampling region, and an arbitrary huge value makes the OS reserve one far bigger than the group needs.

Deployment target

The podspec and Package.swift declare iOS 13. Every glass call site is gated with #available(iOS 26.0, *), so one binary serves both and apps on older iOS still link and run — they simply get the shader path.

Capabilities

getCapabilities answers natively:

ProcessInfo.processInfo.isOperatingSystemAtLeast(
    OperatingSystemVersion(majorVersion: 26, minorVersion: 0, patchVersion: 0)
)

Not a regex over a version string. Accessibility flags come from UIAccessibility; hasImpeller is answered on the Dart side, which is the only side that can see the renderer.

Verifying Apple's API surface

Published documentation for Liquid Glass is frequently wrong — glassEffect has no isEnabled: parameter despite what most references claim. Check the SDK:

grep -n "func glassEffect" \
  "$(xcrun --sdk iphonesimulator --show-sdk-path)/System/Library/Frameworks/SwiftUICore.framework/Modules/SwiftUICore.swiftmodule/arm64-apple-ios-simulator.swiftinterface"

Known issue

A Flutter BackdropFilter in the same scene suppresses native glass platform views entirely. fresnel prevents the combination by scoping the render path per route — see KNOWN_ISSUES.md in the repository.

License

MIT

Libraries

fresnel_ios
iOS implementation of fresnel.