webview_sdk_advanced Pro
Self-contained, standalone WebView Advanced feature SDK. Ships its own full WebView capability plus a bidirectional JS bridge (typed handlers + Promises), request/response interceptors for auth header injection, deeplink routing from WebView back to native, and a full mini-app container (manifest registry, bridge dispatcher, lifecycle state machine, capability handlers, and
MiniAppContainerPage).
Version: 2.1.0
Independent of webview_sdk
webview_sdk_advanced does not require webview_sdk to be installed first, and does not extend or build on it — generate this brick alone if your app needs the JS bridge and/or mini-app hosting. Installing both is not a supported layering model; pick the one your project needs.
Variables
| Variable | Type | Default | Description |
|---|---|---|---|
uiKitPackageName | string | app_ui_kit | Name of the UI kit package used by the mini-app container |
Mini-app hosting is not gated behind a variable — it is the point of this brick. If you don't need it, install webview_sdk (the basic, independent brick) instead.
analyticsInstalled is derived automatically (not a prompted variable) from whether infrastructure/analytics_api exists in the target project — when absent, the analytics bridge capability (handler, imports, tracker param) is stripped from the generated sources and the analytics_api dependency is omitted.
Usage
Interactive
archipelago generate webview_sdk_advancedNon-interactive (CI)
archipelago generate webview_sdk_advanced --config my_config.jsonGenerated Package
This brick generates a single, complete, standalone package — it does not patch or inject files into any other package.
features/
└── webview_advanced/
└── lib/src/
├── js_handler.dart # Abstract JsHandler<TArgs, TResult> base
├── js_handler_registry.dart # JsHandlerRegistry (first-registration-wins)
├── webview_request.dart # Immutable WebViewRequest value class
├── webview_request_interceptor.dart # WebViewRequestInterceptor interface
├── webview_advanced_sdk.dart # WebViewAdvancedSDK contract
├── webview_advanced_sdk_impl.dart # flutter_inappwebview-backed impl
├── webview_controller.dart
├── webview_inappwebview_controller.dart
├── webview_inappwebview_controller_advanced.dart
├── di/
├── models/
│ ├── js_message.dart
│ ├── webview_advanced_config.dart # WebViewAdvancedConfig extends WebViewConfig
│ └── ...
└── mini_app/
├── bridge/
├── bridge_dispatcher.dart
├── container/
│ ├── mini_app_container.dart
│ └── mini_app_container_page.dart
├── handlers/ # analytics_handler.dart omitted when analytics_api is absent
├── interceptors/
├── lifecycle/
├── manifest/
├── providers/
├── registry/
├── tokens/
└── webview_bridge_binding.dartDistinct type names
To avoid ambiguous-import collisions if both webview and webview_advanced ever end up in the same workspace (they are both kept in template_base for analyze/tests), the advanced package's FeatureSDK interface is WebViewAdvancedSDK / WebViewAdvancedSDKImpl — not WebViewSDK. Everything else (WebViewController, WebViewConfig, mini-app types, etc.) is duplicated wholesale rather than shared, per the independence design.
Mini-App Container
The mini-app container — the headline Pro feature — is generated unconditionally for running config-driven web micro-apps inside your native shell.
How it works
- Manifest registry —
MiniAppRegistry(ConfigMiniAppRegistry) loads mini-app definitions fromassets/config/mini_apps.yamlviaArchipelagoConfigHelper, with an optional remote-config source layered on top (capability-guarded for net-new mini-app ids). The post-gen hook registers the asset in the host app'spubspec.yamland writes a starter YAML file. - Bridge dispatcher —
MiniAppBridgeDispatchervalidates (bridge version, per-invoke origin, capability grant) and routes incoming JS calls to registeredBridgeCapabilityHandlerimplementations. - Lifecycle state machine —
MiniAppContainertracksinitializing → loading → ready → closing → closed(with anerrorbranch) and exposes transitions as aMiniAppLifecycleEventstream. - Capability handlers —
LifecycleHandler(always registered),NavigationHandler,ProfileHandler,StorageHandler,PermissionsHandler,AuthHandler, andAnalyticsHandler(only generated whenanalytics_apiis present in the target project). MiniAppContainerPage— A ready-to-use Flutter page that wires up the manifest, bridge dispatcher, and container widget.
Mini-app config file
The post-gen hook creates assets/config/mini_apps.yaml in your app:
mini_apps:
- id: rewards
entry_url: https://rewards.example.com/
allowed_origins:
- https://rewards.example.com
bridge_origins:
- https://rewards.example.com
capabilities: [auth, profile, navigation, analytics]
display:
mode: fullscreen
show_header: true
title: "Rewards"Token provider
Implement MiniAppTokenProvider to mint short-lived, scoped tokens for mini-app bridge sessions (see MiniAppScopedToken):
class MyTokenProvider implements MiniAppTokenProvider {
@override
Future<MiniAppScopedToken> mintScopedToken(
String miniAppId,
List<String> scopes,
) async => MiniAppScopedToken(
token: await tokenService.exchangeForMiniApp(miniAppId, scopes),
expiresIn: 300,
scopes: scopes,
miniAppId: miniAppId,
);
}Token Exchange 2.1.0+
Each mini-app can independently opt into one of two auth.getToken strategies via token_strategy in its mini_apps.yaml entry:
mini_apps:
- id: rewards
# ...existing manifest fields...
token_strategy: exchange # default: interceptor (MVP)
exchange_endpoint: /api/mini-apps/token-exchange # optional overridetoken_strategy: interceptor(default) — unchanged MVP behavior:auth.getTokenreturns whatever yourMiniAppAuthProvider.getTokensupplies as-is, andMiniAppAuthInterceptorinjects that same token on bridge-origin requests.token_strategy: exchange—auth.getTokencalls a backend token-exchange endpoint viaExchangeMiniAppTokenProvider(ships with this brick, implementsMiniAppTokenProvider) to mint a short-lived, audience-bound token scoped to that mini-app. Wire your instance intoMiniAppContainer.tokenProvider/MiniAppContainerPage.tokenProvider.
ExchangeMiniAppTokenProvider handles scope narrowing against the manifest's granted capabilities, in-memory caching until expires_in - 30s, single-flight de-duplication, expires_in clamping to 300s, and 401-refresh-retry-once session handling. You supply four seams: a TokenExchangeHttpClient (this package has no HTTP dependency of its own — bring your own client), a host session token supplier, a host session refresh hook, and a manifest lookup function.
Full backend contract (request/response shape, error-code table, client behavior) is documented in the Archipelago-ac3d spec: docs/plans/2026-07-10-miniapp-token-exchange-spec.md.
Integration
1. Implement Handlers
class GetTokenHandler implements JsHandler<void, String> {
@override
String get handlerName => 'getToken';
@override
void parseArgs(List<dynamic> args) {}
@override
Future<String> handle(void args) async =>
await tokenService.getAccessToken();
@override
Map<String, dynamic> serializeResult(String result) => {'token': result};
}2. Create Config
final config = WebViewAdvancedConfig(
initialUrl: 'https://app.example.com',
trustedOrigins: WebViewTrustPolicy.origins(['https://app.example.com']),
interceptors: [AuthInterceptor(tokenProvider)],
jsHandlers: [GetTokenHandler()],
);3. Create Controller
final controller = getIt<WebViewAdvancedSDK>().createController(config);4. Call from JavaScript
const token = await window.archipelago.getToken();5. Post Native Messages to JS
await controller.postMessageToJs('userLoggedIn', {'userId': '123'});window.archipelago.onNativeMessage = function(name, payload) {
if (name === 'userLoggedIn') console.log('User:', payload.userId);
};Auth Interceptor Example
class AuthInterceptor implements WebViewRequestInterceptor {
const AuthInterceptor(this._tokenProvider);
final TokenProvider _tokenProvider;
@override
Future<WebViewRequest?> intercept(WebViewRequest request) async {
final token = await _tokenProvider.getAccessToken();
return request.copyWith(
headers: {...request.headers, 'Authorization': 'Bearer $token'},
);
}
}Provider Capability
| Feature | flutter_inappwebview |
|---|---|
| JS bridge | Full (Promise-based, per-handler channels) |
| Header injection | All requests |
| File upload | Full (onCreateFileChooser) |
| File download | Full |