Skip to main content
This is an enterprise-only feature. Please contact us to enable.
The same headless architecture as iOS and Android: render your own native list and drive a hidden WebViewWidget that runs the Dynamic SDK and returns results (including message and transaction signatures) over a JS bridge. No wallet SDK in your Flutter app. The basic Flutter flow is the recommended default.
No SDK in your app. Your app links no wallet SDK: no CocoaPods, no native crypto, no Gradle dep. It needs a hidden WebViewWidget pointed at headless.html and your URL scheme. All WalletConnect / MetaMask / Phantom logic (and the wallet list itself) comes from that hosted view. Redeploy the page to update wallets; the app never changes.
fireblocks_headless_connect.dart
Source in the sample app: fireblocks_headless_connect.dart. Prefer the buildable flutter-app/ over any older flutter-harness reference.

1. Add dependencies

pubspec.yaml

2. Register URL schemes

You need two hosts under your scheme: one for the visible flow callback (wallet-callback) and one for Phantom’s redirect (phantom-headless), plus LSApplicationQueriesSchemes on iOS for the wallet schemes you open.
Info.plist (iOS)
AndroidManifest.xml

3. Mount the engine and connect

Wrap your home screen with FireblocksEngineHost. It keeps the hidden WebViewWidget alive at all times. Prewarm at launch and connect on tap.
main.dart
example_screen.dart
Forward deep-links from Phantom with app_links (getInitialLink + uriLinkStream) into FireblocksHeadlessConnect.shared.handleReturnUrl(uri). Do not rely on MaterialApp.onGenerateRoute for custom-scheme intents.

4. Sign a message

After a successful headless connect, await sign() with any string.
example_screen.dart
Signing is only available for wallets connected through the headless engine (connectedHeadlessly == true). Wallets connected via the visible fallback flow do not hold an open session.

5. Send a transaction (EVM)

sendTransaction() calls eth_sendTransaction: the wallet signs and broadcasts in one step. The result is an on-chain transaction hash. Prefer this over eth_signTransaction, which mobile wallets (including MetaMask) often reject. The Flutter sample does not expose a sign-only signTransaction() helper. Use sendTransaction() for EVM sends, or call the engine’s signTx bridge yourself if you need sign-only.
example_screen.dart
chainId is required for send. The engine verifies it against the wallet’s active network and fails with chain_mismatch (or missing_chain_id) rather than silently using whatever network the wallet is on. Treat every send as final: confirm with the user before calling.

6. Disconnect

Clears localStorage in the hidden WebView and reloads the engine so stale SDK state does not bleed into the next connect.
example_screen.dart

7. The bridge (for reference)

Flutter uses addJavaScriptChannel('walletNative', …) which creates window.walletNative.postMessage(json). The channel name must match exactly.
bridge messages

Common pitfalls

  • Match the channel name exactly: walletNative. A mismatch is invisible; the channel just never receives anything.
  • Use app_links for Phantom returns, not onGenerateRoute.
  • Test on a physical device.
  • Serve over HTTPS.
Last modified on August 10, 2026