[{"data":1,"prerenderedAt":27},["ShallowReactive",2],{"articolo-web-view-e-contenuti-ibridi-in-flutter-con-webview-flutter":3,"comments-article-web-view-e-contenuti-ibridi-in-flutter-con-webview-flutter":26},{"id":4,"title":5,"slug":6,"excerpt":7,"body":8,"cover_image":9,"cover_remote_url":10,"cover_credit":11,"video_url":15,"status":16,"published_at":17,"meta_title":18,"meta_description":19,"category":20,"author":24},69,"Web view e contenuti ibridi in Flutter con webview_flutter","web-view-e-contenuti-ibridi-in-flutter-con-webview-flutter","Integrare pagine web, contenuti HTML e flussi OAuth nelle app Flutter è semplice con webview_flutter. Scopri come configurare la WebView, gestire la navigazione e comunicare tra JavaScript e Dart.","## Introifca perché una WebView\n\nNon tutto ciò che mostriamo in un'app deve essere ricostruito con widget nativi. A volte serve visualizzare una pagina web esistente, un contenuto HTML dinamico, i termini di servizio, una dashboard di terze parti o completare un flusso OAuth che avviene interamente nel browser. In questi casi la **WebView** è lo strumento giusto.\n\nIl pacchetto ufficiale mantenuto dal team Flutter è [`webview_flutter`](https:\u002F\u002Fpub.dev\u002Fpackages\u002Fwebview_flutter), che a partire dalla versione 4 espone un'API unificata e moderna basata su `WebViewController`.\n\n## Installazione e configurazione\n\nAggiungi la dipendenza:\n\n```yaml\ndependencies:\n  webview_flutter: ^4.10.0\n```\n\nSu **Android** non serve alcuna configurazione particolare per contenuti HTTPS. Se devi caricare contenuti HTTP in chiaro, ricorda di abilitare il cleartext traffic nel `AndroidManifest.xml`.\n\nSu **iOS** non è necessario aggiungere permessi per il semplice caricamento di pagine, ma se la WebView deve accedere a fotocamera o microfono dovrai dichiarare le relative `NSCameraUsageDescription` nel file `Info.plist`.\n\n## Una WebView di base\n\nLa struttura minima ruota attorno a un `WebViewController` configurato in `initState` e passato al widget `WebViewWidget`:\n\n```dart\nimport 'package:flutter\u002Fmaterial.dart';\nimport 'package:webview_flutter\u002Fwebview_flutter.dart';\n\nclass SimpleWebView extends StatefulWidget {\n  const SimpleWebView({super.key});\n\n  @override\n  State\u003CSimpleWebView> createState() => _SimpleWebViewState();\n}\n\nclass _SimpleWebViewState extends State\u003CSimpleWebView> {\n  late final WebViewController _controller;\n\n  @override\n  void initState() {\n    super.initState();\n    _controller = WebViewController()\n      ..setJavaScriptMode(JavaScriptMode.unrestricted)\n      ..loadRequest(Uri.parse('https:\u002F\u002Fflutter.dev'));\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(title: const Text('WebView')),\n      body: WebViewWidget(controller: _controller),\n    );\n  }\n}\n```\n\nCon `JavaScriptMode.unrestricted` abilitiamo l'esecuzione di JavaScript, indispensabile per la maggior parte dei siti moderni.\n\n## Monitorare la navigazione e il caricamento\n\nUno dei bisogni più frequenti è mostrare un indicatore di progresso e intercettare la navigazione. Il `NavigationDelegate` permette di reagire a ogni evento del ciclo di vita:\n\n```dart\n_controller\n  ..setJavaScriptMode(JavaScriptMode.unrestricted)\n  ..setNavigationDelegate(\n    NavigationDelegate(\n      onProgress: (progress) {\n        setState(() => _progress = progress \u002F 100);\n      },\n      onPageStarted: (url) => debugPrint('Caricamento: $url'),\n      onPageFinished: (url) => debugPrint('Completato: $url'),\n      onWebResourceError: (error) {\n        debugPrint('Errore: ${error.description}');\n      },\n      onNavigationRequest: (request) {\n        if (request.url.startsWith('https:\u002F\u002Fblocked.com')) {\n          return NavigationDecision.prevent;\n        }\n        return NavigationDecision.navigate;\n      },\n    ),\n  )\n  ..loadRequest(Uri.parse('https:\u002F\u002Fflutter.dev'));\n```\n\nIl callback `onNavigationRequest` è particolarmente utile per **intercettare i redirect** in un flusso OAuth: quando il provider reindirizza al tuo `redirect_uri` puoi bloccare la navigazione, estrarre il codice di autorizzazione dalla query e chiudere la WebView.\n\n## Comunicazione tra Dart e JavaScript\n\nLa WebView non è una scatola chiusa: possiamo far dialogare il codice web con quello Dart in entrambe le direzioni.\n\n### Da Dart a JavaScript\n\nPer eseguire codice JavaScript e leggere il risultato:\n\n```dart\nfinal result = await _controller.runJavaScriptReturningResult(\n  'document.title',\n);\ndebugPrint('Titolo della pagina: $result');\n```\n\n### Da JavaScript a Dart\n\nRegistrando un `JavaScriptChannel` esponiamo un canale che la pagina web può invocare:\n\n```dart\n_controller.addJavaScriptChannel(\n  'FlutterBridge',\n  onMessageReceived: (JavaScriptMessage message) {\n    debugPrint('Messaggio da JS: ${message.message}');\n  },\n);\n```\n\nDal lato JavaScript, la pagina invia dati così:\n\n```javascript\nFlutterBridge.postMessage('Utente ha cliccato il pulsante');\n```\n\nQuesto meccanismo è perfetto per contenuti HTML ibridi in cui la parte web deve notificare eventi all'app nativa.\n\n## Caricare HTML locale o inline\n\nOltre agli URL remoti puoi caricare stringhe HTML direttamente o file dagli asset:\n\n```dart\n_controller.loadHtmlString('''\n  \u003Chtml>\n    \u003Cbody style=\"font-family: sans-serif; padding: 24px\">\n      \u003Ch1>Contenuto locale\u003C\u002Fh1>\n      \u003Cbutton onclick=\"FlutterBridge.postMessage('ciao')\">Invia\u003C\u002Fbutton>\n    \u003C\u002Fbody>\n  \u003C\u002Fhtml>\n''');\n```\n\nPer file negli asset, ricordati di dichiararli nel `pubspec.yaml` e usa `loadFlutterAsset('assets\u002Fpagina.html')`.\n\n## Gestire il pulsante indietro\n\nUn dettaglio spesso trascurato è il tasto indietro di Android: per impostazione predefinita chiude la schermata invece di navigare indietro nella cronologia della WebView. Usa `PopScope` per gestirlo:\n\n```dart\nPopScope(\n  canPop: false,\n  onPopInvokedWithResult: (didPop, result) async {\n    if (didPop) return;\n    if (await _controller.canGoBack()) {\n      _controller.goBack();\n    } else {\n      if (mounted) Navigator.of(context).pop();\n    }\n  },\n  child: WebViewWidget(controller: _controller),\n)\n```\n\n## Buone pratiche\n\n- **Limita l'ambito**: usa la WebView solo dove serve davvero, preferendo widget nativi per prestazioni e coerenza dell'interfaccia.\n- **Valida gli URL** in `onNavigationRequest` per evitare che l'utente navighi fuori dal dominio previsto.\n- **Attenzione ai `JavaScriptChannel`**: rappresentano una superficie di sicurezza, non esporre operazioni sensibili a pagine di cui non hai il controllo.\n- **Gestisci lo stato offline** mostrando un fallback quando `onWebResourceError` segnala l'assenza di rete.\n\n## Conclusione\n\n`webview_flutter` è la soluzione ufficiale e affidabile per integrare contenuti web nelle app Flutter. Con `WebViewController`, `NavigationDelegate` e i canali JavaScript hai tutto il necessario per costruire esperienze ibride solide: dalla semplice visualizzazione di una pagina a complessi flussi bidirezionali tra web e nativo.","https:\u002F\u002Fflutter.it\u002Fstorage\u002Farticles\u002F65324309-53c8-4e21-b34d-f300e88deac8.jpg","https:\u002F\u002Fimages.unsplash.com\u002Fphoto-1641327524708-0246aa928f16?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w5NzA2NTJ8MHwxfHJhbmRvbXx8fHx8fHx8fDE3ODczMTU4NjJ8&ixlib=rb-4.1.0&q=80&w=1080",{"name":12,"author_url":13,"photo_url":14},"Andrea De Santis","https:\u002F\u002Funsplash.com\u002F@santesson89","https:\u002F\u002Funsplash.com\u002Fphotos\u002Fa-group-of-buildings-that-are-next-to-each-other-cV8BIJolid4",null,"published","2026-08-17T04:00:44+00:00","WebView in Flutter con webview_flutter: guida pratica","Impara a integrare contenuti web nelle app Flutter con webview_flutter: navigazione, comunicazione JS-Dart, OAuth e gestione del tasto indietro.",{"id":21,"name":22,"slug":23},1,"Guide","guide",{"id":21,"name":25},"Flutter Bot",[],1789205512428]