1. Pengantar
Terakhir Diperbarui: 19-10-2021
Dengan plugin WebView Flutter, Anda dapat menambahkan widget WebView ke aplikasi Flutter Android atau iOS Anda. Di iOS, widget WebView didukung oleh WKWebView, sedangkan di Android, widget WebView didukung oleh WebView. Plugin tersebut dapat merender widget Flutter melalui tampilan web. Jadi misalnya, menu drop-down dapat dirender melalui tampilan web.
Yang akan Anda build
Dalam codelab ini, Anda akan mem-build aplikasi seluler langkah demi langkah dengan WebView menggunakan Flutter SDK. Aplikasi Anda akan:
- Menampilkan konten web di
WebView
- Menampilkan widget Flutter yang ditumpuk melalui
WebView
- Menanggapi peristiwa progres pemuatan halaman
- Mengontrol
WebView
melaluiWebViewController
- Memblokir berbagai situs menggunakan
NavigationDelegate
- Mengevaluasi ekspresi JavaScript
- Menangani callback dari JavaScript dengan
JavascriptChannels
- Menetapkan, menghapus, menambahkan, atau menampilkan cookie
- Memuat dan menampilkan HTML dari aset, file, atau String yang berisi HTML
Yang akan Anda pelajari
Dalam codelab ini, Anda akan mempelajari cara menggunakan plugin webview_flutter
dalam berbagai cara, termasuk:
- Cara mengonfigurasi plugin
webview_flutter
- Cara memproses peristiwa progres pemuatan halaman
- Cara mengontrol navigasi halaman
- Cara memerintahkan
WebView
untuk mundur dan maju melalui historinya - Cara mengevaluasi JavaScript, termasuk cara menggunakan hasil yang ditampilkan
- Cara mendaftarkan callback untuk memanggil kode Dart dari JavaScript
- Cara mengelola cookie
- Cara memuat dan menampilkan halaman HTML dari aset atau file atau String yang berisi HTML
Yang akan Anda butuhkan
- Android Studio versi 4.1 atau yang lebih baru (untuk pengembangan Android)
- Xcode versi 12 atau yang lebih baru (untuk pengembangan iOS)
- Flutter SDK
- Editor kode, seperti Android Studio, Visual Studio Code, atau Emacs.
2. Menyiapkan lingkungan Flutter Anda
Anda memerlukan dua software untuk menyelesaikan lab ini: Flutter SDK dan editor.
Anda dapat menjalankan codelab ini menggunakan perangkat berikut:
- Perangkat fisik seluler (Android atau iOS) yang terhubung ke komputer Anda dan disetel ke mode developer.
- Simulator iOS. (Khusus macOS, dan memerlukan penginstalan alat Xcode.)
- Emulator Android. (Memerlukan penyiapan di Android Studio.)
3. Memulai
Mulai menggunakan Flutter
Ada berbagai cara untuk membuat project Flutter baru, Anda dapat menggunakan Android Studio dan Visual Studio Code, keduanya menyediakan alat yang diperlukan untuk tugas ini. Anda bisa mengikuti prosedur yang telah ditautkan untuk membuat project, atau menjalankan perintah berikut di terminal command line dengan mudah.
$ flutter create webview_in_flutter Creating project webview_in_flutter... [Listing of created files elided] Wrote 81 files. All done! In order to run your application, type: $ cd webview_in_flutter $ flutter run Your application code is in webview_in_flutter\lib\main.dart.
Menambahkan plugin WebView Flutter sebagai dependensi
Menambahkan kemampuan tambahan ke aplikasi Flutter adalah hal yang mudah dilakukan menggunakan paket Pub. Dalam codelab ini, Anda akan menambahkan plugin webview_flutter
ke project Anda. Jalankan perintah berikut di terminal.
$ cd webview_in_flutter $ flutter pub add webview_flutter Resolving dependencies... async 2.8.1 (2.8.2 available) characters 1.1.0 (1.2.0 available) matcher 0.12.10 (0.12.11 available) + plugin_platform_interface 2.0.2 test_api 0.4.2 (0.4.8 available) vector_math 2.1.0 (2.1.1 available) + webview_flutter 3.0.0 + webview_flutter_android 2.8.0 + webview_flutter_platform_interface 1.8.0 + webview_flutter_wkwebview 2.7.0 Downloading webview_flutter 3.0.0... Downloading webview_flutter_wkwebview 2.7.0... Downloading webview_flutter_android 2.8.0... Changed 5 dependencies!
Jika memeriksa pubspec.yaml, Anda akan melihat baris tersebut memiliki baris di bagian dependensi untuk plugin webview_flutter
.
Mengonfigurasi Android minSDK
Untuk menggunakan plugin webview_flutter
di Android, Anda perlu menetapkan minSDK
ke 19 atau 20, bergantung pada Tampilan Platform Android yang ingin Anda gunakan. Informasi selengkapnya mengenai Tampilan Platform Android dapat ditemukan di halaman plugin webview_flutter
. Ubah file android/app/build.gradle
Anda sebagai berikut:
android/app/build.gradle
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.example.webview_in_flutter"
minSdkVersion 20 // MODIFY
targetSdkVersion 30
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
4. Menambahkan widget WebView ke Aplikasi Flutter
Di langkah ini, Anda akan menambahkan WebView
ke aplikasi. WebView adalah tampilan native yang dihosting, dan Anda sebagai developer aplikasi memiliki pilihan untuk menghosting tampilan native ini di aplikasi Anda. Di Android, Anda memiliki pilihan antara Display Virtual, yang saat ini merupakan pilihan default untuk Android dan komposisi Hybrid. Namun, iOS selalu menggunakan komposisi Hybrid.
Untuk diskusi mendalam mengenai perbedaan antara Display Virtual dan komposisi Hybrid, harap baca dokumentasi mengenai Menghosting tampilan Android dan iOS native di aplikasi Flutter Anda dengan Tampilan Platform.
Menampilkan Webview di layar
Ganti konten lib/main.dart
dengan konten berikut:
lib/main.dart
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
void main() {
runApp(
const MaterialApp(
home: WebViewApp(),
),
);
}
class WebViewApp extends StatefulWidget {
const WebViewApp({Key? key}) : super(key: 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 WebView(
initialUrl: 'https://flutter.dev',
),
);
}
}
Menjalankan kode ini di iOS atau Android akan menampilkan WebView sebagai jendela browser full bleed di perangkat Anda, yang berarti browser yang ditampilkan di perangkat Anda akan memasuki mode layar penuh tanpa batas atau margin. Saat men-scroll, Anda akan melihat bagian halaman yang mungkin terlihat sedikit aneh. Hal ini dikarenakan JavaScript masih belum aktif dan untuk merender flutter.dev dengan benar diperlukan JavaScript.
Mengaktifkan Komposisi Hybrid
Jika Anda ingin menggunakan mode Komposisi Hybrid untuk perangkat Android, Anda dapat melakukannya dengan beberapa modifikasi kecil. Ubah lib/main.dart
Anda sebagai berikut:
lib/main.dart
import 'dart:io'; // Add this import.
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
void main() {
runApp(
const MaterialApp(
home: WebViewApp(),
),
);
}
class WebViewApp extends StatefulWidget {
const WebViewApp({Key? key}) : super(key: key);
@override
State<WebViewApp> createState() => _WebViewAppState();
}
class _WebViewAppState extends State<WebViewApp> {
// Add from here ...
@override
void initState() {
if (Platform.isAndroid) {
WebView.platform = SurfaceAndroidWebView();
}
super.initState();
}
// ... to here.
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Flutter WebView'),
),
body: const WebView(
initialUrl: 'https://flutter.dev',
),
);
}
}
Jangan lupa untuk mengubah minSdkVersion
di build.gradle
ke 19 saat Anda ingin menggunakan Tampilan Platform komposisi Hybrid.
Menjalankan aplikasi
Jalankan aplikasi Flutter di perangkat iOS atau Android untuk melihat Webview, yang menampilkan situs flutter.dev. Atau, jalankan aplikasi di emulator Android atau iOS. Jangan ragu untuk mengganti URL WebView awal dengan, misalnya, situs Anda sendiri.
$ flutter run
Dengan asumsi bahwa Anda memiliki simulator atau emulator yang sesuai, atau perangkat fisik yang terpasang, setelah mengompilasi dan men-deploy aplikasi ke perangkat, Anda akan melihat sesuatu seperti berikut:
5. Memproses peristiwa pemuatan halaman
Widget WebView
menyediakan beberapa peristiwa progres pemuatan halaman, yang dapat diproses oleh aplikasi Anda. Selama siklus pemuatan halaman WebView
, ada tiga peristiwa pemuatan halaman berbeda yang diaktifkan: onPageStarted
, onProgress
, dan onPageFinished
. Pada langkah ini, Anda akan menerapkan indikator pemuatan halaman. Sebagai bonus, Anda akan ditunjukkan bahwa Anda dapat merender konten Flutter melalui area konten WebView
.
Menambahkan peristiwa pemuatan halaman ke aplikasi Anda
Buat file sumber baru di lib/src/web_view_stack.dart
lalu isi dengan konten berikut:
lib/src/web_view_stack.dart
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
class WebViewStack extends StatefulWidget {
const WebViewStack({Key? key}) : super(key: key);
@override
State<WebViewStack> createState() => _WebViewStackState();
}
class _WebViewStackState extends State<WebViewStack> {
var loadingPercentage = 0;
@override
Widget build(BuildContext context) {
return Stack(
children: [
WebView(
initialUrl: 'https://flutter.dev',
onPageStarted: (url) {
setState(() {
loadingPercentage = 0;
});
},
onProgress: (progress) {
setState(() {
loadingPercentage = progress;
});
},
onPageFinished: (url) {
setState(() {
loadingPercentage = 100;
});
},
),
if (loadingPercentage < 100)
LinearProgressIndicator(
value: loadingPercentage / 100.0,
),
],
);
}
}
Kode ini telah menggabungkan widget WebView
di Stack
, yang menempatkan WebView
secara bersyarat dengan LinearProgressIndicator
saat persentase pemuatan halaman kurang dari 100%. Karena kode ini melibatkan status program yang berubah dari waktu ke waktu, Anda harus menyimpan status ini di class State
yang terkait dengan StatefulWidget
.
Untuk memanfaatkan widget WebViewStack
baru ini, ubah lib/main.dart Anda sebagai berikut:
import 'package:flutter/material.dart';
// Delete the package:webview_flutter/webview_flutter.dart import
import 'src/web_view_stack.dart'; // Add this import
void main() {
runApp(
const MaterialApp(
home: WebViewApp(),
),
);
}
class WebViewApp extends StatefulWidget {
const WebViewApp({Key? key}) : super(key: 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(), // Replace the WebView widget with WebViewStack
);
}
}
Saat menjalankan aplikasi, bergantung pada kondisi jaringan Anda, dan apakah browser telah meng-cache halaman yang Anda buka, Anda akan melihat indikator pemuatan halaman yang ditempatkan di atas area konten WebView
.
6. Menggunakan WebViewController
Mengakses WebViewController dari Widget WebView
Widget WebView
memungkinkan kontrol terprogram dengan WebViewController
. Pengontrol ini tersedia setelah konstruksi widget WebView
melalui callback. Ketersediaan pengontrol ini bersifat asinkron, sehingga menjadikannya kandidat utama untuk class Completer<T>
asinkron Dart.
Update lib/src/web_view_stack.dart
sebagai berikut:
lib/src/web_view_stack.dart
import 'dart:async'; // Add this import for Completer
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
class WebViewStack extends StatefulWidget {
const WebViewStack({required this.controller, Key? key}) : super(key: key); // Modify
final Completer<WebViewController> controller; // Add this attribute
@override
State<WebViewStack> createState() => _WebViewStackState();
}
class _WebViewStackState extends State<WebViewStack> {
var loadingPercentage = 0;
@override
Widget build(BuildContext context) {
return Stack(
children: [
WebView(
initialUrl: 'https://flutter.dev',
// Add from here ...
onWebViewCreated: (webViewController) {
widget.controller.complete(webViewController);
},
// ... to here.
onPageStarted: (url) {
setState(() {
loadingPercentage = 0;
});
},
onProgress: (progress) {
setState(() {
loadingPercentage = progress;
});
},
onPageFinished: (url) {
setState(() {
loadingPercentage = 100;
});
},
),
if (loadingPercentage < 100)
LinearProgressIndicator(
value: loadingPercentage / 100.0,
),
],
);
}
}
Widget WebViewStack
kini menerbitkan pengontrol yang dibuat secara asinkron menggunakan Completer<WebViewController>
. Penerbitan ini adalah alternatif yang lebih ringan untuk membuat argumen fungsi callback guna menyediakan pengontrol ke seluruh aplikasi.
Membuat Kontrol Navigasi
Memiliki WebView
yang berfungsi adalah salah satu tujuannya, tetapi kemampuan untuk menavigasi mundur dan maju pada histori halaman dan memuat ulang halaman akan menjadi tujuan tambahan yang berguna. Untungnya, dengan WebViewController
Anda dapat menambahkan fungsi ini ke aplikasi Anda.
Buat file sumber baru di lib/src/navigation_controls.dart
dan isi dengan konten berikut:
lib/src/navigation_controls.dart
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
class NavigationControls extends StatelessWidget {
const NavigationControls({required this.controller, Key? key})
: super(key: key);
final Completer<WebViewController> controller;
@override
Widget build(BuildContext context) {
return FutureBuilder<WebViewController>(
future: controller.future,
builder: (context, snapshot) {
final WebViewController? controller = snapshot.data;
if (snapshot.connectionState != ConnectionState.done ||
controller == null) {
return Row(
children: const <Widget>[
Icon(Icons.arrow_back_ios),
Icon(Icons.arrow_forward_ios),
Icon(Icons.replay),
],
);
}
return Row(
children: <Widget>[
IconButton(
icon: const Icon(Icons.arrow_back_ios),
onPressed: () async {
if (await controller.canGoBack()) {
await controller.goBack();
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('No back history item')),
);
return;
}
},
),
IconButton(
icon: const Icon(Icons.arrow_forward_ios),
onPressed: () async {
if (await controller.canGoForward()) {
await controller.goForward();
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('No forward history item')),
);
return;
}
},
),
IconButton(
icon: const Icon(Icons.replay),
onPressed: () {
controller.reload();
},
),
],
);
},
);
}
}
Widget ini menggunakan widget FutureBuilder<T>
untuk melakukan repaint dengan tepat saat pengontrol tersedia. Sambil menunggu pengontrol tersedia, ikon tiga baris akan dirender, namun setelah pengontrol muncul, pengontrol tersebut akan diganti dengan Row
dari IconButton
dengan handler onPressed
yang menggunakan controller
untuk menerapkan fungsinya.
Menambahkan kontrol navigasi ke AppBar
Dengan WebViewStack
yang diupdate dan NavigationControls
yang baru dibuat, kini saatnya Anda menyatukan semuanya dalam WebViewApp
yang diupdate. Sebelumnya, Anda telah melihat cara menggunakan Completer<T>
, tetapi bukan tempat pembuatannya. Dengan WebViewApp
yang berada di dekat bagian atas hierarki Widget dalam aplikasi ini, Anda dapat membuatnya pada tingkat ini.
Update file lib/main.dart
sebagai berikut:
lib/main.dart
import 'dart:async'; // Add this import
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart'; // Add this import back
import 'src/navigation_controls.dart'; // Add this import
import 'src/web_view_stack.dart';
void main() {
runApp(
const MaterialApp(
home: WebViewApp(),
),
);
}
class WebViewApp extends StatefulWidget {
const WebViewApp({Key? key}) : super(key: key);
@override
State<WebViewApp> createState() => _WebViewAppState();
}
class _WebViewAppState extends State<WebViewApp> {
final controller = Completer<WebViewController>(); // Instantiate the controller
@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), // Add the controller argument
);
}
}
Menjalankan aplikasi akan memunculkan halaman web dengan kontrol:
7. Melacak navigasi dengan NavigationDelegate
WebView
memberi aplikasi Anda NavigationDelegate,
yang memungkinkan aplikasi Anda melacak dan mengontrol navigasi halaman widget WebView
. Saat navigasi dimulai oleh WebView,
misalnya saat pengguna mengklik link, NavigationDelegate
akan dipanggil. Callback NavigationDelegate
dapat digunakan untuk mengontrol apakah WebView
akan melanjutkan navigasi.
Mendaftarkan NavigationDelegate kustom
Pada langkah ini, Anda akan mendaftarkan callback NavigationDelegate
untuk memblokir navigasi ke YouTube.com. Perhatikan bahwa penerapan sederhana ini juga akan memblokir konten YouTube inline, yang muncul di berbagai halaman dokumentasi Flutter API.
Update lib/src/web_view_stack.dart
sebagai berikut:
lib/src/web_view_stack.dart
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
class WebViewStack extends StatefulWidget {
const WebViewStack({required this.controller, Key? key}) : super(key: key);
final Completer<WebViewController> controller;
@override
State<WebViewStack> createState() => _WebViewStackState();
}
class _WebViewStackState extends State<WebViewStack> {
var loadingPercentage = 0;
@override
Widget build(BuildContext context) {
return Stack(
children: [
WebView(
initialUrl: 'https://flutter.dev',
onWebViewCreated: (webViewController) {
widget.controller.complete(webViewController);
},
onPageStarted: (url) {
setState(() {
loadingPercentage = 0;
});
},
onProgress: (progress) {
setState(() {
loadingPercentage = progress;
});
},
onPageFinished: (url) {
setState(() {
loadingPercentage = 100;
});
},
// Add from here ...
navigationDelegate: (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.
),
if (loadingPercentage < 100)
LinearProgressIndicator(
value: loadingPercentage / 100.0,
),
],
);
}
}
Pada langkah berikutnya, Anda akan menambahkan item menu untuk mengaktifkan pengujian NavigationDelegate
dengan menggunakan class WebViewController
. Langkah ini disiapkan sebagai latihan bagi pembaca untuk meningkatkan logika callback agar hanya memblokir navigasi halaman penuh ke YouTube.com, dan tetap mengizinkan konten YouTube inline dalam dokumentasi API.
8. Menambahkan tombol menu ke AppBar
Selama mempraktikkan beberapa langkah berikutnya, Anda akan membuat tombol menu di widget AppBar
yang digunakan untuk mengevaluasi JavaScript, memanggil saluran JavaScript, dan mengelola cookie. Secara keseluruhan, ini adalah menu yang berguna.
Buat file sumber baru di lib/src/menu.dart
dan isi dengan konten berikut:
lib/src/menu.dart
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
enum _MenuOptions {
navigationDelegate,
}
class Menu extends StatelessWidget {
const Menu({required this.controller, Key? key}) : super(key: key);
final Completer<WebViewController> controller;
@override
Widget build(BuildContext context) {
return FutureBuilder<WebViewController>(
future: controller.future,
builder: (context, controller) {
return PopupMenuButton<_MenuOptions>(
onSelected: (value) async {
switch (value) {
case _MenuOptions.navigationDelegate:
controller.data!.loadUrl('https://youtube.com');
break;
}
},
itemBuilder: (context) => [
const PopupMenuItem<_MenuOptions>(
value: _MenuOptions.navigationDelegate,
child: Text('Navigate to YouTube'),
),
],
);
},
);
}
}
Saat pengguna memilih opsi menu Buka YouTube, metode loadUrl
WebViewController
akan dijalankan. Navigasi ini akan diblokir oleh callback navigationDelegate
yang Anda buat di langkah sebelumnya.
Untuk menambahkan menu ke layar WebViewApp
, ubah lib/main.dart
sebagai berikut:
lib/main.dart
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'src/menu.dart'; // Add this import
import 'src/navigation_controls.dart';
import 'src/web_view_stack.dart';
void main() {
runApp(
const MaterialApp(
home: WebViewApp(),
),
);
}
class WebViewApp extends StatefulWidget {
const WebViewApp({Key? key}) : super(key: key);
@override
State<WebViewApp> createState() => _WebViewAppState();
}
class _WebViewAppState extends State<WebViewApp> {
final controller = Completer<WebViewController>();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Flutter WebView'),
actions: [
NavigationControls(controller: controller),
Menu(controller: controller), // Add this line
],
),
body: WebViewStack(controller: controller),
);
}
}
Jalankan aplikasi Anda dan ketuk item menu Buka YouTube. Anda akan disambut dengan SnackBar yang menginformasikan bahwa pengontrol navigasi telah memblokir navigasi ke YouTube.
9. Mengevaluasi JavaScript
WebViewController
dapat mengevaluasi ekspresi JavaScript dalam konteks halaman saat ini. Ada dua cara untuk mengevaluasi JavaScript: untuk kode JavaScript yang tidak menampilkan nilai, gunakan runJavaScript
, dan untuk kode JavaScript yang menampilkan nilai, gunakan runJavaScriptReturningResult
.
Untuk mengaktifkan JavaScript, Anda harus mengonfigurasi widget WebView
dengan properti javaScriptMode
yang disetel ke JavascriptMode.unrestricted
. Secara default, javascriptMode
disetel ke JavascriptMode.disabled
.
Update class _WebViewStackState
dengan menambahkan setelan javascriptMode
sebagai berikut:
lib/src/web_view_stack.dart
class _WebViewStackState extends State<WebViewStack> {
var loadingPercentage = 0;
@override
Widget build(BuildContext context) {
return Stack(
children: [
WebView(
initialUrl: 'https://flutter.dev',
onWebViewCreated: (webViewController) {
widget.controller.complete(webViewController);
},
onPageStarted: (url) {
setState(() {
loadingPercentage = 0;
});
},
onProgress: (progress) {
setState(() {
loadingPercentage = progress;
});
},
onPageFinished: (url) {
setState(() {
loadingPercentage = 100;
});
},
navigationDelegate: (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;
},
javascriptMode: JavascriptMode.unrestricted, // Add this line
),
if (loadingPercentage < 100)
LinearProgressIndicator(
value: loadingPercentage / 100.0,
),
],
);
}
}
Setelah WebView
dapat menjalankan JavaScript, Anda dapat menambahkan opsi pada menu tersebut untuk menggunakan metode runJavaScriptReturningResult
.
Ubah lib/src/menu.dart
sebagai berikut:
lib/src/menu.dart
enum _MenuOptions {
navigationDelegate,
userAgent, // Add this line
}
class Menu extends StatelessWidget {
const Menu({required this.controller, Key? key}) : super(key: key);
final Completer<WebViewController> controller;
@override
Widget build(BuildContext context) {
return FutureBuilder<WebViewController>(
future: controller.future,
builder: (context, controller) {
return PopupMenuButton<_MenuOptions>(
onSelected: (value) async {
switch (value) {
case _MenuOptions.navigationDelegate:
controller.data!.loadUrl('https://youtube.com');
break;
// Add from here ...
case _MenuOptions.userAgent:
final userAgent = await controller.data!
.runJavascriptReturningResult('navigator.userAgent');
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(userAgent),
));
break;
// ... to here.
}
},
itemBuilder: (context) => [
const PopupMenuItem<_MenuOptions>(
value: _MenuOptions.navigationDelegate,
child: Text('Navigate to YouTube'),
),
// Add from here ...
const PopupMenuItem<_MenuOptions>(
value: _MenuOptions.userAgent,
child: Text('Show user-agent'),
),
// ... to here.
],
);
},
);
}
}
Jika Anda mengetuk opsi menu 'Tampilkan agen pengguna', hasil dari mengeksekusi ekspresi JavaScript navigator.userAgent
akan ditampilkan dalam Snackbar
. Saat menjalankan aplikasi tersebut, Anda mungkin melihat bahwa halaman Flutter.dev terlihat berbeda. Halaman ini adalah hasilnya saat JavaScript diaktifkan ketika aplikasi dijalankan.
10. Menggunakan Saluran JavaScript
JavascriptChannel
memungkinkan aplikasi Anda mendaftarkan handler callback dalam konteks JavaScript WebView
yang dapat dipanggil untuk mengirimkan nilai kembali ke kode Dart Aplikasi. Pada langkah ini, Anda akan mendaftarkan saluran SnackBar
yang akan dipanggil dengan hasil XMLHttpRequest
.
Update class WebViewStack
sebagai berikut:
lib/src/web_view_stack.dart
class WebViewStack extends StatefulWidget {
const WebViewStack({required this.controller, Key? key}) : super(key: key);
final Completer<WebViewController> controller;
@override
State<WebViewStack> createState() => _WebViewStackState();
}
class _WebViewStackState extends State<WebViewStack> {
var loadingPercentage = 0;
@override
Widget build(BuildContext context) {
return Stack(
children: [
WebView(
initialUrl: 'https://flutter.dev',
onWebViewCreated: (webViewController) {
widget.controller.complete(webViewController);
},
onPageStarted: (url) {
setState(() {
loadingPercentage = 0;
});
},
onProgress: (progress) {
setState(() {
loadingPercentage = progress;
});
},
onPageFinished: (url) {
setState(() {
loadingPercentage = 100;
});
},
navigationDelegate: (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;
},
javascriptMode: JavascriptMode.unrestricted,
javascriptChannels: _createJavascriptChannels(context), // Add this line
),
if (loadingPercentage < 100)
LinearProgressIndicator(
value: loadingPercentage / 100.0,
),
],
);
}
// Add from here ...
Set<JavascriptChannel> _createJavascriptChannels(BuildContext context) {
return {
JavascriptChannel(
name: 'SnackBar',
onMessageReceived: (message) {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text(message.message)));
},
),
};
}
// ... to here.
}
Untuk setiap JavascriptChannel
di Set
, objek saluran disediakan dalam konteks JavaScript sebagai properti jendela dengan nama yang sama seperti JavascriptChannel.name
. Menggunakannya dari konteks JavaScript melibatkan pemanggilan postMessage
pada JavaScriptChannel untuk mengirim pesan yang diteruskan ke handler callback onMessageReceived
JavascriptChannel
yang diberi nama.
Untuk memanfaatkan JavascriptChannel
yang ditambahkan di atas, tambahkan item menu lain yang menjalankan XMLHttpRequest
dalam konteks JavaScript dan meneruskan kembali hasilnya menggunakan SnackBar
JavascriptChannel
.
Setelah WebView
mengetahui tentang JavascriptChannels,
, Anda akan menambahkan contoh untuk memperluas aplikasi lebih lanjut. Untuk melakukannya, tambahkan PopupMenuItem
tambahan ke class Menu
dan tambahkan fungsi tambahan.
Update _MenuOptions
dengan opsi menu tambahan, dengan menambahkan nilai enumerasi javascriptChannel
, dan tambahkan implementasi ke class Menu
seperti berikut:
lib/src/menu.dart
enum _MenuOptions {
navigationDelegate,
userAgent,
javascriptChannel, // Add this line
}
class Menu extends StatelessWidget {
const Menu({required this.controller, Key? key}) : super(key: key);
final Completer<WebViewController> controller;
@override
Widget build(BuildContext context) {
return FutureBuilder<WebViewController>(
future: controller.future,
builder: (context, controller) {
return PopupMenuButton<_MenuOptions>(
onSelected: (value) async {
switch (value) {
case _MenuOptions.navigationDelegate:
controller.data!.loadUrl('https://youtube.com');
break;
case _MenuOptions.userAgent:
final userAgent = await controller.data!
.runJavascriptReturningResult('navigator.userAgent');
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(userAgent),
));
break;
// Add from here ...
case _MenuOptions.javascriptChannel:
await controller.data!.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();''');
break;
// ... 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'),
),
// Add from here ...
const PopupMenuItem<_MenuOptions>(
value: _MenuOptions.javascriptChannel,
child: Text('Lookup IP Address'),
),
// ... to here.
],
);
},
);
}
}
JavaScript ini dieksekusi saat pengguna memilih opsi menu Contoh Saluran JavaScript.
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();
Kode ini mengirim permintaan GET
ke API Alamat IP Publik, yang menampilkan alamat IP perangkat. Hasil ini ditampilkan di SnackBar
dengan memanggil postMessage
yang berada di SnackBar
JavascriptChannel
.
11. Mengelola Cookie
Aplikasi Anda dapat mengelola cookie di WebView
dengan menggunakan class CookieManager
. Pada langkah ini, Anda akan menampilkan daftar cookie, menghapus daftar cookie, menghapus cookie, dan menetapkan cookie baru. Tambahkan entri ke _MenuOptions
untuk setiap kasus penggunaan cookie sebagai berikut:
lib/src/menu.dart
enum _MenuOptions {
navigationDelegate,
userAgent,
javascriptChannel,
// Add from here ...
listCookies,
clearCookies,
addCookie,
setCookie,
removeCookie,
// ... to here.
}
Perubahan lainnya dalam langkah ini berfokus pada class Menu
, termasuk konversi class Menu
dari stateless menjadi stateful. Perubahan ini penting karena Menu
harus memiliki CookieManager
, dan status yang dapat diubah pada widget stateless adalah kombinasi yang buruk.
Dengan menggunakan Editor atau pekerjaan keyboard Anda, konversi class Menu ke StatefulWidget dan tambahkan CookieManager ke class Status yang dihasilkan sebagai berikut:
lib/src/menu.dart
class Menu extends StatefulWidget { // Convert to StatefulWidget
const Menu({required this.controller, Key? key}) : super(key: key);
final Completer<WebViewController> controller;
@override
State<Menu> createState() => _MenuState(); // Add this line
}
class _MenuState extends State<Menu> { // New State class
final CookieManager cookieManager = CookieManager(); // Add this line
@override
Widget build(BuildContext context) {
// ...
Class _MenuState
akan berisi kode yang sebelumnya ditambahkan di class Menu
, beserta CookieManager
yang baru ditambahkan. Pada seri bagian berikutnya, Anda akan menambahkan fungsi bantuan ke _MenuState
yang, pada gilirannya, akan dipanggil oleh item menu yang belum ditambahkan.
Mendapatkan daftar semua cookie
Anda akan menggunakan JavaScript untuk mendapatkan daftar semua cookie. Untuk mendapatkannya, tambahkan metode bantuan ke akhir class _MenuState
, yang disebut _onListCookies
. Dengan menggunakan metode runJavaScriptReturningResult
, metode bantuan Anda akan mengeksekusi document.cookie
dalam konteks JavaScript, yang nantinya akan menampilkan daftar semua cookie.
Tambahkan konten berikut ke class _MenuState
:
lib/src/menu.dart
Future<void> _onListCookies(WebViewController controller) async {
final String cookies =
await controller.runJavascriptReturningResult('document.cookie');
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(cookies.isNotEmpty ? cookies : 'There are no cookies.'),
),
);
}
Hapus semua cookie
Untuk menghapus semua cookie di WebView, gunakan metode clearCookies
dari class CookieManager
. Metode ini akan menampilkan Future<bool>
yang me-resolve ke true
jika CookieManager
menghapus cookie tersebut, dan false
jika tidak ada cookie yang dihapus.
Tambahkan konten berikut ke class _MenuState
:
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.';
}
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(message),
),
);
}
Menambahkan cookie
Menambahkan cookie dapat dilakukan dengan memanggil JavaScript. API yang digunakan untuk menambahkan Cookie ke dokumen JavaScript didokumentasikan secara mendalam di MDN.
Tambahkan konten berikut ke class _MenuState
:
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();''');
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Custom cookie added.'),
),
);
}
Menetapkan cookie menggunakan CookieManager
Cookie juga dapat ditetapkan menggunakan CookieManager dengan cara berikut.
Tambahkan konten berikut ke class _MenuState
:
lib/src/menu.dart
Future<void> _onSetCookie(WebViewController controller) async {
await cookieManager.setCookie(
const WebViewCookie(name: 'foo', value: 'bar', domain: 'flutter.dev'),
);
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Custom cookie is set.'),
),
);
}
Menghapus cookie
Penghapusan cookie melibatkan penambahan cookie, dengan tanggal habis masa berlaku yang telah ditetapkan sebelumnya.
Tambahkan konten berikut ke class _MenuState
:
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" ');
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Custom cookie removed.'),
),
);
}
Menambahkan item Menu CookieManager
Langkah yang tersisa hanyalah menambahkan opsi menu, dan menghubungkannya ke metode bantuan yang baru saja Anda tambahkan. Update class _MenuState
sebagai berikut:
lib/src/menu.dart
class _MenuState extends State<Menu> {
final CookieManager cookieManager = CookieManager();
@override
Widget build(BuildContext context) {
return FutureBuilder<WebViewController>(
future: widget.controller.future,
builder: (context, controller) {
return PopupMenuButton<_MenuOptions>(
onSelected: (value) async {
switch (value) {
case _MenuOptions.navigationDelegate:
controller.data!.loadUrl('https://youtube.com');
break;
case _MenuOptions.userAgent:
final userAgent = await controller.data!
.runJavascriptReturningResult('navigator.userAgent');
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(userAgent),
));
break;
case _MenuOptions.javascriptChannel:
await controller.data!.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();''');
break;
// Add from here ...
case _MenuOptions.clearCookies:
_onClearCookies();
break;
case _MenuOptions.listCookies:
_onListCookies(controller.data!);
break;
case _MenuOptions.addCookie:
_onAddCookie(controller.data!);
break;
case _MenuOptions.setCookie:
_onSetCookie(controller.data!);
break;
case _MenuOptions.removeCookie:
_onRemoveCookie(controller.data!);
break;
// ... 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'),
),
// Add from here ...
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'),
),
// ... to here.
],
);
},
);
}
Menerapkan CookieManager
Untuk menggunakan semua fungsi yang baru saja Anda tambahkan ke aplikasi, coba langkah berikut:
- Pilih Cantumkan cookie. Langkah ini akan mencantumkan cookie Google Analytics yang ditetapkan oleh flutter.dev.
- Pilih Hapus cookie. Langkah ini akan melaporkan bahwa cookie telah dihapus.
- Pilih Hapus cookie lagi. Langkah ini akan melaporkan bahwa tidak ada cookie yang tersedia untuk dihapus.
- Pilih Cantumkan cookie. Langkah ini akan melaporkan bahwa tidak ada cookie.
- Pilih Tambahkan cookie. Langkah ini akan melaporkan cookie setiap kali ditambahkan.
- Pilih Tetapkan cookie. Langkah ini akan melaporkan bahwa cookie telah ditetapkan.
- Pilih Cantumkan cookie, lalu sebagai langkah terakhir, pilih Hapus cookie.
12. Memuat aset, file, dan string HTML Flutter di WebView
Aplikasi Anda dapat memuat file HTML menggunakan metode lain dan menampilkannya di WebView. Di langkah ini, Anda akan memuat aset Flutter yang ditentukan dalam file pubspec.yaml
, memuat file yang berada di jalur yang ditentukan, dan memuat halaman menggunakan String HTML.
Jika ingin memuat file yang berada di jalur yang ditentukan, Anda harus menambahkan path_provider
ke pubspec.yaml
. Ini adalah plugin Flutter yang berfungsi untuk menemukan lokasi yang biasa digunakan pada sistem file.
Pada pubspec.yaml, tambahkan baris berikut:
dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.2
webview_flutter: ^3.0.0
path_provider: ^2.0.7 # Add this line
Untuk memuat aset, kita harus menentukan jalur ke aset tersebut di pubspec.yaml
. Di bagian pubspec.yaml
, tambahkan baris berikut:
pubspec.yaml
# The following section is specific to Flutter.
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.
Untuk menambahkan aset tersebut ke project Anda, lakukan langkah-langkah berikut:
- Buat Direktori baru dengan nama
assets
dalam folder root project Anda. - Buat Direktori baru dengan nama
www
dalam folderassets
. - Buat Direktori baru dengan nama
styles
dalam folderwww
. - Buat File baru dengan nama
index.html
dalam folderwww
. - Buat File baru dengan nama
style.css
dalam folderstyles
.
Salin dan tempel kode berikut di file 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>
Untuk style.css, gunakan beberapa baris berikut untuk menetapkan gaya header HTML:
h1 {
color: blue;
}
Setelah aset ditetapkan dan siap digunakan, Anda dapat menerapkan metode yang diperlukan untuk memuat dan menampilkan aset, file, atau String HTML Flutter.
Memuat aset Flutter
Untuk memuat aset yang baru saja dibuat, cukup panggil metode loadFlutterAsset
menggunakan WebViewController
dan berikan jalur ke aset tersebut sebagai parameter. Tambahkan metode berikut di akhir kode Anda:
lib/src/menu.dart
Future<void> _onLoadFlutterAssetExample(
WebViewController controller, BuildContext context) async {
await controller.loadFlutterAsset('assets/www/index.html');
}
Memuat file lokal
Untuk memuat file di perangkat, Anda dapat menambahkan metode yang akan menggunakan metode loadFile
, sekali lagi dengan WebViewController
yang menggunakan String
yang berisi jalur ke file tersebut.
Anda harus membuat file yang berisi kode HTML terlebih dahulu. Anda dapat melakukannya dengan menambahkan kode HTML sebagai String di bagian atas kode dalam file menu.dart
yang tepat berada di bagian bawah impor.
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
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.
Untuk membuat File
dan menulis String HTML ke file tersebut, Anda akan menambahkan dua metode. _onLoadLocalFileExample
akan memuat file tersebut dengan menyediakan jalur sebagai String yang ditampilkan oleh metode _prepareLocalFile()
. Tambahkan metode berikut ke kode Anda:
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;
}
// ... to here.
Memuat String HTML
Untuk menampilkan halaman dengan menyediakan string HTML adalah hal yang cukup mudah. WebViewController
memiliki metode yang dapat Anda gunakan bernama loadHtmlString
, tempat Anda dapat memberikan String HTML sebagai argumen. WebView
kemudian akan menampilkan halaman HTML yang disediakan. Tambahkan metode berikut ke kode Anda:
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.
Menambahkan item menu
Setelah aset ditetapkan dan siap digunakan, serta metode dengan semua fungsinya telah dibuat, menu dapat diperbarui. Tambahkan entri berikut ke enum _MenuOptions
:
lib/src/menu.dart
enum _MenuOptions {
navigationDelegate,
userAgent,
javascriptChannel,
listCookies,
clearCookies,
addCookie,
setCookie,
removeCookie,
// Add from here ...
loadFlutterAsset,
loadLocalFile,
loadHtmlString,
// ... to here.
}
Setelah enum diupdate, sekarang Anda dapat menambahkan opsi menu dan menghubungkannya ke metode bantuan yang baru saja Anda tambahkan. Update class _MenuState
sebagai berikut:
lib/src/menu.dart
class _MenuState extends State<Menu> {
final CookieManager cookieManager = CookieManager();
@override
Widget build(BuildContext context) {
return FutureBuilder<WebViewController>(
future: widget.controller.future,
builder: (context, controller) {
return PopupMenuButton<_MenuOptions>(
onSelected: (value) async {
switch (value) {
case _MenuOptions.navigationDelegate:
controller.data!.loadUrl('https://youtube.com');
break;
case _MenuOptions.userAgent:
final userAgent = await controller.data!
.runJavascriptReturningResult('navigator.userAgent');
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(userAgent),
));
break;
case _MenuOptions.javascriptChannel:
await controller.data!.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();''');
break;
case _MenuOptions.clearCookies:
_onClearCookies();
break;
case _MenuOptions.listCookies:
_onListCookies(controller.data!);
break;
case _MenuOptions.addCookie:
_onAddCookie(controller.data!);
break;
case _MenuOptions.setCookie:
_onSetCookie(controller.data!);
break;
case _MenuOptions.removeCookie:
_onRemoveCookie(controller.data!);
Break;
// Add from here ...
case _MenuOptions.loadFlutterAsset:
_onLoadFlutterAssetExample(controller.data!, context);
break;
case _MenuOptions.loadLocalFile:
_onLoadLocalFileExample(controller.data!, context);
break;
case _MenuOptions.loadHtmlString:
_onLoadHtmlStringExample(controller.data!, context);
Break;
// ... 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'),
),
// Add from here ...
const PopupMenuItem<_MenuOptions>(
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.
],
);
},
);
}
Menguji aset, file, dan string HTML
Untuk menguji apakah kode yang baru saja diterapkan telah berfungsi dengan baik, Anda dapat menjalankan kode tersebut di perangkat dan mengklik salah satu item menu yang baru ditambahkan. Perhatikan cara _onLoadFlutterAssetExample
menggunakan style.css
yang ditambahkan untuk mengubah warna header file HTML menjadi biru.
13. Selesai!
Selamat. Anda telah menyelesaikan codelab. Anda dapat menemukan kode yang sudah selesai untuk codelab ini di repositori codelab.
Untuk mempelajari lebih lanjut, coba codelab Flutter lain.