Lifecycle and performance
WebView ownership
There are three useful ownership patterns:
| Pattern | Use case | Native WebView lifetime |
|---|---|---|
Normal InAppWebView | One screen owns the WebView | Ends when the widget/controller is disposed |
InAppWebViewKeepAlive | Temporary widget detach or route replacement | Retained across reattachment |
InAppWebViewPreloader | Known destination that should open faster | Starts headless, then transfers to inline |
The owner must be created outside build(). A Flutter rebuild must not be treated as a request to create a new native WebView.
Safe lifecycle sequence
create -> prepare -> attach -> ready -> detach/retain -> reattach -> disposeDispose is idempotent. Once disposal begins, new events and asynchronous operations should not be sent to the native WebView. Pending callbacks keep their existing result contract and complete once.
Avoiding cold starts
- Keep
InAppWebViewKeepAlivestable while a screen is temporarily removed. - Use
InAppWebViewPreloaderwhen the destination and initial settings are known before navigation. - Keep the initial settings stable; changing profile, container, incognito, or data-store settings usually requires a new native WebView.
- Do not clear cache or cookies as a generic performance workaround.
- Do not reload a page merely because the Flutter widget rebuilt.
Event pressure
Scroll, progress, JavaScript bridge, and WebMessage callbacks can be high frequency. Application callbacks should avoid expensive synchronous work, large map copies, and unnecessary state updates. Coalesce UI updates when the application only needs the latest value.
Memory trade-off
Retaining a WebView preserves page state but also retains its renderer, JavaScript context, callbacks, and data-store references. Keep only the WebViews that the user is likely to revisit. Always dispose retained instances when the owning feature or session ends.
Performance checklist
- Measure release/profile builds, not only debug builds.
- Record the Android WebView provider or iOS version with measurements.
- Measure first usable frame separately from
onLoadStop. - Test repeated attach/detach and dispose/recreate cycles.
- Check memory after navigation to a heavy page and after disposal.
- Treat provider, renderer, and OS behavior as separate from Flutter widget rebuild performance.