Skip to content

Setting Up the WebView SDK

Free

What you'll learn

  • Picking webview_sdk over webview_sdk_advanced (they're independent — pick one)
  • Generating the self-contained WebView SDK
  • Configuring platform permissions for Android and iOS
  • Embedding the WebView widget and wiring up its callbacks
  • Intercepting custom URI schemes for in-app navigation
  • Making one-way calls from Dart into the page's JavaScript context

Prerequisites

Step 1: Pick a Package — Basic or Advanced

Archipelago ships two independent, self-contained WebView bricks. Install whichever one matches your needs — not both:

BrickTierUse it when...
webview_sdk (this tutorial)FreeYou need URL loading, navigation controls, progress tracking, one-way JS calls, and URI scheme interception
webview_sdk_advancedProYou additionally need a bidirectional JS bridge, request interceptors, or the mini-app container

webview_sdk_advanced does not require webview_sdk to be generated first, and does not extend or build on it — it is not an upgrade path. Installing both in the same app is not a supported layering model.

Step 2: Generate the WebView SDK

bash
archipelago generate webview_sdk

This brick has no configuration variables — generation is entirely non-interactive, so there's no prompt to answer and no config file to pass.

Step 3: Understand the Generated Structure

webview_sdk generates a single, self-contained package — contract and flutter_inappwebview-backed implementation together, no API/Impl split:

features/webview/
└── webview/
    └── lib/src/
        ├── webview_sdk.dart                    # WebViewSDK contract
        ├── webview_sdk_impl.dart                # flutter_inappwebview-backed impl
        ├── webview_controller.dart              # WebViewController interface
        ├── webview_inappwebview_controller.dart # Concrete controller
        ├── di/
        │   └── webview_global_module.dart       # WebViewGlobalModule
        └── models/
            ├── webview_config.dart              # WebViewConfig value class
            ├── webview_intercepted_url.dart      # URI intercept payload
            ├── webview_load_progress.dart
            ├── webview_load_state.dart
            └── webview_navigation_event.dart

The generator also wires WebViewGlobalModule into your shell app's @InjectableInit(externalPackageModulesBefore: [...]) in lib/di/injector.dart and adds the webview path dependency to your app's pubspec.yaml automatically — there's no manual DI registration step to perform.

Step 4: Configure Platform Permissions

Android

Add the Internet permission to android/app/src/main/AndroidManifest.xml inside the <manifest> tag:

xml
<uses-permission android:name="android.permission.INTERNET" />

iOS

If you need to load plain HTTP URLs, add App Transport Security to ios/Runner/Info.plist:

xml
<key>NSAppTransportSecurity</key>
<dict>
  <key>NSAllowsArbitraryLoads</key>
  <true/>
</dict>

For HTTPS-only apps you can skip this block.

Step 5: Embed the WebView Widget

dart
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:webview/webview.dart';

class TradePage extends StatefulWidget {
  const TradePage({super.key});

  @override
  State<TradePage> createState() => _TradePageState();
}

class _TradePageState extends State<TradePage> {
  late final WebViewInAppWebViewController _controller;
  final _config = const WebViewConfig(
    initialUrl: 'https://example.com/trade',
    interceptedSchemes: ['app', 'tg'],
  );

  @override
  void initState() {
    super.initState();
    _controller = getIt<WebViewSDK>().createController(_config)
        as WebViewInAppWebViewController;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: InAppWebView(
        initialUrlRequest: URLRequest(url: WebUri(_config.initialUrl)),
        onWebViewCreated: (c) => _controller.attachNativeController(c),
        shouldOverrideUrlLoading: _controller.shouldOverrideUrlLoading,
        onProgressChanged: _controller.onProgressChanged,
        onLoadStart: _controller.onLoadStart,
        onLoadStop: _controller.onLoadStop,
        onReceivedError: _controller.onReceivedError,
      ),
    );
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }
}

WebViewSDK.isAvailable returns false on platforms flutter_inappwebview doesn't support (e.g. web, desktop) — createController returns null in that case, so check it before casting if your app targets those platforms.

Step 6: Intercept Custom URI Schemes

interceptStream is a Stream<WebViewInterceptedUrl> that fires whenever the WebView navigates to a scheme listed in WebViewConfig.interceptedSchemes. No corresponding navigationStream event fires for an intercepted URL — the navigation itself is cancelled at the platform layer.

dart
@override
void initState() {
  super.initState();
  // ... controller setup ...

  _controller.interceptStream.listen((event) {
    // event.url    — the full Uri that was intercepted
    // event.scheme — e.g. 'app' or 'tg'
    final productId = event.url.pathSegments.last;
    Navigator.pushNamed(context, '/trade/$productId');
  });
}

The web page triggers an intercept by navigating to a custom URL:

html
<a href="app://trade/BTC-IDR">Open in app</a>

Step 7: Call JavaScript from Dart

For one-way, fire-and-forget calls from Dart into the page's JavaScript context:

dart
await _controller.runJavaScript('window.showBanner("Order filled!")');

Need a response back from JavaScript, or bidirectional messaging? That requires the Pro-tier webview_sdk_advanced brick, which adds a full window.archipelago.* JS bridge with Promise-based responses. See WebView SDK Advanced.

Common Customizations

CustomizationWhere to Change
Change initial URL at runtimePass a different initialUrl in WebViewConfig
Add more intercepted schemesExtend interceptedSchemes list in WebViewConfig
Restrict which schemes may load at allOverride allowedSchemes (defaults to ['http', 'https'])
Show a loading indicatorListen to progressStream (WebViewLoadProgress, 0.01.0)
Handle navigation errorsListen to progressStream for a WebViewLoadState.error state
Clear cookies/local storageCall controller.clearCookies()

Next Steps

Built by Banua Coder