in_app_webview_flutter 1.1.0
in_app_webview_flutter: ^1.1.0 copied to clipboard
Inline WebView, headless WebView, and in-app browser for Flutter. SPA-safe App Shell, current Flutter/Dart, SPM-ready iOS. No donation banner.
In-App-Webview-Flutter #
in_app_webview_flutter (In-App-Webview-Flutter) is a maintained pub.dev package for embedding an inline WebView, running a headless WebView, and opening an in-app browser — updated for current Flutter/Dart, including Swift Package Manager-ready iOS/macOS platform deps, and without the upstream debug donation console banner.
This package is based on flutter_inappwebview (Apache-2.0) by Lorenzo Pichilli. Pub.dev package names cannot contain hyphens, so the published name is in_app_webview_flutter.
flutter_inappwebview_fx is unlisted. Use this package instead.
Why this package #
- Works with Flutter ≥ 3.32 / Dart ≥ 3.8 (tested on Flutter 3.47 / Dart 3.13)
- Pulls platform implementations that include Swift Package Manager support (avoids the
flutter_inappwebview_iosSPM warning on modern Flutter) - Keeps the familiar public API (
InAppWebView,HeadlessInAppWebView,InAppBrowser,ChromeSafariBrowser, cookie manager, etc.) - Adds Linux support via upstream platform packages
Requirements #
- Dart SDK:
^3.8.0 - Flutter:
>=3.32.0 - Android:
minSdkVersion >= 19, AGP>= 7.3.0 - iOS 12.0+, Xcode
>= 15.0(SPM-capable platform package) - macOS 10.14+, Xcode
>= 15.0 - Windows: NuGet CLI on
PATH - Linux: WPE 2.0 WebKit
Installation #
dependencies:
in_app_webview_flutter: ^1.0.0
import 'package:in_app_webview_flutter/flutter_inappwebview.dart';
Migration from
flutter_inappwebvieworflutter_inappwebview_fx: only the package/import name changes. Widget and class names stay the same.import 'package:in_app_webview_flutter/flutter_inappwebview.dart'; // or: import 'package:in_app_webview_flutter/in_app_webview_flutter.dart';Versioning: this package starts at
1.0.0. It is based on upstreamflutter_inappwebview6.2.0-beta.3 — see the CHANGELOG for the upstream base of each release.
Quick example #
import 'package:flutter/material.dart';
import 'package:in_app_webview_flutter/flutter_inappwebview.dart';
class SimpleWebView extends StatelessWidget {
const SimpleWebView({super.key});
@override
Widget build(BuildContext context) {
return InAppWebView(
initialUrlRequest: URLRequest(url: WebUri('https://flutter.dev')),
);
}
}
App shell: making a page feel native #
InAppWebViewFx is an opt-in wrapper around InAppWebView that applies a
declarative WebAppShell. Plain InAppWebView is untouched, so adopting it is
a drop-in change on a per-screen basis.
InAppWebViewFx(
initialUrlRequest: URLRequest(url: WebUri('https://shop.example.com')),
shell: WebAppShell(
// Hide the site's own header, nav and footer — Flutter supplies the chrome.
// Best-effort for classic HTML. Component SPAs usually need the picker.
hide: ElementHiding.preset(HidePreset.siteChrome)
.plusSelectors(['.newsletter-popup']),
// Body text unselectable, no long-press callout, forms still work.
selection: WebSelection.appLike,
// No white flash on load; page renders in the app's light/dark variant.
theme: WebTheme.of(context),
// Keep sticky bars clear of the home indicator.
safeArea: WebSafeArea.bottomOnly,
// Off by default — leave it off for third-party SPAs.
reportUnmatchedSelectors: false,
),
)
What the shell handles:
- Element hiding. Rules are enforced both as a native
css-display-nonecontent blocker (applied before first paint, and unaffected by a strictstyle-srcCSP) and as an injected stylesheet that is re-asserted on DOM mutations andhistory.pushStateroute changes, so single-page apps cannot bring hidden elements back.HidePreset.siteChrometargets classicheader/nav/footerlandmarks — React/Vue chrome often will not match. The CSS4iflag ([class*="Navbar" i]) works in the stylesheet path; native content blockers drop those selectors so one invalid flag cannot reject the whole rule list. - Text selection.
WebSelection.appLike,.noCalloutand.disabled. Editable elements are always exempt, so disabling selection does not break the site's forms. - Theme integration. A
backgroundColormakes the WebView transparent and paints Flutter's colour underneath, removing the white flash during load, andcolor-schemeis injected so the page picks its own dark variant.forceDarkFallback: trueinverts pages that have no dark theme at all, re-inverting images and video. - Safe areas.
env(safe-area-inset-*)reads as zero inside an embedded WebView, so Flutter's real insets are published as--fx-safe-top/--fx-safe-right/--fx-safe-bottom/--fx-safe-leftcustom properties, which first-party page CSS can also consume directly. - Error pages. The platform error page is suppressed and replaced with a
themed Flutter overlay offering a retry. Pass
WebErrorHandling(builder: ...)to supply your own.
Finding selectors #
Hard-coding selectors for a site you do not control is the fragile part, so the shell helps on both ends. Turn on the element picker in a debug build and tap whatever you want gone:
InAppWebViewFx(
elementPickerEnabled: kDebugMode,
onElementPicked: (controller, element) => debugPrint(element.selector),
shell: shell,
)
And when a site's markup later drifts, selectors that stop matching are reported rather than failing silently:
onUnmatchedSelectors: (controller, selectors, url) =>
debugPrint('stale hide rules on $url: $selectors'),
Reporting is off by default. When you turn it on (only while writing
rules), the same miss list is reported at most once per URL — SPA
pushState / hash changes and shell reinject do not flood the JS bridge.
Use WebAppShell(reportUnmatchedSelectors: false) for third-party SPAs.
Reshaping a site you do not own means its markup can change under you, and hiding third-party content may carry terms-of-service implications. Both are worth checking before shipping.
Embedding a third-party SPA (Flutter owns the tabs) #
When a Flutter NavigationBar drives a React/Vue site, do not pad the
page again and do not assume HidePreset.siteChrome matches:
InAppWebViewFx(
initialUrlRequest: URLRequest(url: WebUri('https://example.com')),
initialSettings: InAppWebViewSettings(
useShouldOverrideUrlLoading: true,
),
initialUserScripts: UnmodifiableListView([
UserScript(
groupName: 'app.probe',
source: 'if (!window.__appProbe) window.__appProbe = true;',
injectionTime: UserScriptInjectionTime.AT_DOCUMENT_START,
),
]),
shell: WebAppShell.appEmbedded(
theme: WebTheme.of(context),
// WebSafeArea.variablesOnly — Flutter's bar already owns the home indicator.
reportUnmatchedSelectors: false,
),
onReceivedServerTrustAuthRequest: (controller, challenge) async {
return ServerTrustAuthResponse(
action: ServerTrustAuthResponseAction.PROCEED,
);
},
onUpdateVisitedHistory: (controller, url, isReload) {
// Sync the selected Flutter tab from url.path.
},
shouldOverrideUrlLoading: (controller, action) async {
final scheme = action.request.url?.scheme;
if (scheme == 'http' || scheme == 'https') {
return NavigationActionPolicy.ALLOW;
}
return NavigationActionPolicy.CANCEL; // tel:, mailto:, custom schemes
},
)
InAppWebViewFx forwards production callbacks (onReceivedServerTrustAuthRequest,
onJsAlert / onJsConfirm / onJsPrompt, onReceivedHttpAuthRequest,
onReceivedLoginRequest, shouldInterceptRequest, …). Host UserScripts
are re-evaluated after a full document load (they must be idempotent); the
shell group is never removed to do this. Same-document SPA navigations are
handled in-page — Dart does not re-inject on every history tick.
Optional WebAppShell(diagnostics: WebViewDiagnostics.debug) emits one
[in_app_webview_flutter][perf] /path total=… line per full load.
The example app has two screens: App Shell (toggles) and Embedded SPA
(/app-embedded-spa) for this Flutter-nav + third-party site pattern.
For API corners the wrapper does not expose (deprecated Android/iOS-prefixed
aliases), drive the shell against a plain InAppWebView with
WebAppShell.applyToSettings, WebAppShell.buildUserScript,
WebAppShell.inject and WebAppShell.reapplyUserScripts.
Supported platforms #
Android · iOS · macOS · Windows · Linux · Web (via endorsed federated implementations)
Docs & upstream #
- Upstream docs: inappwebview.dev/docs
- Upstream API (same surface): pub.dev/documentation/flutter_inappwebview
- Upstream source: github.com/pichillilorenzo/flutter_inappwebview
License #
Apache License 2.0 — see LICENSE. Copyright remains with the original authors; this package is an independently published fork for pub.dev naming and Flutter currency.