7
7
import 'dart:async' ;
8
8
import 'dart:convert' ;
9
9
import 'dart:io' ;
10
- import 'dart:typed_data' ;
11
10
11
+ import 'package:flutter/foundation.dart' ;
12
12
import 'package:flutter/material.dart' ;
13
13
import 'package:path_provider/path_provider.dart' ;
14
14
import 'package:webview_flutter/webview_flutter.dart' ;
@@ -104,6 +104,39 @@ const String kLogExamplePage = '''
104
104
</html>
105
105
''' ;
106
106
107
+ const String kAlertTestPage = '''
108
+ <!DOCTYPE html>
109
+ <html>
110
+ <head>
111
+ <script type = "text/javascript">
112
+ function showAlert(text) {
113
+ console.log('showAlert(' + text + ')' )
114
+ alert(text);
115
+ }
116
+
117
+ function showConfirm(text) {
118
+ var result = confirm(text);
119
+ alert(result);
120
+ }
121
+
122
+ function showPrompt(text, defaultText) {
123
+ var inputString = prompt('Enter input', 'Default text');
124
+ alert(inputString);
125
+ }
126
+ </script>
127
+ </head>
128
+
129
+ <body>
130
+ <p> Click the following button to see the effect </p>
131
+ <form>
132
+ <input type = "button" value = "Alert" onclick = "showAlert('Test Alert');" />
133
+ <input type = "button" value = "Confirm" onclick = "showConfirm('Test Confirm');" />
134
+ <input type = "button" value = "Prompt" onclick = "showPrompt('Test Prompt', 'Default Value');" />
135
+ </form>
136
+ </body>
137
+ </html>
138
+ ''' ;
139
+
107
140
class WebViewExample extends StatefulWidget {
108
141
const WebViewExample ({super .key});
109
142
@@ -112,13 +145,21 @@ class WebViewExample extends StatefulWidget {
112
145
}
113
146
114
147
class _WebViewExampleState extends State <WebViewExample > {
115
- final WebViewController _controller = WebViewController () ;
148
+ late final WebViewController _controller;
116
149
117
150
@override
118
151
void initState () {
119
152
super .initState ();
120
153
121
- _controller
154
+ // #docregion platform_features
155
+ late final PlatformWebViewControllerCreationParams params;
156
+ params = const PlatformWebViewControllerCreationParams ();
157
+
158
+ final WebViewController controller =
159
+ WebViewController .fromPlatformCreationParams (params);
160
+ // #enddocregion platform_features
161
+
162
+ controller
122
163
..setJavaScriptMode (JavaScriptMode .unrestricted)
123
164
..setBackgroundColor (const Color (0x00000000 ))
124
165
..setNavigationDelegate (
@@ -149,9 +190,17 @@ Page resource error:
149
190
debugPrint ('allowing navigation to ${request .url }' );
150
191
return NavigationDecision .navigate;
151
192
},
193
+ // Note: onHttpError is not implemented by TizenWebview.
194
+ // onHttpError: (HttpResponseError error) {
195
+ // debugPrint('Error occurred on page: ${error.response?.statusCode}');
196
+ // },
152
197
onUrlChange: (UrlChange change) {
153
198
debugPrint ('url change to ${change .url }' );
154
199
},
200
+ // Note: onHttpAuthRequest is not implemented by TizenWebview.
201
+ // onHttpAuthRequest: (HttpAuthRequest request) {
202
+ // openDialog(request);
203
+ // },
155
204
),
156
205
)
157
206
..addJavaScriptChannel (
@@ -163,6 +212,13 @@ Page resource error:
163
212
},
164
213
)
165
214
..loadRequest (Uri .parse ('https://flutter.dev' ));
215
+
216
+ // setBackgroundColor is not currently supported on macOS.
217
+ if (kIsWeb || ! Platform .isMacOS) {
218
+ controller.setBackgroundColor (const Color (0x80000000 ));
219
+ }
220
+
221
+ _controller = controller;
166
222
}
167
223
168
224
@override
@@ -195,6 +251,62 @@ Page resource error:
195
251
child: const Icon (Icons .favorite),
196
252
);
197
253
}
254
+
255
+ Future <void > openDialog (HttpAuthRequest httpRequest) async {
256
+ final TextEditingController usernameTextController =
257
+ TextEditingController ();
258
+ final TextEditingController passwordTextController =
259
+ TextEditingController ();
260
+
261
+ return showDialog (
262
+ context: context,
263
+ barrierDismissible: false ,
264
+ builder: (BuildContext context) {
265
+ return AlertDialog (
266
+ title: Text ('${httpRequest .host }: ${httpRequest .realm ?? '-' }' ),
267
+ content: SingleChildScrollView (
268
+ child: Column (
269
+ mainAxisSize: MainAxisSize .min,
270
+ children: < Widget > [
271
+ TextField (
272
+ decoration: const InputDecoration (labelText: 'Username' ),
273
+ autofocus: true ,
274
+ controller: usernameTextController,
275
+ ),
276
+ TextField (
277
+ decoration: const InputDecoration (labelText: 'Password' ),
278
+ controller: passwordTextController,
279
+ ),
280
+ ],
281
+ ),
282
+ ),
283
+ actions: < Widget > [
284
+ // Explicitly cancel the request on iOS as the OS does not emit new
285
+ // requests when a previous request is pending.
286
+ TextButton (
287
+ onPressed: () {
288
+ httpRequest.onCancel ();
289
+ Navigator .of (context).pop ();
290
+ },
291
+ child: const Text ('Cancel' ),
292
+ ),
293
+ TextButton (
294
+ onPressed: () {
295
+ httpRequest.onProceed (
296
+ WebViewCredential (
297
+ user: usernameTextController.text,
298
+ password: passwordTextController.text,
299
+ ),
300
+ );
301
+ Navigator .of (context).pop ();
302
+ },
303
+ child: const Text ('Authenticate' ),
304
+ ),
305
+ ],
306
+ );
307
+ },
308
+ );
309
+ }
198
310
}
199
311
200
312
enum MenuOptions {
@@ -212,6 +324,8 @@ enum MenuOptions {
212
324
transparentBackground,
213
325
setCookie,
214
326
logExample,
327
+ basicAuthentication,
328
+ javaScriptAlert,
215
329
}
216
330
217
331
class SampleMenu extends StatelessWidget {
@@ -257,6 +371,10 @@ class SampleMenu extends StatelessWidget {
257
371
_onSetCookie ();
258
372
case MenuOptions .logExample:
259
373
_onLogExample ();
374
+ case MenuOptions .basicAuthentication:
375
+ _promptForUrl (context);
376
+ case MenuOptions .javaScriptAlert:
377
+ _onJavaScriptAlertExample (context);
260
378
}
261
379
},
262
380
itemBuilder: (BuildContext context) => < PopupMenuItem <MenuOptions >> [
@@ -317,6 +435,14 @@ class SampleMenu extends StatelessWidget {
317
435
value: MenuOptions .logExample,
318
436
child: Text ('Log example' ),
319
437
),
438
+ const PopupMenuItem <MenuOptions >(
439
+ value: MenuOptions .basicAuthentication,
440
+ child: Text ('Basic Authentication Example' ),
441
+ ),
442
+ const PopupMenuItem <MenuOptions >(
443
+ value: MenuOptions .javaScriptAlert,
444
+ child: Text ('JavaScript Alert Example' ),
445
+ ),
320
446
],
321
447
);
322
448
}
@@ -437,6 +563,28 @@ class SampleMenu extends StatelessWidget {
437
563
return webViewController.loadHtmlString (kTransparentBackgroundPage);
438
564
}
439
565
566
+ Future <void > _onJavaScriptAlertExample (BuildContext context) {
567
+ webViewController.setOnJavaScriptAlertDialog (
568
+ (JavaScriptAlertDialogRequest request) async {
569
+ await _showAlert (context, request.message);
570
+ });
571
+
572
+ webViewController.setOnJavaScriptConfirmDialog (
573
+ (JavaScriptConfirmDialogRequest request) async {
574
+ final bool result = await _showConfirm (context, request.message);
575
+ return result;
576
+ });
577
+
578
+ webViewController.setOnJavaScriptTextInputDialog (
579
+ (JavaScriptTextInputDialogRequest request) async {
580
+ final String result =
581
+ await _showTextInput (context, request.message, request.defaultText);
582
+ return result;
583
+ });
584
+
585
+ return webViewController.loadHtmlString (kAlertTestPage);
586
+ }
587
+
440
588
Widget _getCookieList (String cookies) {
441
589
if (cookies == '""' ) {
442
590
return Container ();
@@ -471,6 +619,97 @@ class SampleMenu extends StatelessWidget {
471
619
472
620
return webViewController.loadHtmlString (kLogExamplePage);
473
621
}
622
+
623
+ Future <void > _promptForUrl (BuildContext context) {
624
+ final TextEditingController urlTextController = TextEditingController ();
625
+
626
+ return showDialog <String >(
627
+ context: context,
628
+ builder: (BuildContext context) {
629
+ return AlertDialog (
630
+ title: const Text ('Input URL to visit' ),
631
+ content: TextField (
632
+ decoration: const InputDecoration (labelText: 'URL' ),
633
+ autofocus: true ,
634
+ controller: urlTextController,
635
+ ),
636
+ actions: < Widget > [
637
+ TextButton (
638
+ onPressed: () {
639
+ if (urlTextController.text.isNotEmpty) {
640
+ final Uri ? uri = Uri .tryParse (urlTextController.text);
641
+ if (uri != null && uri.scheme.isNotEmpty) {
642
+ webViewController.loadRequest (uri);
643
+ Navigator .pop (context);
644
+ }
645
+ }
646
+ },
647
+ child: const Text ('Visit' ),
648
+ ),
649
+ ],
650
+ );
651
+ },
652
+ );
653
+ }
654
+
655
+ Future <void > _showAlert (BuildContext context, String message) async {
656
+ return showDialog <void >(
657
+ context: context,
658
+ builder: (BuildContext ctx) {
659
+ return AlertDialog (
660
+ content: Text (message),
661
+ actions: < Widget > [
662
+ TextButton (
663
+ onPressed: () {
664
+ Navigator .of (ctx).pop ();
665
+ },
666
+ child: const Text ('OK' ))
667
+ ],
668
+ );
669
+ });
670
+ }
671
+
672
+ Future <bool > _showConfirm (BuildContext context, String message) async {
673
+ return await showDialog <bool >(
674
+ context: context,
675
+ builder: (BuildContext ctx) {
676
+ return AlertDialog (
677
+ content: Text (message),
678
+ actions: < Widget > [
679
+ TextButton (
680
+ onPressed: () {
681
+ Navigator .of (ctx).pop (false );
682
+ },
683
+ child: const Text ('Cancel' )),
684
+ TextButton (
685
+ onPressed: () {
686
+ Navigator .of (ctx).pop (true );
687
+ },
688
+ child: const Text ('OK' )),
689
+ ],
690
+ );
691
+ }) ??
692
+ false ;
693
+ }
694
+
695
+ Future <String > _showTextInput (
696
+ BuildContext context, String message, String ? defaultText) async {
697
+ return await showDialog <String >(
698
+ context: context,
699
+ builder: (BuildContext ctx) {
700
+ return AlertDialog (
701
+ content: Text (message),
702
+ actions: < Widget > [
703
+ TextButton (
704
+ onPressed: () {
705
+ Navigator .of (ctx).pop ('Text test' );
706
+ },
707
+ child: const Text ('Enter' )),
708
+ ],
709
+ );
710
+ }) ??
711
+ '' ;
712
+ }
474
713
}
475
714
476
715
class NavigationControls extends StatelessWidget {
0 commit comments