lynx_view 1.8.1
lynx_view: ^1.8.1 copied to clipboard
Wraps LynxJS (https://lynxjs.org) native LynxView as a Flutter PlatformView, so existing Flutter apps can embed Lynx templates.
1.8.1 #
- iOS taps no longer vanish intermittently. Flutter's default gesture
blocking policy (
Eager) guarantees a platform view's gesture recognizers only theirtouchesBegan— the rest of a touch sequence may be cut off mid-stream whenever the framework decides to block. Lynx recognizes taps with its own nativeUITapGestureRecognizer, so a tap whose sequence was cut simply never fired. The iOS factory now registers withWaitUntilTouchesEnded, which lets Lynx's recognizers see every touch sequence whole and applies blocking only to recognition, at the end of the sequence. - Trade-off worth knowing: raw touch events of a sequence that a Flutter
widget wins (an overlay tap, an edge-swipe back) now reach the bundle as
touchstart/touchmove/touchend.bindtapis unaffected — it is driven by the native tap recognizer, which Flutter still blocks — but anything a bundle drives off raw touch events (:activehighlights, touch-following carousels) may react to touches that belong to Flutter. - Requires
lynx_view_ios1.8.1. Android is unaffected and unchanged.
1.8.0 #
- A bundle no longer lays itself out against a size the view does not have
yet. Flutter creates a platform view before it places it, and the native
side loaded the template right there — against a zero viewport. Lynx
resolves
%,flexandvhwhile laying out and does not redo that on its own, so a screen could come up collapsed into the top-left and stay that way: a centered spinner drawn in the corner, then white. - Both platforms now hold the first load until Flutter has given the view a
real size, then load once, with the right viewport. It costs about a frame
— the load itself is a network fetch — and it removes the workaround hosts
had settled on, which was to resize the view by a pixel after
onLoadSuccessso the template would lay out a second time. If you carry one of those, this is the release to drop it. - Requests are not lost while the view waits: a
reload()that arrives first is queued and the newest one wins, exactly as it already worked behind an in-flight load. - Behavior change worth knowing: a
LynxViewthat Flutter never gives a size to never loads its bundle. Parking one in a zero-height box no longer pre-warms it — it rendered nothing either way. - Requires
lynx_view_android1.8.0 andlynx_view_ios1.8.0.
1.7.3 #
- Completes the Android bridge fix started in 1.7.2. That release repaired the
JS -> Dart direction; this one repairs the reply. 1.7.2 said the other
direction was fine — that holds only for flat payloads.
sendEventhanded Lynx its arguments with a top-level-only conversion, so any nested object or list inside them was passed through as a plain JavaMap/Listand rejected when Lynx read it back, with the exception swallowed and the bundle seeing onlycannot convert to object. - So a bundle using
addJavaScriptChannelfor request/response still hung after 1.7.2: the request reached Dart, and the reply envelope ({id, ok, result}) never arrived, becauseresultis a structured object by definition. Verified on a real screen whose every data call goes through that protocol. - Requires
lynx_view_android1.7.2. iOS is unaffected and unchanged.
1.7.2 #
- Fixes the JS -> Dart bridge on Android, which had never worked. A bundle
calling
NativeModules.FlutterBridge.postMessage(...)had its message dropped without a log, soaddJavaScriptChannelnever fired and any request/response protocol built on top of it hung forever. The other direction (sendEvent, viaGlobalEventEmitter) was fine, so screens rendered and only the calls into the app went missing. iOS was unaffected and needs no change. - The cause was how the native module found the Flutter view it belonged to:
it asked
LynxContextfor itsLynxViewand read the id off the view's tag. Neither half answers on Android — Lynx 4.0.0 never callsLynxContext.setLynxView()anywhere in the SDK, andLynxViewoverridesgetTag()to return the constant"lynxview". On iOS the same code works because aLynxViewis aUIViewwhosetagreally is an integer. - The view id is now handed to the module when it is built, through Lynx's
per-view module registration, so nothing has to be read back off the view.
Dropped messages are logged instead of swallowed, and the routing is
covered by unit tests that need no live
LynxView.
1.7.1 #
- Fixes the iOS build. 1.7.0's font registration called the Objective-C
selectors as written in Lynx's header —
sharedManager()andregisterFont(_:forName:)— but the header carries noNS_SWIFT_NAME, so Swift's automatic renaming applies and the real names areshared()andregister(_:forName:). Any app on 1.7.0 fails to compile for iOS with "'sharedManager()' has been renamed to 'shared()'". Android was unaffected.
1.7.0 #
- Fonts. A template could name a
font-familyand never get one: Lynx does not load fonts by itself —@font-face src: url()is delegated to a resource fetcher this package does not ship, and the built-in loader understands onlylocal()and inlinedata:URIs — so every custom family fell through to the system font, silently, the same failure shape the image service had before 1.5.0.LynxViewControllernow takesfonts:, a list ofLynxFontAsset(family:, assetPath:), and the native side registers those Flutter assets with Lynx while the view is being created, before the first template load. - Nothing is fetched. A host app that already ships a typeface for its own UI
hands Lynx the same asset — no CDN to stand up, no download in front of the
first paint, and no drift between what Flutter draws and what a template
draws. Fonts declared under
fonts:in the host'spubspec.yamlare in the asset bundle already, so there is no second copy. - One family is one weight. Lynx resolves
font-familyby name alone: it has no way to choose between weights registered under one name, and on Android every CSS weight from 500 up collapses into a single "bold" slot (TextAttributes.isFontWeightBOLD). RegisterPretendard-RegularandPretendard-Boldas two families and let the template pick withfont-familyrather thanfont-weight. - Registration is per-process and idempotent — re-listing a family on a later view skips the decode rather than repeating it. A font that will not load is skipped with a log; the screen keeps rendering in the system font, exactly as it did before.
1.6.0 #
- Recoverable errors no longer arrive as
onLoadError. Lynx reports every error through one native callback — a template that failed to load, but also an<image>src that 404'd or a runtime warning. 1.5.0's image pipeline made the latter kind common, and consumers treatingonLoadErroras fatal started killing whole screens over one missing thumbnail. Fatal errors (LynxError's ownisFatal) keep firingonLoadError; everything else goes to the new optionalonReceivedErrorcallback, for logging rather than teardown.
1.5.0 #
<image>now renders remote sources. Lynx delegates all image fetching, decoding and caching to a host-registered image service, and renders nothing — silently — when there is none; this package never shipped one, so every remotesrccame out as an empty box. Android now shipslynx-service-imageon Fresco and registers it beforeLynxEnvinit; iOS pullsLynxService/Image(SDWebImage-backed), which self-registers at load.- Images are cached by those native libraries' own memory and disk caches.
Nothing is shared with the host app's image stack (e.g. Flutter's
CachedNetworkImage) — a URL seen by both sides is fetched once per side. - On Android, Fresco is initialized by the plugin only if the host app has not already done so — initializing twice resets Fresco's caches.
1.4.0 #
- XElement's elements —
<input>,<textarea>,<svg>,<overlay>,<viewpager>,<refresh>and the rest — now work. Lynx's core registers only 13 UI elements and leaves everything else to XElement, which this package did not ship. A template using<input>loaded successfully, rendered an empty box, and never took focus, with nothing in the log: Lynx skips tags it does not recognise silently. - Fixed release builds on Android, which failed in R8 once XElement was
added. Two of its artifacts reference libraries they do not declare —
Fresco, from the remote-image path of
<svg>, and the Serval markdown engine, which is not published to Maven at all. <markdown>remains unsupported on both platforms. On iOS its subspec pulls statically linked binaries that CocoaPods refuses under theuse_frameworks!every Flutter Podfile declares; on Android its engine does not exist as an artifact. The dependency is excluded rather than shipped as dead code.<svg>renders inline sources out of the box. Loading one from a remote URL goes through Fresco, which an app wanting that must add itself — Lynx expects the host to supply its own image service.
1.3.0 #
- The example app now uses
com.example.*identifiers, the same as a freshflutter create. It carried the maintainer's own reverse-DNS prefix for no reason, which is not what someone cloning the example wants to inherit.
1.2.1 #
- Removed the maintainer's Apple
DEVELOPMENT_TEAMfrom the example project — it served no purpose in a template and only produced signing errors for anyone building the example under their own account. - README now documents the memory APIs added in 1.2.0 and points at
docs/ko/memory.md; the 1.2.0 listing still described the 1.0.0 surface.
1.2.0 #
-
Fixed: Android release builds failed with R8. Lynx references Gson from
LynxEnv.GetNativeEnvDebugDescription()without depending on it, so every consuming app'sassembleReleasedied withMissing class com.google.gson.Gson. The plugin now ships a consumer ProGuard rule, so apps need no workaround of their own. Debug builds never showed this. -
Fixed (iOS): the native
LynxViewwas never explicitly torn down. Release was left entirely to ARC, and because Lynx holds internal references of its own the engine could outlivedispose()indefinitely — memory measured after tearing down five views went up, not down.clearForDestroyis now called, which makes release deterministic; the same measurement now reclaims what it allocated. -
Fixed (Android):
destroy()ran twice on the same native view. Both the controller's explicitdispose()and the engine'sPlatformView.dispose()reach the same teardown path in the normal flow, and nothing guarded against the second pass. -
Added
LynxMemory.trim(). Flutter already surfaces the platform's memory-pressure signal and Lynx already exposesLynxEnv.trimMemory, but nothing connected the two — a liveLynxViewheld its caches right up to the moment the system killed the app. The relay installs itself only while aLynxViewis mounted. -
Added
LynxMemory.usage(). Per-instance memory attribution (element tree, platform views, main-thread and background JS runtimes) plus the app's own physical footprint, so "where does a LynxView's memory go" is answerable without guessing from RSS.
1.0.0 #
- Initial release:
LynxViewwidget andLynxViewControllerfor embedding LynxJS (https://lynxjs.org) templates in Flutter apps via a native PlatformView.