1. Einführung
Zuletzt aktualisiert: 19.10.2021
Mit dem WebView Flutter-Plug-in können Sie Ihrer Android- oder iOS-Flutter-App ein WebView-Widget hinzufügen. Unter iOS wird das WebView-Widget von einem WKWebView unterstützt, unter Android von einem WebView. Das Plug-in kann Flutter-Widgets über der Webansicht rendern. So ist es beispielsweise möglich, ein Drop-down-Menü über der Webansicht zu rendern.
Aufgaben
In diesem Codelab erstellen Sie Schritt für Schritt eine mobile App mit einer WebView mithilfe des Flutter SDK. Mit der Anwendung können Sie Folgendes tun:
- Webinhalte in einem
WebView
anzeigen - Flutter-Widgets über dem
WebView
anzeigen - Auf Ereignisse zum Fortschritt des Seitenaufbaus reagieren
WebView
über dieWebViewController
steuern- Websites mit
NavigationDelegate
blockieren - JavaScript-Ausdrücke auswerten
- Callbacks aus JavaScript mit
JavascriptChannels
verarbeiten - Cookies setzen, entfernen, hinzufügen oder anzeigen
- HTML aus Assets, Dateien oder Strings mit HTML laden und anzeigen
Lerninhalte
In diesem Codelab erfahren Sie, wie Sie das webview_flutter
-Plug-in auf verschiedene Arten verwenden können, z. B.:
webview_flutter
-Plug-in konfigurieren- Ereignisse für den Fortschritt des Seitenaufbaus erfassen
- Seitennavigation steuern
WebView
anweisen, in der Historie vor- und zurückzugehen- JavaScript auswerten, einschließlich der Verwendung zurückgegebener Ergebnisse
- Callbacks registrieren, um Dart-Code aus JavaScript aufzurufen
- Cookies verwalten
- HTML-Seiten aus Assets, Dateien oder einem String mit HTML laden und anzeigen
Voraussetzungen
- Android Studio 4.1 oder höher (für die Android-Entwicklung)
- Xcode 12 oder höher (für die iOS-Entwicklung)
- Flutter SDK
- Ein Codeeditor wie Android Studio oder Visual Studio Code.
2. Flutter-Entwicklungsumgebung einrichten
Für dieses Lab benötigen Sie zwei Softwarekomponenten: das Flutter SDK und einen Editor.
Sie können das Codelab auf einem der folgenden Geräte ausführen:
- Ein physisches Android- oder iOS-Gerät, das mit Ihrem Computer verbunden ist und auf den Entwicklermodus eingestellt ist.
- Der iOS-Simulator (erfordert die Installation von Xcode-Tools).
- Android Emulator (muss in Android Studio eingerichtet werden)
3. Erste Schritte
Erste Schritte mit Flutter
Es gibt verschiedene Möglichkeiten, ein neues Flutter-Projekt zu erstellen. Sowohl Android Studio als auch Visual Studio Code bieten Tools für diese Aufgabe. Folgen Sie entweder der verlinkten Anleitung, um ein Projekt zu erstellen, oder führen Sie die folgenden Befehle in einem geeigneten Befehlszeilenterminal aus.
$ flutter create --platforms=android,ios webview_in_flutter Creating project webview_in_flutter... Resolving dependencies in `webview_in_flutter`... Downloading packages... Got dependencies in `webview_in_flutter`. Wrote 74 files. All done! You can find general documentation for Flutter at: https://docs.flutter.dev/ Detailed API documentation is available at: https://api.flutter.dev/ If you prefer video documentation, consider: https://www.youtube.com/c/flutterdev In order to run your application, type: $ cd webview_in_flutter $ flutter run Your application code is in webview_in_flutter/lib/main.dart.
WebView Flutter-Plug-in als Abhängigkeit hinzufügen
Am besten fügen Sie einer Flutter-App zusätzliche Funktionen hinzu, indem Sie Pub-Pakete verwenden. In diesem Codelab fügen Sie Ihrem Projekt das webview_flutter
-Plug-in hinzu. Führen Sie im Terminal die folgenden Befehle aus.
$ cd webview_in_flutter $ flutter pub add webview_flutter Resolving dependencies... Downloading packages... collection 1.18.0 (1.19.0 available) leak_tracker 10.0.5 (10.0.7 available) leak_tracker_flutter_testing 3.0.5 (3.0.7 available) material_color_utilities 0.11.1 (0.12.0 available) + plugin_platform_interface 2.1.8 string_scanner 1.2.0 (1.3.0 available) test_api 0.7.2 (0.7.3 available) + webview_flutter 4.9.0 + webview_flutter_android 3.16.7 + webview_flutter_platform_interface 2.10.0 + webview_flutter_wkwebview 3.15.0 Changed 5 dependencies! 6 packages have newer versions incompatible with dependency constraints. Try `flutter pub outdated` for more information.
Wenn Sie die Datei pubspec.yaml untersuchen, sehen Sie, dass sie jetzt eine Zeile im Abschnitt „dependencies“ für das webview_flutter
-Plug-in enthält.
Android-minSDK konfigurieren
Wenn Sie das webview_flutter
-Plug-in unter Android verwenden möchten, müssen Sie minSDK
auf 20
festlegen. Ändern Sie die Datei android/app/build.gradle
so:
android/app/build.gradle
android {
//...
defaultConfig {
applicationId = "com.example.webview_in_flutter"
minSdk = 20 // Modify this line
targetSdk = flutter.targetSdkVersion
versionCode = flutterVersionCode.toInteger()
versionName = flutterVersionName
}
4. WebView-Widget zur Flutter-App hinzufügen
In diesem Schritt fügen Sie Ihrer Anwendung ein WebView
hinzu. WebViews sind gehostete integrierte Ansichten. Als App-Entwickler haben Sie die Möglichkeit, diese integrierten Ansichten in Ihrer App zu hosten. Unter Android können Sie zwischen virtuellen Displays (Standard für Android) und der Hybrid-Komposition wählen. Unter iOS wird jedoch immer die Hybrid-Komposition verwendet.
Eine ausführliche Erläuterung der Unterschiede zwischen virtuellen Displays und der Hybrid-Zusammensetzung finden Sie in der Dokumentation unter Hosting native Android and iOS views in your Flutter app with Platform Views .
Webview auf dem Bildschirm anzeigen
Ersetzen Sie den Inhalt von lib/main.dart
durch Folgendes:
lib/main.dart
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
void main() {
runApp(
MaterialApp(
theme: ThemeData(useMaterial3: true),
home: const WebViewApp(),
),
);
}
class WebViewApp extends StatefulWidget {
const WebViewApp({super.key});
@override
State<WebViewApp> createState() => _WebViewAppState();
}
class _WebViewAppState extends State<WebViewApp> {
late final WebViewController controller;
@override
void initState() {
super.initState();
controller = WebViewController()
..loadRequest(
Uri.parse('https://flutter.dev'),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Flutter WebView'),
),
body: WebViewWidget(
controller: controller,
),
);
}
}
Wenn Sie diesen Code auf iOS oder Android ausführen, wird eine WebView als randloses Browserfenster auf Ihrem Gerät angezeigt. Das bedeutet, dass der Browser auf Ihrem Gerät im Vollbildmodus ohne Rahmen oder Rand angezeigt wird. Beim Scrollen werden Sie feststellen, dass einige Teile der Seite etwas seltsam aussehen. Das liegt daran, dass JavaScript deaktiviert ist. Für das korrekte Rendern von flutter.dev ist JavaScript erforderlich.
App ausführen
Führen Sie die Flutter-App unter iOS oder Android aus, um eine Webansicht zu sehen, in der die Website flutter.dev angezeigt wird. Alternativ können Sie die App in einem Android-Emulator oder einem iOS-Simulator ausführen. Sie können die ursprüngliche WebView-URL durch beispielsweise Ihre eigene Website ersetzen.
$ flutter run
Wenn Sie den entsprechenden Simulator oder Emulator ausführen oder ein physisches Gerät angeschlossen haben, sollte nach dem Kompilieren und Bereitstellen der App auf Ihrem Gerät Folgendes angezeigt werden:
5. Auf Seitenaufbau-Ereignisse warten
Das WebView
-Widget bietet mehrere Ereignisse für den Fortschritt des Seitenaufbaus, auf die Ihre App reagieren kann. Während des WebView
-Seitenladezyklus werden drei verschiedene Seitenladeereignisse ausgelöst: onPageStarted
, onProgress
und onPageFinished
. In diesem Schritt implementieren Sie eine Anzeige für das Laden der Seite. Außerdem wird dadurch gezeigt, dass Sie Flutter-Inhalte über dem WebView
-Inhaltsbereich rendern können.
Seitenaufbau-Ereignisse in Ihre App einfügen
Erstellen Sie eine neue Quelldatei unter lib/src/web_view_stack.dart
und fügen Sie ihr folgenden Inhalt hinzu:
lib/src/web_view_stack.dart
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
class WebViewStack extends StatefulWidget {
const WebViewStack({super.key});
@override
State<WebViewStack> createState() => _WebViewStackState();
}
class _WebViewStackState extends State<WebViewStack> {
var loadingPercentage = 0;
late final WebViewController controller;
@override
void initState() {
super.initState();
controller = WebViewController()
..setNavigationDelegate(NavigationDelegate(
onPageStarted: (url) {
setState(() {
loadingPercentage = 0;
});
},
onProgress: (progress) {
setState(() {
loadingPercentage = progress;
});
},
onPageFinished: (url) {
setState(() {
loadingPercentage = 100;
});
},
))
..loadRequest(
Uri.parse('https://flutter.dev'),
);
}
@override
Widget build(BuildContext context) {
return Stack(
children: [
WebViewWidget(
controller: controller,
),
if (loadingPercentage < 100)
LinearProgressIndicator(
value: loadingPercentage / 100.0,
),
],
);
}
}
In diesem Code wird das WebView
-Widget in ein Stack
eingebettet und das WebView
wird bedingt mit einem LinearProgressIndicator
überlagert, wenn der Prozentsatz des Seitenaufbaus weniger als 100 % beträgt. Da sich der Programmstatus im Laufe der Zeit ändert, haben Sie ihn in einer State
-Klasse gespeichert, die mit einem StatefulWidget
verknüpft ist.
Wenn Sie dieses neue WebViewStack
-Widget verwenden möchten, müssen Sie Ihre lib/main.dart
so ändern:
lib/main.dart
import 'package:flutter/material.dart';
import 'src/web_view_stack.dart';
void main() {
runApp(
MaterialApp(
theme: ThemeData(useMaterial3: true),
home: const WebViewApp(),
),
);
}
class WebViewApp extends StatefulWidget {
const WebViewApp({super.key});
@override
State<WebViewApp> createState() => _WebViewAppState();
}
class _WebViewAppState extends State<WebViewApp> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Flutter WebView'),
),
body: const WebViewStack(),
);
}
}
Wenn Sie die App ausführen, wird je nach Netzwerkbedingungen und je nachdem, ob der Browser die Seite, zu der Sie navigieren, im Cache gespeichert hat, eine Ladeanzeige für die Seite über dem Inhaltsbereich WebView
eingeblendet.
6. Mit dem WebViewController arbeiten
Über das WebView-Widget auf den WebViewController zugreifen
Das WebView
-Widget ermöglicht die programmatische Steuerung mit einer WebViewController
. Dieser Controller wird nach der Erstellung des WebView
-Widgets über einen Callback zur Verfügung gestellt. Aufgrund der asynchronen Verfügbarkeit dieses Controllers ist er ein hervorragender Kandidat für die asynchrone Completer<T>
-Klasse von Dart.
Aktualisieren Sie lib/src/web_view_stack.dart
so:
lib/src/web_view_stack.dart
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
class WebViewStack extends StatefulWidget {
const WebViewStack({required this.controller, super.key}); // MODIFY
final WebViewController controller; // ADD
@override
State<WebViewStack> createState() => _WebViewStackState();
}
class _WebViewStackState extends State<WebViewStack> {
var loadingPercentage = 0;
// REMOVE the controller that was here
@override
void initState() {
super.initState();
// Modify from here...
widget.controller.setNavigationDelegate(
NavigationDelegate(
onPageStarted: (url) {
setState(() {
loadingPercentage = 0;
});
},
onProgress: (progress) {
setState(() {
loadingPercentage = progress;
});
},
onPageFinished: (url) {
setState(() {
loadingPercentage = 100;
});
},
),
);
// ...to here.
}
@override
Widget build(BuildContext context) {
return Stack(
children: [
WebViewWidget(
controller: widget.controller, // MODIFY
),
if (loadingPercentage < 100)
LinearProgressIndicator(
value: loadingPercentage / 100.0,
),
],
);
}
}
Das WebViewStack
-Widget verwendet jetzt einen Controller, der im umgebenden Widget erstellt wurde. Dadurch kann der Controller für WebViewWidget
mit anderen Teilen der App geteilt werden.
Navigationssteuerelemente erstellen
Ein funktionierendes WebView
ist eine Sache, aber die Möglichkeit, vorwärts und rückwärts durch den Seitenverlauf zu navigieren und die Seite neu zu laden, wäre eine nützliche Ergänzung. Mit einem WebViewController
können Sie diese Funktion in Ihre App einfügen.
Erstellen Sie eine neue Quelldatei unter lib/src/navigation_controls.dart
und fügen Sie Folgendes ein:
lib/src/navigation_controls.dart
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
class NavigationControls extends StatelessWidget {
const NavigationControls({required this.controller, super.key});
final WebViewController controller;
@override
Widget build(BuildContext context) {
return Row(
children: <Widget>[
IconButton(
icon: const Icon(Icons.arrow_back_ios),
onPressed: () async {
final messenger = ScaffoldMessenger.of(context);
if (await controller.canGoBack()) {
await controller.goBack();
} else {
messenger.showSnackBar(
const SnackBar(content: Text('No back history item')),
);
return;
}
},
),
IconButton(
icon: const Icon(Icons.arrow_forward_ios),
onPressed: () async {
final messenger = ScaffoldMessenger.of(context);
if (await controller.canGoForward()) {
await controller.goForward();
} else {
messenger.showSnackBar(
const SnackBar(content: Text('No forward history item')),
);
return;
}
},
),
IconButton(
icon: const Icon(Icons.replay),
onPressed: () {
controller.reload();
},
),
],
);
}
}
Dieses Widget verwendet das WebViewController
, das ihm bei der Erstellung zugewiesen wurde, damit der Nutzer das WebView
über eine Reihe von IconButton
s steuern kann.
Navigationssteuerelemente zur App-Leiste hinzufügen
Mit der aktualisierten WebViewStack
und der neu erstellten NavigationControls
ist es jetzt an der Zeit, alles in einer aktualisierten WebViewApp
zusammenzufügen. Hier erstellen wir das freigegebene WebViewController
. Da sich WebViewApp
in dieser App oben im Widget-Baum befindet, ist es sinnvoll, es auf dieser Ebene zu erstellen.
Aktualisieren Sie die Datei lib/main.dart
so:
lib/main.dart
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart'; // ADD
import 'src/navigation_controls.dart'; // ADD
import 'src/web_view_stack.dart';
void main() {
runApp(
MaterialApp(
theme: ThemeData(useMaterial3: true),
home: const WebViewApp(),
),
);
}
class WebViewApp extends StatefulWidget {
const WebViewApp({super.key});
@override
State<WebViewApp> createState() => _WebViewAppState();
}
class _WebViewAppState extends State<WebViewApp> {
// Add from here...
late final WebViewController controller;
@override
void initState() {
super.initState();
controller = WebViewController()
..loadRequest(
Uri.parse('https://flutter.dev'),
);
}
// ...to here.
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Flutter WebView'),
// Add from here...
actions: [
NavigationControls(controller: controller),
],
// ...to here.
),
body: WebViewStack(controller: controller), // MODIFY
);
}
}
Beim Ausführen der App sollte eine Webseite mit Steuerelementen angezeigt werden:
7. Navigation mit NavigationDelegate im Blick behalten
WebView
stellt Ihrer App einen NavigationDelegate,
zur Verfügung, mit dem Ihre App die Seitennavigation des WebView
-Widgets verfolgen und steuern kann. Wenn eine Navigation von WebView,
initiiert wird, z. B. wenn ein Nutzer auf einen Link klickt, wird NavigationDelegate
aufgerufen. Mit dem NavigationDelegate
-Callback kann gesteuert werden, ob WebView
mit der Navigation fortfährt.
Benutzerdefinierten NavigationDelegate registrieren
In diesem Schritt registrieren Sie einen NavigationDelegate
-Callback, um die Navigation zu YouTube.com zu blockieren. Beachten Sie, dass diese einfache Implementierung auch Inline-YouTube-Inhalte blockiert, die auf verschiedenen Flutter-API-Dokumentationsseiten angezeigt werden.
Aktualisieren Sie lib/src/web_view_stack.dart
so:
lib/src/web_view_stack.dart
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
class WebViewStack extends StatefulWidget {
const WebViewStack({required this.controller, super.key});
final WebViewController controller;
@override
State<WebViewStack> createState() => _WebViewStackState();
}
class _WebViewStackState extends State<WebViewStack> {
var loadingPercentage = 0;
@override
void initState() {
super.initState();
widget.controller.setNavigationDelegate(
NavigationDelegate(
onPageStarted: (url) {
setState(() {
loadingPercentage = 0;
});
},
onProgress: (progress) {
setState(() {
loadingPercentage = progress;
});
},
onPageFinished: (url) {
setState(() {
loadingPercentage = 100;
});
},
// Add from here...
onNavigationRequest: (navigation) {
final host = Uri.parse(navigation.url).host;
if (host.contains('youtube.com')) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
'Blocking navigation to $host',
),
),
);
return NavigationDecision.prevent;
}
return NavigationDecision.navigate;
},
// ...to here.
),
);
}
@override
Widget build(BuildContext context) {
return Stack(
children: [
WebViewWidget(
controller: widget.controller,
),
if (loadingPercentage < 100)
LinearProgressIndicator(
value: loadingPercentage / 100.0,
),
],
);
}
}
Im nächsten Schritt fügen Sie einen Menüpunkt hinzu, mit dem Sie Ihr NavigationDelegate
mithilfe der Klasse WebViewController
testen können. Es bleibt dem Leser überlassen, die Logik des Rückrufs so zu erweitern, dass die Navigation auf YouTube.com nur für die gesamte Seite blockiert wird und Inline-YouTube-Inhalte in der API-Dokumentation weiterhin zulässig sind.
8. Menüschaltfläche zur App-Leiste hinzufügen
In den nächsten Schritten erstellen Sie eine Menüschaltfläche im AppBar
-Widget, mit der JavaScript ausgewertet, JavaScript-Channels aufgerufen und Cookies verwaltet werden. Insgesamt ein wirklich nützliches Menü.
Erstellen Sie eine neue Quelldatei unter lib/src/menu.dart
und fügen Sie Folgendes ein:
lib/src/menu.dart
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
enum _MenuOptions {
navigationDelegate,
}
class Menu extends StatelessWidget {
const Menu({required this.controller, super.key});
final WebViewController controller;
@override
Widget build(BuildContext context) {
return PopupMenuButton<_MenuOptions>(
onSelected: (value) async {
switch (value) {
case _MenuOptions.navigationDelegate:
await controller.loadRequest(Uri.parse('https://youtube.com'));
}
},
itemBuilder: (context) => [
const PopupMenuItem<_MenuOptions>(
value: _MenuOptions.navigationDelegate,
child: Text('Navigate to YouTube'),
),
],
);
}
}
Wenn der Nutzer die Menüoption Zu YouTube wechseln auswählt, wird die Methode loadRequest
des WebViewController
ausgeführt. Diese Navigation wird durch den navigationDelegate
-Callback blockiert, den Sie im vorherigen Schritt erstellt haben.
Wenn Sie das Menü dem Bildschirm von WebViewApp
hinzufügen möchten, ändern Sie lib/main.dart
so:
lib/main.dart
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'src/menu.dart'; // ADD
import 'src/navigation_controls.dart';
import 'src/web_view_stack.dart';
void main() {
runApp(
MaterialApp(
theme: ThemeData(useMaterial3: true),
home: const WebViewApp(),
),
);
}
class WebViewApp extends StatefulWidget {
const WebViewApp({super.key});
@override
State<WebViewApp> createState() => _WebViewAppState();
}
class _WebViewAppState extends State<WebViewApp> {
late final WebViewController controller;
@override
void initState() {
super.initState();
controller = WebViewController()
..loadRequest(
Uri.parse('https://flutter.dev'),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Flutter WebView'),
actions: [
NavigationControls(controller: controller),
Menu(controller: controller), // ADD
],
),
body: WebViewStack(controller: controller),
);
}
}
Führen Sie Ihre App aus und tippen Sie auf den Menüpunkt Zu YouTube wechseln. Es sollte eine Snackbar angezeigt werden, in der Sie darüber informiert werden, dass der Navigationscontroller die Navigation zu YouTube blockiert hat.
9. JavaScript auswerten
Mit WebViewController
können JavaScript-Ausdrücke im Kontext der aktuellen Seite ausgewertet werden. Es gibt zwei verschiedene Möglichkeiten, JavaScript auszuwerten: Für JavaScript-Code, der keinen Wert zurückgibt, verwenden Sie runJavaScript
. Für JavaScript-Code, der einen Wert zurückgibt, verwenden Sie runJavaScriptReturningResult
.
Damit JavaScript aktiviert wird, müssen Sie WebViewController
konfigurieren und das Attribut javaScriptMode
auf JavascriptMode.unrestricted
festlegen. Standardmäßig ist javascriptMode
auf JavascriptMode.disabled
festgelegt.
Aktualisieren Sie die Klasse _WebViewStackState
, indem Sie die Einstellung javascriptMode
wie folgt hinzufügen:
lib/src/web_view_stack.dart
class _WebViewStackState extends State<WebViewStack> {
var loadingPercentage = 0;
@override
void initState() {
super.initState();
widget.controller
..setNavigationDelegate( // Modify this line to use .. instead of .
NavigationDelegate(
onPageStarted: (url) {
setState(() {
loadingPercentage = 0;
});
},
onProgress: (progress) {
setState(() {
loadingPercentage = progress;
});
},
onPageFinished: (url) {
setState(() {
loadingPercentage = 100;
});
},
onNavigationRequest: (navigation) {
final host = Uri.parse(navigation.url).host;
if (host.contains('youtube.com')) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
'Blocking navigation to $host',
),
),
);
return NavigationDecision.prevent;
}
return NavigationDecision.navigate;
},
),
)
..setJavaScriptMode(JavaScriptMode.unrestricted); // Add this line
}
@override
Widget build(BuildContext context) {
return Stack(
children: [
WebViewWidget(
controller: widget.controller,
),
if (loadingPercentage < 100)
LinearProgressIndicator(
value: loadingPercentage / 100.0,
),
],
);
}
}
Da die WebViewWidget
jetzt JavaScript ausführen kann, können Sie dem Menü eine Option hinzufügen, um die runJavaScriptReturningResult
-Methode zu verwenden.
Konvertieren Sie die Klasse „Menu“ entweder mit dem Editor oder über die Tastatur in ein StatefulWidget. Ändern Sie lib/src/menu.dart
so:
lib/src/menu.dart
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
enum _MenuOptions {
navigationDelegate,
userAgent, // Add this line
}
class Menu extends StatefulWidget { // Convert to StatefulWidget
const Menu({required this.controller, super.key});
final WebViewController controller;
@override // Add from here
State<Menu> createState() => _MenuState();
}
class _MenuState extends State<Menu> { // To here.
@override
Widget build(BuildContext context) {
return PopupMenuButton<_MenuOptions>(
onSelected: (value) async {
switch (value) {
case _MenuOptions.navigationDelegate: // Modify from here
await widget.controller
.loadRequest(Uri.parse('https://youtube.com'));
case _MenuOptions.userAgent:
final userAgent = await widget.controller
.runJavaScriptReturningResult('navigator.userAgent');
if (!context.mounted) return;
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('$userAgent'),
)); // To here.
}
},
itemBuilder: (context) => [
const PopupMenuItem<_MenuOptions>(
value: _MenuOptions.navigationDelegate,
child: Text('Navigate to YouTube'),
),
const PopupMenuItem<_MenuOptions>( // Add from here
value: _MenuOptions.userAgent,
child: Text('Show user-agent'),
), // To here.
],
);
}
}
Wenn Sie auf die Menüoption „User-Agent anzeigen“ tippen, wird das Ergebnis der Ausführung des JavaScript-Ausdrucks navigator.userAgent
in einem Snackbar
angezeigt. Wenn Sie die App ausführen, werden Sie feststellen, dass die Seite „Flutter.dev“ anders aussieht. Das ist das Ergebnis der Ausführung mit aktiviertem JavaScript.
10. Mit JavaScript-Channels arbeiten
Mit JavaScript-Channels kann Ihre App Callback-Handler im JavaScript-Kontext des WebViewWidget
registrieren, die aufgerufen werden können, um Werte an den Dart-Code der App zurückzugeben. In diesem Schritt registrieren Sie einen SnackBar
-Channel, der mit dem Ergebnis eines XMLHttpRequest
aufgerufen wird.
Aktualisieren Sie die Klasse WebViewStack
so:
lib/src/web_view_stack.dart
class WebViewStack extends StatefulWidget {
const WebViewStack({required this.controller, super.key});
final WebViewController controller;
@override
State<WebViewStack> createState() => _WebViewStackState();
}
class _WebViewStackState extends State<WebViewStack> {
var loadingPercentage = 0;
@override
void initState() {
super.initState();
widget.controller
..setNavigationDelegate(
NavigationDelegate(
onPageStarted: (url) {
setState(() {
loadingPercentage = 0;
});
},
onProgress: (progress) {
setState(() {
loadingPercentage = progress;
});
},
onPageFinished: (url) {
setState(() {
loadingPercentage = 100;
});
},
onNavigationRequest: (navigation) {
final host = Uri.parse(navigation.url).host;
if (host.contains('youtube.com')) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
'Blocking navigation to $host',
),
),
);
return NavigationDecision.prevent;
}
return NavigationDecision.navigate;
},
),
)
// Modify from here...
..setJavaScriptMode(JavaScriptMode.unrestricted)
..addJavaScriptChannel(
'SnackBar',
onMessageReceived: (message) {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text(message.message)));
},
);
// ...to here.
}
@override
Widget build(BuildContext context) {
return Stack(
children: [
WebViewWidget(
controller: widget.controller,
),
if (loadingPercentage < 100)
LinearProgressIndicator(
value: loadingPercentage / 100.0,
),
],
);
}
}
Für jeden JavaScript-Channel in Set
wird im JavaScript-Kontext ein Channel-Objekt als Fensterattribut mit demselben Namen wie der JavaScript-Channel name
verfügbar gemacht. Wenn Sie dies aus dem JavaScript-Kontext verwenden, müssen Sie postMessage
für den JavaScript-Channel aufrufen, um eine Nachricht zu senden, die an den onMessageReceived
-Callback-Handler des benannten JavascriptChannel
übergeben wird.
Wenn Sie den zuvor hinzugefügten JavaScript-Channel verwenden möchten, fügen Sie ein weiteres Menüelement hinzu, das ein XMLHttpRequest
im JavaScript-Kontext ausführt und die Ergebnisse über den SnackBar
-JavaScript-Channel zurückgibt.
Da WebViewWidget
jetzt über unsere JavaScript-Channels informiert ist,
, fügen Sie ein Beispiel hinzu, um die App weiter zu entwickeln. Fügen Sie dazu der Menu
-Klasse ein zusätzliches PopupMenuItem
hinzu und fügen Sie die zusätzliche Funktion hinzu.
Aktualisieren Sie _MenuOptions
mit der zusätzlichen Menüoption, indem Sie den Enumerationswert javascriptChannel
hinzufügen, und fügen Sie der Klasse Menu
eine Implementierung hinzu:
lib/src/menu.dart
enum _MenuOptions {
navigationDelegate,
userAgent,
javascriptChannel, // Add this option
}
class Menu extends StatefulWidget {
const Menu({required this.controller, super.key});
final WebViewController controller;
@override
State<Menu> createState() => _MenuState();
}
class _MenuState extends State<Menu> {
@override
Widget build(BuildContext context) {
return PopupMenuButton<_MenuOptions>(
onSelected: (value) async {
switch (value) {
case _MenuOptions.navigationDelegate:
await widget.controller
.loadRequest(Uri.parse('https://youtube.com'));
case _MenuOptions.userAgent:
final userAgent = await widget.controller
.runJavaScriptReturningResult('navigator.userAgent');
if (!context.mounted) return;
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('$userAgent'),
));
case _MenuOptions.javascriptChannel: // Add from here
await widget.controller.runJavaScript('''
var req = new XMLHttpRequest();
req.open('GET', "https://api.ipify.org/?format=json");
req.onload = function() {
if (req.status == 200) {
let response = JSON.parse(req.responseText);
SnackBar.postMessage("IP Address: " + response.ip);
} else {
SnackBar.postMessage("Error: " + req.status);
}
}
req.send();'''); // To here.
}
},
itemBuilder: (context) => [
const PopupMenuItem<_MenuOptions>(
value: _MenuOptions.navigationDelegate,
child: Text('Navigate to YouTube'),
),
const PopupMenuItem<_MenuOptions>(
value: _MenuOptions.userAgent,
child: Text('Show user-agent'),
),
const PopupMenuItem<_MenuOptions>( // Add from here
value: _MenuOptions.javascriptChannel,
child: Text('Lookup IP Address'),
), // To here.
],
);
}
}
Dieses JavaScript wird ausgeführt, wenn der Nutzer die Menüoption JavaScript Channel Example auswählt.
var req = new XMLHttpRequest();
req.open('GET', "https://api.ipify.org/?format=json");
req.onload = function() {
if (req.status == 200) {
SnackBar.postMessage(req.responseText);
} else {
SnackBar.postMessage("Error: " + req.status);
}
}
req.send();
Dieser Code sendet eine GET
-Anfrage an eine API für öffentliche IP-Adressen und gibt die IP-Adresse des Geräts zurück. Dieses Ergebnis wird in einem SnackBar
angezeigt, indem postMessage
für das SnackBar
JavascriptChannel
aufgerufen wird.
11. Cookies verwalten
Ihre App kann Cookies im WebView
mit der Klasse CookieManager
verwalten. In diesem Schritt zeigen Sie eine Liste von Cookies an, löschen die Liste von Cookies, löschen Cookies und legen neue Cookies fest. Fügen Sie für jeden der Cookie-Anwendungsfälle Einträge in die _MenuOptions
ein:
lib/src/menu.dart
enum _MenuOptions {
navigationDelegate,
userAgent,
javascriptChannel,
// Add from here ...
listCookies,
clearCookies,
addCookie,
setCookie,
removeCookie,
// ... to here.
}
Die restlichen Änderungen in diesem Schritt beziehen sich auf die Klasse Menu
, einschließlich der Umwandlung der Klasse Menu
von zustandslos zu zustandsbehaftet. Diese Änderung ist wichtig, da das Menu
das CookieManager
besitzen muss und ein veränderlicher Status in zustandslosen Widgets eine schlechte Kombination ist.
Fügen Sie der resultierenden State-Klasse den CookieManager so hinzu:
lib/src/menu.dart
class Menu extends StatefulWidget {
const Menu({required this.controller, super.key});
final WebViewController controller;
@override
State<Menu> createState() => _MenuState();
}
class _MenuState extends State<Menu> {
final cookieManager = WebViewCookieManager(); // Add this line
@override
Widget build(BuildContext context) {
// ...
Die Klasse _MenuState
enthält den Code, der zuvor in der Klasse Menu
hinzugefügt wurde, sowie die neu hinzugefügte CookieManager
. In den nächsten Abschnitten fügen Sie _MenuState
Hilfsfunktionen hinzu, die wiederum von den noch hinzuzufügenden Menüpunkten aufgerufen werden.
Liste aller Cookies abrufen
Sie verwenden JavaScript, um eine Liste aller Cookies abzurufen. Fügen Sie dazu am Ende der Klasse _MenuState
eine Hilfsmethode mit dem Namen _onListCookies
hinzu. Mit der Methode runJavaScriptReturningResult
wird document.cookie
im JavaScript-Kontext ausgeführt und eine Liste aller Cookies zurückgegeben.
Fügen Sie der Klasse _MenuState
Folgendes hinzu:
lib/src/menu.dart
Future<void> _onListCookies(WebViewController controller) async {
final String cookies = await controller
.runJavaScriptReturningResult('document.cookie') as String;
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(cookies.isNotEmpty ? cookies : 'There are no cookies.'),
),
);
}
Alle Cookies löschen
Wenn Sie alle Cookies in der WebView löschen möchten, verwenden Sie die Methode clearCookies
der Klasse CookieManager
. Die Methode gibt ein Future<bool>
zurück, das in true
aufgelöst wird, wenn der CookieManager
die Cookies gelöscht hat, und in false
, wenn keine Cookies zum Löschen vorhanden waren.
Fügen Sie der Klasse _MenuState
Folgendes hinzu:
lib/src/menu.dart
Future<void> _onClearCookies() async {
final hadCookies = await cookieManager.clearCookies();
String message = 'There were cookies. Now, they are gone!';
if (!hadCookies) {
message = 'There were no cookies to clear.';
}
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(message),
),
);
}
Cookie hinzufügen
Cookies können durch Aufrufen von JavaScript hinzugefügt werden. Die API zum Hinzufügen eines Cookies zu einem JavaScript-Dokument ist auf MDN ausführlich dokumentiert.
Fügen Sie der Klasse _MenuState
Folgendes hinzu:
lib/src/menu.dart
Future<void> _onAddCookie(WebViewController controller) async {
await controller.runJavaScript('''var date = new Date();
date.setTime(date.getTime()+(30*24*60*60*1000));
document.cookie = "FirstName=John; expires=" + date.toGMTString();''');
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Custom cookie added.'),
),
);
}
Cookie mit CookieManager setzen
Cookies können auch mit CookieManager festgelegt werden.
Fügen Sie der Klasse _MenuState
Folgendes hinzu:
lib/src/menu.dart
Future<void> _onSetCookie(WebViewController controller) async {
await cookieManager.setCookie(
const WebViewCookie(name: 'foo', value: 'bar', domain: 'flutter.dev'),
);
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Custom cookie is set.'),
),
);
}
Cookie entfernen
Wenn Sie ein Cookie entfernen möchten, müssen Sie ein Cookie mit einem Ablaufdatum in der Vergangenheit hinzufügen.
Fügen Sie der Klasse _MenuState
Folgendes hinzu:
lib/src/menu.dart
Future<void> _onRemoveCookie(WebViewController controller) async {
await controller.runJavaScript(
'document.cookie="FirstName=John; expires=Thu, 01 Jan 1970 00:00:00 UTC" ');
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Custom cookie removed.'),
),
);
}
CookieManager-Menüelemente hinzufügen
Jetzt müssen Sie nur noch die Menüoptionen hinzufügen und sie mit den gerade hinzugefügten Hilfsmethoden verknüpfen. Aktualisieren Sie die Klasse _MenuState
so:
lib/src/menu.dart
class _MenuState extends State<Menu> {
final cookieManager = WebViewCookieManager();
@override
Widget build(BuildContext context) {
return PopupMenuButton<_MenuOptions>(
onSelected: (value) async {
switch (value) {
case _MenuOptions.navigationDelegate:
await widget.controller
.loadRequest(Uri.parse('https://youtube.com'));
case _MenuOptions.userAgent:
final userAgent = await widget.controller
.runJavaScriptReturningResult('navigator.userAgent');
if (!context.mounted) return;
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('$userAgent'),
));
case _MenuOptions.javascriptChannel:
await widget.controller.runJavaScript('''
var req = new XMLHttpRequest();
req.open('GET', "https://api.ipify.org/?format=json");
req.onload = function() {
if (req.status == 200) {
let response = JSON.parse(req.responseText);
SnackBar.postMessage("IP Address: " + response.ip);
} else {
SnackBar.postMessage("Error: " + req.status);
}
}
req.send();''');
case _MenuOptions.clearCookies: // Add from here
await _onClearCookies();
case _MenuOptions.listCookies:
await _onListCookies(widget.controller);
case _MenuOptions.addCookie:
await _onAddCookie(widget.controller);
case _MenuOptions.setCookie:
await _onSetCookie(widget.controller);
case _MenuOptions.removeCookie:
await _onRemoveCookie(widget.controller); // To here.
}
},
itemBuilder: (context) => [
const PopupMenuItem<_MenuOptions>(
value: _MenuOptions.navigationDelegate,
child: Text('Navigate to YouTube'),
),
const PopupMenuItem<_MenuOptions>(
value: _MenuOptions.userAgent,
child: Text('Show user-agent'),
),
const PopupMenuItem<_MenuOptions>(
value: _MenuOptions.javascriptChannel,
child: Text('Lookup IP Address'),
),
const PopupMenuItem<_MenuOptions>( // Add from here
value: _MenuOptions.clearCookies,
child: Text('Clear cookies'),
),
const PopupMenuItem<_MenuOptions>(
value: _MenuOptions.listCookies,
child: Text('List cookies'),
),
const PopupMenuItem<_MenuOptions>(
value: _MenuOptions.addCookie,
child: Text('Add cookie'),
),
const PopupMenuItem<_MenuOptions>(
value: _MenuOptions.setCookie,
child: Text('Set cookie'),
),
const PopupMenuItem<_MenuOptions>(
value: _MenuOptions.removeCookie,
child: Text('Remove cookie'),
), // To here.
],
);
}
CookieManager verwenden
So können Sie alle Funktionen nutzen, die Sie der App gerade hinzugefügt haben:
- Wählen Sie Cookies auflisten aus. Dort sollten die von flutter.dev gesetzten Google Analytics-Cookies aufgeführt sein.
- Wählen Sie Cookies löschen aus. Es sollte angezeigt werden, dass die Cookies tatsächlich gelöscht wurden.
- Wählen Sie noch einmal Cookies löschen aus. Es sollte gemeldet werden, dass keine Cookies zum Löschen verfügbar waren.
- Wählen Sie Cookies auflisten aus. Es sollte gemeldet werden, dass keine Cookies vorhanden sind.
- Wählen Sie Cookie hinzufügen aus. Das Cookie sollte als hinzugefügt gemeldet werden.
- Wählen Sie Cookie festlegen aus. Das Cookie sollte als festgelegt gemeldet werden.
- Wählen Sie Cookies auflisten und dann Cookie entfernen aus.
12. Flutter-Assets, -Dateien und -HTML-Strings in der WebView laden
Ihre App kann HTML-Dateien mit verschiedenen Methoden laden und in der WebView anzeigen. In diesem Schritt laden Sie ein in der Datei pubspec.yaml
angegebenes Flutter-Asset, eine Datei am angegebenen Pfad und eine Seite mit einem HTML-String.
Wenn Sie eine Datei laden möchten, die sich an einem bestimmten Pfad befindet, müssen Sie der pubspec.yaml
die path_provider
hinzufügen. Dies ist ein Flutter-Plug-in zum Auffinden häufig verwendeter Speicherorte im Dateisystem.
Führen Sie in der Befehlszeile folgenden Befehl aus:
$ flutter pub add path_provider
Zum Laden des Assets muss der Pfad zum Asset in pubspec.yaml
angegeben werden. Fügen Sie in pubspec.yaml
die folgenden Zeilen hinzu:
pubspec.yaml
# The following section is specific to Flutter packages.
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
# Add from here
assets:
- assets/www/index.html
- assets/www/styles/style.css
# ... to here.
So fügen Sie die Assets Ihrem Projekt hinzu:
- Erstellen Sie im Stammordner Ihres Projekts ein neues Verzeichnis mit dem Namen
assets
. - Erstellen Sie im Ordner
assets
ein neues Verzeichnis mit dem Namenwww
. - Erstellen Sie im Ordner
www
ein neues Verzeichnis mit dem Namenstyles
. - Erstellen Sie im Ordner
www
eine neue Datei mit dem Namenindex.html
. - Erstellen Sie im Ordner
styles
eine neue Datei mit dem Namenstyle.css
.
Kopieren Sie den folgenden Code in die Datei index.html
:
assets/www/index.html
<!DOCTYPE html>
<!-- Copyright 2013 The Flutter Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file. -->
<html lang="en">
<head>
<title>Load file or HTML string example</title>
<link rel="stylesheet" href="styles/style.css" />
</head>
<body>
<h1>Local demo page</h1>
<p>
This is an example page used to demonstrate how to load a local file or HTML
string using the <a href="https://pub.dev/packages/webview_flutter">Flutter
webview</a> plugin.
</p>
</body>
</html>
Verwenden Sie für style.css die folgenden Zeilen, um den HTML-Headerstil festzulegen:
assets/www/styles/style.css
h1 {
color: blue;
}
Nachdem die Assets festgelegt und einsatzbereit sind, können Sie die Methoden implementieren, die zum Laden und Anzeigen von Flutter-Assets, ‑Dateien oder HTML-Strings erforderlich sind.
Flutter-Asset laden
Um das gerade erstellte Asset zu laden, müssen Sie nur die Methode loadFlutterAsset
mit dem WebViewController
aufrufen und den Pfad zum Asset als Parameter angeben. Fügen Sie am Ende Ihres Codes die folgende Methode hinzu:
lib/src/menu.dart
Future<void> _onLoadFlutterAssetExample(
WebViewController controller, BuildContext context) async {
await controller.loadFlutterAsset('assets/www/index.html');
}
Lokale Datei laden
Wenn Sie eine Datei auf Ihr Gerät laden möchten, können Sie eine Methode hinzufügen, die die Methode loadFile
verwendet. Dazu nutzen Sie wieder WebViewController
, das ein String
mit dem Pfad zur Datei akzeptiert.
Sie müssen zuerst eine Datei mit dem HTML-Code erstellen. Fügen Sie dazu den HTML-Code als String oben in den Code in der Datei menu.dart
direkt unter den Importen ein.
lib/src/menu.dart
import 'dart:io'; // Add this line,
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart'; // And this one.
import 'package:webview_flutter/webview_flutter.dart';
// Add from here ...
const String kExamplePage = '''
<!DOCTYPE html>
<html lang="en">
<head>
<title>Load file or HTML string example</title>
</head>
<body>
<h1>Local demo page</h1>
<p>
This is an example page used to demonstrate how to load a local file or HTML
string using the <a href="https://pub.dev/packages/webview_flutter">Flutter
webview</a> plugin.
</p>
</body>
</html>
''';
// ... to here.
Um eine File
zu erstellen und den HTML-String in die Datei zu schreiben, fügen Sie zwei Methoden hinzu. Mit _onLoadLocalFileExample
wird die Datei geladen, indem der Pfad als String angegeben wird, der von der Methode _prepareLocalFile()
zurückgegeben wird. Fügen Sie Ihrem Code die folgenden Methoden hinzu:
lib/src/menu.dart
Future<void> _onLoadLocalFileExample(
WebViewController controller, BuildContext context) async {
final String pathToIndex = await _prepareLocalFile();
await controller.loadFile(pathToIndex);
}
static Future<String> _prepareLocalFile() async {
final String tmpDir = (await getTemporaryDirectory()).path;
final File indexFile = File('$tmpDir/www/index.html');
await Directory('$tmpDir/www').create(recursive: true);
await indexFile.writeAsString(kExamplePage);
return indexFile.path;
}
HTML-String laden
Eine Seite über einen HTML-String anzuzeigen, ist ganz einfach. Die WebViewController
hat eine Methode namens loadHtmlString
, die Sie verwenden können. Dort können Sie den HTML-String als Argument angeben. Im WebView
wird dann die bereitgestellte HTML-Seite angezeigt. Fügen Sie Ihrem Code die folgende Methode hinzu:
lib/src/menu.dart
Future<void> _onLoadFlutterAssetExample(
WebViewController controller, BuildContext context) async {
await controller.loadFlutterAsset('assets/www/index.html');
}
Future<void> _onLoadLocalFileExample(
WebViewController controller, BuildContext context) async {
final String pathToIndex = await _prepareLocalFile();
await controller.loadFile(pathToIndex);
}
static Future<String> _prepareLocalFile() async {
final String tmpDir = (await getTemporaryDirectory()).path;
final File indexFile = File('$tmpDir/www/index.html');
await Directory('$tmpDir/www').create(recursive: true);
await indexFile.writeAsString(kExamplePage);
return indexFile.path;
}
// Add here ...
Future<void> _onLoadHtmlStringExample(
WebViewController controller, BuildContext context) async {
await controller.loadHtmlString(kExamplePage);
}
// ... to here.
Speisen und Getränke auf der Speisekarte hinzufügen
Nachdem die Assets festgelegt und einsatzbereit sind und die Methoden mit allen Funktionen erstellt wurden, kann das Menü aktualisiert werden. Fügen Sie dem _MenuOptions
-Enum die folgenden Einträge hinzu:
lib/src/menu.dart
enum _MenuOptions {
navigationDelegate,
userAgent,
javascriptChannel,
listCookies,
clearCookies,
addCookie,
setCookie,
removeCookie,
// Add from here ...
loadFlutterAsset,
loadLocalFile,
loadHtmlString,
// ... to here.
}
Nachdem das Enum aktualisiert wurde, können Sie die Menüoptionen hinzufügen und sie mit den gerade hinzugefügten Hilfsmethoden verknüpfen. Aktualisieren Sie die Klasse _MenuState
so:
lib/src/menu.dart
class _MenuState extends State<Menu> {
final cookieManager = WebViewCookieManager();
@override
Widget build(BuildContext context) {
return PopupMenuButton<_MenuOptions>(
onSelected: (value) async {
switch (value) {
case _MenuOptions.navigationDelegate:
await widget.controller
.loadRequest(Uri.parse('https://youtube.com'));
case _MenuOptions.userAgent:
final userAgent = await widget.controller
.runJavaScriptReturningResult('navigator.userAgent');
if (!context.mounted) return;
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('$userAgent'),
));
case _MenuOptions.javascriptChannel:
await widget.controller.runJavaScript('''
var req = new XMLHttpRequest();
req.open('GET', "https://api.ipify.org/?format=json");
req.onload = function() {
if (req.status == 200) {
let response = JSON.parse(req.responseText);
SnackBar.postMessage("IP Address: " + response.ip);
} else {
SnackBar.postMessage("Error: " + req.status);
}
}
req.send();''');
case _MenuOptions.clearCookies:
await _onClearCookies();
case _MenuOptions.listCookies:
await _onListCookies(widget.controller);
case _MenuOptions.addCookie:
await _onAddCookie(widget.controller);
case _MenuOptions.setCookie:
await _onSetCookie(widget.controller);
case _MenuOptions.removeCookie:
await _onRemoveCookie(widget.controller);
case _MenuOptions.loadFlutterAsset: // Add from here
if (!mounted) return;
await _onLoadFlutterAssetExample(widget.controller, context);
case _MenuOptions.loadLocalFile:
if (!mounted) return;
await _onLoadLocalFileExample(widget.controller, context);
case _MenuOptions.loadHtmlString:
if (!mounted) return;
await _onLoadHtmlStringExample(widget.controller, context);
// To here.
}
},
itemBuilder: (context) => [
const PopupMenuItem<_MenuOptions>(
value: _MenuOptions.navigationDelegate,
child: Text('Navigate to YouTube'),
),
const PopupMenuItem<_MenuOptions>(
value: _MenuOptions.userAgent,
child: Text('Show user-agent'),
),
const PopupMenuItem<_MenuOptions>(
value: _MenuOptions.javascriptChannel,
child: Text('Lookup IP Address'),
),
const PopupMenuItem<_MenuOptions>(
value: _MenuOptions.clearCookies,
child: Text('Clear cookies'),
),
const PopupMenuItem<_MenuOptions>(
value: _MenuOptions.listCookies,
child: Text('List cookies'),
),
const PopupMenuItem<_MenuOptions>(
value: _MenuOptions.addCookie,
child: Text('Add cookie'),
),
const PopupMenuItem<_MenuOptions>(
value: _MenuOptions.setCookie,
child: Text('Set cookie'),
),
const PopupMenuItem<_MenuOptions>(
value: _MenuOptions.removeCookie,
child: Text('Remove cookie'),
),
const PopupMenuItem<_MenuOptions>( // Add from here
value: _MenuOptions.loadFlutterAsset,
child: Text('Load Flutter Asset'),
),
const PopupMenuItem<_MenuOptions>(
value: _MenuOptions.loadHtmlString,
child: Text('Load HTML string'),
),
const PopupMenuItem<_MenuOptions>(
value: _MenuOptions.loadLocalFile,
child: Text('Load local file'),
), // To here.
],
);
}
Assets, Datei und HTML-String testen
Wenn Sie testen möchten, ob der gerade implementierte Code funktioniert, können Sie ihn auf Ihrem Gerät ausführen und auf eines der neu hinzugefügten Menüelemente klicken. Beachten Sie, wie mit dem _onLoadFlutterAssetExample
das von uns hinzugefügte style.css
verwendet wird, um die Überschrift der HTML-Datei in Blau zu ändern.
13. Fertig!
Herzlichen Glückwunsch!!! Sie haben das Codelab abgeschlossen. Den vollständigen Code für dieses Codelab finden Sie im Codelab-Repository.
Weitere Informationen finden Sie in den anderen Flutter-Codelabs.