1. مقدمه
آخرین به روز رسانی: 2021-10-19
با افزونه WebView Flutter می توانید ویجت WebView را به برنامه Flutter اندروید یا iOS خود اضافه کنید. در iOS ویجت WebView توسط یک WKWebView پشتیبانی می شود، در حالی که در Android ویجت WebView توسط یک WebView پشتیبانی می شود. این افزونه می تواند ویجت های Flutter را در نمای وب ارائه دهد. بنابراین به عنوان مثال می توان یک منوی کشویی را در نمای وب ارائه کرد.
چیزی که خواهی ساخت
در این کد لبه، شما یک برنامه تلفن همراه را مرحله به مرحله میسازید که دارای WebView با استفاده از Flutter SDK است. برنامه شما:
- نمایش محتوای وب در
WebView
- ویجتهای Flutter را که روی
WebView
انباشته شدهاند نمایش دهید - به رویدادهای پیشرفت بارگذاری صفحه واکنش نشان دهید
-
WebView
از طریقWebViewController
کنترل کنید - وب سایت ها را با استفاده از
NavigationDelegate
مسدود کنید - عبارات جاوا اسکریپت را ارزیابی کنید
- با
JavascriptChannels
، تماس های جاوا اسکریپت را مدیریت کنید - تنظیم، حذف، افزودن یا نمایش کوکی ها
- HTML را از دارایی ها، فایل ها یا رشته های حاوی HTML بارگیری و نمایش دهید
چیزی که یاد خواهید گرفت
در این لبه کد یاد خواهید گرفت که چگونه از پلاگین webview_flutter
به روش های مختلفی استفاده کنید، از جمله:
- نحوه پیکربندی افزونه
webview_flutter
- نحوه گوش دادن به رویدادهای پیشرفت بارگذاری صفحه
- نحوه کنترل پیمایش صفحه
- چگونه به
WebView
دستور دهیم که در طول تاریخچه خود به عقب و جلو برود - نحوه ارزیابی جاوا اسکریپت، از جمله استفاده از نتایج بازگشتی
- نحوه ثبت تماس برای فراخوانی کد دارت از جاوا اسکریپت
- نحوه مدیریت کوکی ها
- نحوه بارگذاری و نمایش صفحات HTML از دارایی ها یا فایل ها یا رشته های حاوی HTML
آنچه شما نیاز دارید
- Android Studio نسخه 4.1 یا بالاتر (برای توسعه اندروید)
- Xcode 12 یا بالاتر (برای توسعه iOS)
- فلوتر SDK
- یک ویرایشگر کد، مانند Android Studio ، Visual Studio Code یا Emacs .
2. محیط توسعه Flutter خود را تنظیم کنید
برای تکمیل این آزمایشگاه به دو نرم افزار نیاز دارید - Flutter SDK و یک ویرایشگر .
شما می توانید کدلب را با استفاده از هر یک از این دستگاه ها اجرا کنید:
- یک دستگاه فیزیکی Android یا iOS که به رایانه شما متصل شده و روی حالت Developer تنظیم شده است.
- شبیه ساز iOS (نیاز به نصب ابزار Xcode دارد).
- شبیه ساز اندروید (نیاز به نصب در Android Studio دارد).
3. شروع به کار
شروع کار با فلاتر
راه های مختلفی برای ایجاد یک پروژه فلاتر جدید وجود دارد که هم Android Studio و هم Visual Studio Code ابزارهایی برای این کار ارائه می دهند. یا رویه های مرتبط را برای ایجاد یک پروژه دنبال کنید، یا دستورات زیر را در ترمینال خط فرمان مفید اجرا کنید.
$ 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 به عنوان یک وابستگی
افزودن قابلیت اضافی به برنامه Flutter با استفاده از بستههای Pub آسان است. در این کد لبه پلاگین webview_flutter
را به پروژه خود اضافه خواهید کرد. دستورات زیر را در ترمینال اجرا کنید.
$ 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.
اگر pubspec.yaml خود را بررسی کنید، اکنون خواهید دید که یک خط در بخش وابستگی ها برای افزونه webview_flutter
دارد.
MinSDK اندروید را پیکربندی کنید
برای استفاده از افزونه webview_flutter
در اندروید باید minSDK
روی 20
تنظیم کنید. فایل android/app/build.gradle
خود را به صورت زیر تغییر دهید:
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 به برنامه Flutter
در این مرحله یک WebView
به برنامه خود اضافه می کنید. WebView ها نماهای بومی میزبانی می شوند و شما به عنوان یک توسعه دهنده برنامه می توانید نحوه میزبانی این نماهای بومی را در برنامه خود انتخاب کنید. در اندروید شما می توانید بین نمایشگرهای مجازی، که در حال حاضر پیش فرض برای اندروید است، و ترکیب ترکیبی انتخاب کنید. با این حال، iOS همیشه از ترکیب ترکیبی استفاده می کند.
برای بحث عمیق در مورد تفاوتهای بین نمایشگرهای مجازی و ترکیب ترکیبی، لطفاً مستندات مربوط به میزبانی نماهای بومی Android و iOS را در برنامه Flutter خود با پلتفرم Views مطالعه کنید.
قرار دادن نمای وب روی صفحه
محتویات lib/main.dart
را با موارد زیر جایگزین کنید:
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,
),
);
}
}
با اجرای این برنامه در iOS یا Android، یک WebView به عنوان یک پنجره مرورگر کامل در دستگاه شما نشان داده می شود، به این معنی که مرورگر در دستگاه شما به صورت تمام صفحه بدون هیچ گونه حاشیه یا حاشیه نشان داده می شود. با اسکرول کردن، متوجه قسمت هایی از صفحه می شوید که ممکن است کمی عجیب به نظر برسند. این به این دلیل است که جاوا اسکریپت در حال حاضر غیرفعال است و رندر کردن flutter.dev به درستی به جاوا اسکریپت نیاز دارد.
اجرای برنامه
برنامه Flutter را در iOS یا Android اجرا کنید تا یک Webview را ببینید که وب سایت flutter.dev را نمایش می دهد. یا برنامه را در شبیه ساز اندروید یا شبیه ساز iOS اجرا کنید. به راحتی می توانید URL اولیه WebView را با وب سایت خود جایگزین کنید.
$ flutter run
با فرض اینکه شبیه ساز یا شبیه ساز مناسب را در حال اجرا دارید یا یک دستگاه فیزیکی متصل شده اید، پس از کامپایل و استقرار برنامه در دستگاه خود، باید چیزی شبیه به زیر مشاهده کنید:
5. گوش دادن به رویدادهای بارگذاری صفحه
ویجت WebView
چندین رویداد پیشرفت بارگذاری صفحه را ارائه می دهد که برنامه شما می تواند به آنها گوش دهد. در طول چرخه بارگذاری صفحه WebView
، سه رویداد بارگیری صفحه متفاوت وجود دارد: onPageStarted
، onProgress
و onPageFinished
. در این مرحله شما یک نشانگر بارگذاری صفحه را پیاده سازی می کنید. به عنوان یک امتیاز، این نشان می دهد که می توانید محتوای Flutter را در قسمت محتوای WebView
ارائه دهید.
افزودن رویدادهای بارگذاری صفحه به برنامه شما
یک فایل منبع جدید در lib/src/web_view_stack.dart
ایجاد کنید و آن را با محتوای زیر پر کنید:
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,
),
],
);
}
}
این کد ویجت WebView
را در یک Stack
پیچیده کرده است، و به طور مشروط WebView
با یک LinearProgressIndicator
زمانی که درصد بارگذاری صفحه کمتر از 100٪ است، پوشش داده است. از آنجایی که این شامل حالت برنامه است که در طول زمان تغییر می کند، شما این حالت را در یک کلاس State
مرتبط با StatefulWidget
ذخیره کرده اید.
برای استفاده از این ویجت جدید WebViewStack
، lib/main.dart
خود را به صورت زیر تغییر دهید:
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(),
);
}
}
وقتی برنامه را اجرا میکنید، بسته به شرایط شبکهتان، و اینکه آیا مرورگر صفحهای را که در آن پیمایش میکنید ذخیره کرده است یا خیر، یک نشانگر بارگذاری صفحه را میبینید که در بالای قسمت محتوای WebView
قرار گرفته است.
6. کار با WebViewController
دسترسی به WebViewController از ویجت WebView
ویجت WebView
کنترل برنامه ای را با یک WebViewController
فعال می کند. این کنترلر پس از ساخت ویجت WebView
از طریق یک callback در دسترس قرار می گیرد. ماهیت ناهمزمان در دسترس بودن این کنترلر، آن را به یک کاندیدای اصلی برای کلاس Completer<T>
دارت تبدیل می کند.
lib/src/web_view_stack.dart
را به صورت زیر به روز کنید:
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,
),
],
);
}
}
ویجت WebViewStack
اکنون از یک کنترلر ایجاد شده در ویجت اطراف استفاده می کند. این کار کنترلر WebViewWidget
را قادر می سازد تا به راحتی با سایر بخش های برنامه به اشتراک گذاشته شود.
ساخت کنترل های ناوبری
داشتن یک WebView
کار یک چیز است، اما توانایی پیمایش به عقب و جلو در تاریخچه صفحه، و بارگذاری مجدد صفحه، مجموعه مفیدی از اضافات خواهد بود. خوشبختانه، با یک WebViewController
می توانید این قابلیت را به برنامه خود اضافه کنید.
یک فایل منبع جدید در lib/src/navigation_controls.dart
ایجاد کنید و آن را با موارد زیر پر کنید:
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();
},
),
],
);
}
}
این ویجت از WebViewController
به اشتراک گذاشته شده با آن در زمان ساخت استفاده می کند تا کاربر بتواند WebView
از طریق یک سری IconButton
کنترل کند.
افزودن کنترل های ناوبری به AppBar
با در دست داشتن WebViewStack
بهروز شده و NavigationControls
که به تازگی ساخته شدهاند، اکنون زمان آن فرا رسیده است که همه آنها را در یک WebViewApp
بهروز شده قرار دهید. اینجاست که ما WebViewController
مشترک را می سازیم. با داشتن WebViewApp
در نزدیکی بالای درخت ویجت در این برنامه، ایجاد آن در این سطح منطقی است.
فایل lib/main.dart
را به صورت زیر به روز کنید:
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
);
}
}
اجرای برنامه باید یک صفحه وب با کنترل های زیر را نشان دهد:
7. پیگیری ناوبری با NavigationDelegate
WebView
به برنامه شما یک NavigationDelegate,
ارائه می دهد که به برنامه شما امکان می دهد تا پیمایش صفحه ویجت WebView
را ردیابی و کنترل کند. هنگامی که یک ناوبری توسط WebView,
برای مثال زمانی که کاربر روی یک پیوند کلیک می کند، NavigationDelegate
فراخوانی می شود. از NavigationDelegate
می توان برای کنترل اینکه آیا WebView
با پیمایش ادامه می یابد یا خیر، استفاده کرد.
یک NavigationDelegate سفارشی ثبت کنید
در این مرحله، برای مسدود کردن پیمایش در YouTube.com ، یک پاسخ تماس NavigationDelegate
ثبت میکنید. توجه داشته باشید، این پیاده سازی ساده همچنین محتوای درون خطی YouTube را که در صفحات مختلف اسناد Flutter API ظاهر می شود، مسدود می کند.
lib/src/web_view_stack.dart
را به صورت زیر به روز کنید:
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,
),
],
);
}
}
در مرحله بعد، یک آیتم منو اضافه می کنید تا با استفاده از کلاس WebViewController
، تست NavigationDelegate
خود را فعال کنید. به عنوان تمرینی برای خواننده باقی میماند تا منطق پاسخ به تماس را تقویت کند تا فقط ناوبری صفحه کامل به YouTube.com را مسدود کند و همچنان محتوای YouTube درونخط در اسناد API را مجاز کند.
8. افزودن دکمه منو به AppBar
در طی چند مرحله بعدی، یک دکمه منو در ویجت AppBar
ایجاد خواهید کرد که برای ارزیابی جاوا اسکریپت، فراخوانی کانال های جاوا اسکریپت و مدیریت کوکی ها استفاده می شود. در مجموع، منوی مفیدی است.
یک فایل منبع جدید در lib/src/menu.dart
ایجاد کنید و آن را با موارد زیر پر کنید:
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'),
),
],
);
}
}
هنگامی که کاربر گزینه منوی Navigate to YouTube را انتخاب می کند، روش loadRequest
WebViewController
اجرا می شود. این پیمایش توسط navigationDelegate
callback که در مرحله قبل ایجاد کردید مسدود خواهد شد.
برای افزودن منو به صفحه WebViewApp
، lib/main.dart
را به صورت زیر تغییر دهید:
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),
);
}
}
برنامه خود را اجرا کنید و روی آیتم منوی Navigate to YouTube ضربه بزنید. باید با SnackBar به شما سلام شود که به شما اطلاع میدهد که کنترلکننده ناوبری مسیریابی به YouTube را مسدود کرده است.
9. ارزیابی جاوا اسکریپت
WebViewController
می تواند عبارات جاوا اسکریپت را در زمینه صفحه فعلی ارزیابی کند. دو روش مختلف برای ارزیابی جاوا اسکریپت وجود دارد: برای کد جاوا اسکریپتی که مقداری را بر نمی گرداند، از runJavaScript
استفاده کنید و برای کد جاوا اسکریپتی که مقداری را برمی گرداند، از runJavaScriptReturningResult
استفاده کنید.
برای فعال کردن جاوا اسکریپت، باید WebViewController
را با ویژگی javaScriptMode
که روی JavascriptMode.unrestricted
تنظیم شده است، پیکربندی کنید. به طور پیش فرض، javascriptMode
روی JavascriptMode.disabled
تنظیم شده است.
کلاس _WebViewStackState
را با افزودن تنظیمات javascriptMode
به صورت زیر به روز کنید:
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,
),
],
);
}
}
اکنون که WebViewWidget
می تواند جاوا اسکریپت را اجرا کند، می توانید گزینه ای برای استفاده از روش runJavaScriptReturningResult
به منو اضافه کنید.
با استفاده از ویرایشگر یا برخی از کارهای صفحه کلید، کلاس Menu را به StatefulWidget تبدیل کنید. lib/src/menu.dart
را برای مطابقت با موارد زیر تغییر دهید:
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.
],
);
}
}
وقتی روی گزینه منوی «نمایش عامل کاربر» ضربه میزنید، نتیجه اجرای عبارت JavaScript navigator.userAgent
در یک Snackbar
نشان داده میشود. هنگام اجرای برنامه، ممکن است متوجه شوید که صفحه Flutter.dev متفاوت به نظر می رسد. این نتیجه اجرای با جاوا اسکریپت فعال است.
10. کار با کانال های جاوا اسکریپت
کانالهای جاوا اسکریپت برنامه شما را قادر میسازد تا کنترلکنندههای پاسخ به تماس را در زمینه جاوا اسکریپت WebViewWidget
ثبت کند که میتواند برای انتقال مقادیر به کد Dart برنامه استفاده شود. در این مرحله شما یک کانال SnackBar
را ثبت می کنید که با نتیجه XMLHttpRequest
فراخوانی می شود.
کلاس WebViewStack
را به صورت زیر به روز کنید:
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,
),
],
);
}
}
برای هر کانال جاوا اسکریپت در Set
، یک شی کانال در زمینه جاوا اسکریپت به عنوان یک ویژگی پنجره با نام name
کانال جاوا اسکریپت در دسترس است. استفاده از این مورد از زمینه جاوا اسکریپت شامل فراخوانی postMessage
در کانال جاوا اسکریپت برای ارسال پیامی است که به کنترل کننده پاسخ تماس onMessageReceived
در JavascriptChannel
ارسال می شود.
برای استفاده از کانال جاوا اسکریپت اضافه شده در بالا، آیتم منو دیگری اضافه کنید که یک XMLHttpRequest
را در زمینه جاوا اسکریپت اجرا می کند و نتایج را با استفاده از کانال جاوا اسکریپت SnackBar
پس می دهد.
اکنون که WebViewWidget
از کانالهای جاوا اسکریپت ما اطلاع دارد ,
یک مثال برای گسترش بیشتر برنامه اضافه میکنید. برای انجام این کار، یک PopupMenuItem
اضافی به کلاس Menu
اضافه کنید و عملکرد اضافی را اضافه کنید.
با افزودن مقدار javascriptChannel
enumeration، با گزینه منوی اضافی، _MenuOptions
را به روز کنید و پیاده سازی را به صورت زیر به کلاس Menu
اضافه کنید:
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.
],
);
}
}
این جاوا اسکریپت زمانی اجرا می شود که کاربر گزینه منوی JavaScript Channel Example را انتخاب کند.
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();
این کد یک درخواست GET
را به یک API آدرس IP عمومی ارسال می کند و آدرس IP دستگاه را برمی گرداند. این نتیجه در SnackBar
با فراخوانی postMessage
در JavascriptChannel
SnackBar
نشان داده می شود.
11. مدیریت کوکی ها
برنامه شما میتواند کوکیها را در WebView
با استفاده از کلاس CookieManager
مدیریت کند. در این مرحله میخواهید فهرستی از کوکیها را نشان دهید، فهرست کوکیها را پاک کنید، کوکیها را حذف کنید و کوکیهای جدیدی تنظیم کنید. برای هر یک از موارد استفاده از کوکی، ورودی های _MenuOptions
را به شرح زیر اضافه کنید:
lib/src/menu.dart
enum _MenuOptions {
navigationDelegate,
userAgent,
javascriptChannel,
// Add from here ...
listCookies,
clearCookies,
addCookie,
setCookie,
removeCookie,
// ... to here.
}
بقیه تغییرات در این مرحله بر روی کلاس Menu
متمرکز شده است، از جمله تبدیل کلاس Menu
از حالت بدون حالت به حالت حالت. این تغییر مهم است زیرا Menu
باید دارای CookieManager
باشد و حالت تغییرپذیر در ویجتهای بدون حالت ترکیب بدی است.
CookieManager را به صورت زیر به کلاس State حاصل اضافه کنید:
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) {
// ...
کلاس _MenuState
حاوی کدی است که قبلاً در کلاس Menu
اضافه شده است، همراه با CookieManager
که به تازگی اضافه شده است. در سری بعدی بخش ها، توابع کمکی را به _MenuState
اضافه می کنید که به نوبه خود توسط آیتم های منو که هنوز اضافه نشده اند فراخوانی می شوند.
لیستی از تمام کوکی ها را دریافت کنید
شما می خواهید از جاوا اسکریپت برای دریافت لیستی از تمام کوکی ها استفاده کنید. برای رسیدن به این هدف، یک متد کمکی به انتهای کلاس _MenuState
به نام _onListCookies
اضافه کنید. با استفاده از روش runJavaScriptReturningResult
، روش کمکی شما document.cookie
را در زمینه جاوا اسکریپت اجرا میکند و فهرستی از همه کوکیها را برمیگرداند.
موارد زیر را به کلاس _MenuState
اضافه کنید:
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.'),
),
);
}
تمام کوکی ها را پاک کنید
برای پاک کردن تمام کوکیها در WebView، از روش clearCookies
کلاس CookieManager
استفاده کنید. این روش Future<bool>
را برمیگرداند که اگر CookieManager
کوکیها را پاک کند، مقدار true
و اگر کوکیهایی برای پاک کردن وجود نداشته باشد false
.
موارد زیر را به کلاس _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.';
}
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(message),
),
);
}
یک کوکی اضافه کنید
افزودن کوکی را می توان با فراخوانی جاوا اسکریپت انجام داد. API مورد استفاده برای افزودن یک کوکی به یک سند جاوا اسکریپت به طور عمیق در MDN مستند شده است.
موارد زیر را به کلاس _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();''');
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Custom cookie added.'),
),
);
}
تنظیم یک کوکی با CookieManager
همچنین میتوان کوکیها را با استفاده از CookieManager به صورت زیر تنظیم کرد.
موارد زیر را به کلاس _MenuState
اضافه کنید:
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.'),
),
);
}
یک کوکی را حذف کنید
حذف یک کوکی شامل افزودن یک کوکی با تاریخ انقضا در گذشته است.
موارد زیر را به کلاس _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" ');
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Custom cookie removed.'),
),
);
}
افزودن موارد منوی CookieManager
تنها چیزی که باقی میماند این است که گزینههای منو را اضافه کنید و آنها را به روشهای کمکی که اخیراً اضافه کردهاید متصل کنید. کلاس _MenuState
را به صورت زیر به روز کنید:
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
برای استفاده از تمام قابلیت هایی که به تازگی به برنامه اضافه کرده اید، مراحل زیر را امتحان کنید:
- فهرست کوکی ها را انتخاب کنید. باید کوکی های Google Analytics تنظیم شده توسط flutter.dev را فهرست کند.
- پاک کردن کوکی ها را انتخاب کنید. باید گزارش دهد که کوکی ها واقعاً پاک شده اند.
- دوباره پاک کردن کوکی ها را انتخاب کنید. باید گزارش دهد که هیچ کوکی برای پاک کردن موجود نیست.
- فهرست کوکی ها را انتخاب کنید. باید گزارش دهد که هیچ کوکی وجود ندارد.
- افزودن کوکی را انتخاب کنید. باید کوکی را به عنوان اضافه گزارش کند.
- تنظیم کوکی را انتخاب کنید. باید کوکی را به عنوان تنظیم گزارش کند.
- لیست کوکی ها را انتخاب کنید و سپس به عنوان شکوفایی نهایی، حذف کوکی را انتخاب کنید.
12. دارایی های Flutter، فایل ها و رشته های HTML را در WebView بارگیری کنید
برنامه شما می تواند فایل های HTML را با استفاده از روش های مختلف بارگیری کند و آنها را در WebView نمایش دهد. در این مرحله شما یک دارایی Flutter مشخص شده در فایل pubspec.yaml
را بارگیری می کنید، یک فایل واقع در مسیر مشخص شده را بارگیری می کنید و یک صفحه را با استفاده از یک رشته HTML بارگذاری می کنید.
اگر می خواهید فایلی را که در یک مسیر مشخص قرار دارد بارگیری کنید، باید path_provider
به pubspec.yaml
اضافه کنید. این یک پلاگین Flutter برای یافتن مکان های رایج در سیستم فایل است.
در خط فرمان، دستور زیر را اجرا کنید:
$ flutter pub add path_provider
برای بارگیری دارایی باید مسیر دارایی را در pubspec.yaml
مشخص کنیم. در pubspec.yaml
خطوط زیر را اضافه کنید:
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.
برای افزودن دارایی ها به پروژه خود، مراحل زیر را انجام دهید:
- یک فهرست جدید با نام
assets
در پوشه اصلی پروژه خود ایجاد کنید. - یک دایرکتوری جدید با نام
www
در پوشهassets
ایجاد کنید. - یک دایرکتوری جدید با
styles
نام در پوشهwww
ایجاد کنید. - یک فایل جدید با نام
index.html
در پوشهwww
ایجاد کنید. - یک فایل جدید با نام
style.css
در پوشهstyles
ایجاد کنید.
کد زیر را در فایل 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>
برای style.css از چند خط زیر برای تنظیم سبک هدر HTML استفاده کنید:
h1 {
color: blue;
}
اکنون که داراییها تنظیم شده و آماده استفاده هستند، میتوانید روشهایی را که برای بارگیری و نمایش داراییهای Flutter، فایلها یا رشتههای HTML مورد نیاز است، پیادهسازی کنید.
بارگذاری دارایی فلاتر
برای بارگذاری دارایی ای که به تازگی ایجاد کرده اید، تنها کاری که باید انجام دهید این است که با استفاده از WebViewController
، متد loadFlutterAsset
فراخوانی کنید و به عنوان پارامتر مسیر دارایی را ارائه دهید. روش زیر را در انتهای کد خود اضافه کنید:
lib/src/menu.dart
Future<void> _onLoadFlutterAssetExample(
WebViewController controller, BuildContext context) async {
await controller.loadFlutterAsset('assets/www/index.html');
}
فایل محلی را بارگیری کنید
برای بارگذاری یک فایل در دستگاه خود، می توانید روشی را اضافه کنید که از روش loadFile
استفاده می کند، دوباره با استفاده از WebViewController
که String
حاوی مسیر فایل را می گیرد.
ابتدا باید یک فایل حاوی کد HTML بسازید. شما به سادگی می توانید این کار را با افزودن کد HTML به عنوان یک رشته در بالای کد خود در فایل 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.
برای ایجاد یک File
و نوشتن رشته HTML در فایل، دو روش اضافه می کنید. _onLoadLocalFileExample
با ارائه مسیری به عنوان رشته ای که توسط متد _prepareLocalFile()
برگردانده می شود، فایل را بارگیری می کند. روش های زیر را به کد خود اضافه کنید:
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 را بارگیری کنید
نمایش یک صفحه با ارائه یک رشته HTML بسیار ساده است. WebViewController
روشی دارد که می توانید از آن به نام loadHtmlString
استفاده کنید که در آن می توانید رشته HTML را به عنوان آرگومان ارائه دهید. سپس WebView
صفحه HTML ارائه شده را نمایش می دهد. روش زیر را به کد خود اضافه کنید:
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.
موارد منو را اضافه کنید
اکنون که دارایی ها تنظیم شده و آماده استفاده هستند و روش ها با تمام قابلیت ها ساخته شده اند، می توان منو را به روز کرد. ورودی های زیر را به فهرست _MenuOptions
اضافه کنید:
lib/src/menu.dart
enum _MenuOptions {
navigationDelegate,
userAgent,
javascriptChannel,
listCookies,
clearCookies,
addCookie,
setCookie,
removeCookie,
// Add from here ...
loadFlutterAsset,
loadLocalFile,
loadHtmlString,
// ... to here.
}
اکنون که enum بهروزرسانی شده است، میتوانید گزینههای منو را اضافه کنید و آنها را به روشهای کمکی که اخیراً اضافه کردهاید متصل کنید. کلاس _MenuState
را به صورت زیر به روز کنید:
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.
],
);
}
تست دارایی ها، فایل ها و رشته های HTML
برای آزمایش اینکه آیا کدی که به تازگی پیادهسازی کردهاید کار میکند، میتوانید کد را روی دستگاه خود اجرا کنید و روی یکی از آیتمهای منو که به تازگی اضافه شده است کلیک کنید. توجه کنید که چگونه _onLoadFlutterAssetExample
از style.css
که اضافه کردیم برای تغییر هدر فایل HTML به رنگ آبی استفاده می کند.
13. همه چیز تمام شد!
تبریک میگم!!! شما آزمایشگاه کد را تکمیل کرده اید. شما می توانید کد تکمیل شده برای این کد لبه را در مخزن کد لبه پیدا کنید.
برای کسب اطلاعات بیشتر، سایر کدهای Flutter را امتحان کنید.