Setting Up the WebView SDK
FreeWhat you'll learn
- Picking
webview_sdkoverwebview_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
- An existing Archipelago monorepo (see Monorepo Scaffolding)
Step 1: Pick a Package — Basic or Advanced
Archipelago ships two independent, self-contained WebView bricks. Install whichever one matches your needs — not both:
| Brick | Tier | Use it when... |
|---|---|---|
webview_sdk (this tutorial) | Free | You need URL loading, navigation controls, progress tracking, one-way JS calls, and URI scheme interception |
webview_sdk_advanced | Pro | You 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
archipelago generate webview_sdkThis 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.dartThe 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:
<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:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>For HTTPS-only apps you can skip this block.
Step 5: Embed the WebView Widget
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.
@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:
<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:
await _controller.runJavaScript('window.showBanner("Order filled!")');Need a response back from JavaScript, or bidirectional messaging? That requires the Pro-tier
webview_sdk_advancedbrick, which adds a fullwindow.archipelago.*JS bridge with Promise-based responses. See WebView SDK Advanced.
Common Customizations
| Customization | Where to Change |
|---|---|
| Change initial URL at runtime | Pass a different initialUrl in WebViewConfig |
| Add more intercepted schemes | Extend interceptedSchemes list in WebViewConfig |
| Restrict which schemes may load at all | Override allowedSchemes (defaults to ['http', 'https']) |
| Show a loading indicator | Listen to progressStream (WebViewLoadProgress, 0.0 → 1.0) |
| Handle navigation errors | Listen to progressStream for a WebViewLoadState.error state |
| Clear cookies/local storage | Call controller.clearCookies() |
Next Steps
- Add a JS bridge, request interceptors, and mini-app hosting with the independent Pro-tier WebView SDK Advanced brick
- Set up the Auth SDK to pass auth tokens into your WebView
- Configure monitoring to track WebView load failures