From 1736cec5c5d3a6fcf65f15c732af23c2af957fc1 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Tue, 6 Apr 2021 11:05:13 -0700 Subject: [PATCH 1/9] draft --- .../webview_flutter_test.dart | 2519 +++++++++-------- .../ios/Classes/FlutterWebView.m | 15 +- 2 files changed, 1306 insertions(+), 1228 deletions(-) diff --git a/packages/webview_flutter/example/integration_test/webview_flutter_test.dart b/packages/webview_flutter/example/integration_test/webview_flutter_test.dart index 2c7c765f34bf..b41a123e6d42 100644 --- a/packages/webview_flutter/example/integration_test/webview_flutter_test.dart +++ b/packages/webview_flutter/example/integration_test/webview_flutter_test.dart @@ -20,316 +20,316 @@ import 'package:integration_test/integration_test.dart'; void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); - testWidgets('initalUrl', (WidgetTester tester) async { - final Completer controllerCompleter = - Completer(); - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: GlobalKey(), - initialUrl: 'https://flutter.dev/', - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - ), - ), - ); - final WebViewController controller = await controllerCompleter.future; - final String currentUrl = await controller.currentUrl(); - expect(currentUrl, 'https://flutter.dev/'); - }); - - testWidgets('loadUrl', (WidgetTester tester) async { - final Completer controllerCompleter = - Completer(); - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: GlobalKey(), - initialUrl: 'https://flutter.dev/', - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - ), - ), - ); - final WebViewController controller = await controllerCompleter.future; - await controller.loadUrl('https://www.google.com/'); - final String currentUrl = await controller.currentUrl(); - expect(currentUrl, 'https://www.google.com/'); - }); - - // enable this once https://github.com/flutter/flutter/issues/31510 - // is resolved. - testWidgets('loadUrl with headers', (WidgetTester tester) async { - final Completer controllerCompleter = - Completer(); - final StreamController pageStarts = StreamController(); - final StreamController pageLoads = StreamController(); - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: GlobalKey(), - initialUrl: 'https://flutter.dev/', - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - javascriptMode: JavascriptMode.unrestricted, - onPageStarted: (String url) { - pageStarts.add(url); - }, - onPageFinished: (String url) { - pageLoads.add(url); - }, - ), - ), - ); - final WebViewController controller = await controllerCompleter.future; - final Map headers = { - 'test_header': 'flutter_test_header' - }; - await controller.loadUrl('https://flutter-header-echo.herokuapp.com/', - headers: headers); - final String currentUrl = await controller.currentUrl(); - expect(currentUrl, 'https://flutter-header-echo.herokuapp.com/'); - - await pageStarts.stream.firstWhere((String url) => url == currentUrl); - await pageLoads.stream.firstWhere((String url) => url == currentUrl); - - final String content = await controller - .evaluateJavascript('document.documentElement.innerText'); - expect(content.contains('flutter_test_header'), isTrue); - }); - - testWidgets('JavaScriptChannel', (WidgetTester tester) async { - final Completer controllerCompleter = - Completer(); - final Completer pageStarted = Completer(); - final Completer pageLoaded = Completer(); - final List messagesReceived = []; - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: GlobalKey(), - // This is the data URL for: '' - initialUrl: - 'data:text/html;charset=utf-8;base64,PCFET0NUWVBFIGh0bWw+', - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - javascriptMode: JavascriptMode.unrestricted, - javascriptChannels: { - JavascriptChannel( - name: 'Echo', - onMessageReceived: (JavascriptMessage message) { - messagesReceived.add(message.message); - }, - ), - }, - onPageStarted: (String url) { - pageStarted.complete(null); - }, - onPageFinished: (String url) { - pageLoaded.complete(null); - }, - ), - ), - ); - final WebViewController controller = await controllerCompleter.future; - await pageStarted.future; - await pageLoaded.future; - - expect(messagesReceived, isEmpty); - // Append a return value "1" in the end will prevent an iOS platform exception. - // See: https://github.com/flutter/flutter/issues/66318#issuecomment-701105380 - // TODO(cyanglaz): remove the workaround "1" in the end when the below issue is fixed. - // https://github.com/flutter/flutter/issues/66318 - await controller.evaluateJavascript('Echo.postMessage("hello");1;'); - expect(messagesReceived, equals(['hello'])); - }); - - testWidgets('resize webview', (WidgetTester tester) async { - final String resizeTest = ''' - - Resize test - - - - - - '''; - final String resizeTestBase64 = - base64Encode(const Utf8Encoder().convert(resizeTest)); - final Completer resizeCompleter = Completer(); - final Completer pageStarted = Completer(); - final Completer pageLoaded = Completer(); - final Completer controllerCompleter = - Completer(); - final GlobalKey key = GlobalKey(); - - final WebView webView = WebView( - key: key, - initialUrl: 'data:text/html;charset=utf-8;base64,$resizeTestBase64', - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - javascriptChannels: { - JavascriptChannel( - name: 'Resize', - onMessageReceived: (JavascriptMessage message) { - resizeCompleter.complete(true); - }, - ), - }, - onPageStarted: (String url) { - pageStarted.complete(null); - }, - onPageFinished: (String url) { - pageLoaded.complete(null); - }, - javascriptMode: JavascriptMode.unrestricted, - ); - - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: Column( - children: [ - SizedBox( - width: 200, - height: 200, - child: webView, - ), - ], - ), - ), - ); - - await controllerCompleter.future; - await pageStarted.future; - await pageLoaded.future; - - expect(resizeCompleter.isCompleted, false); - - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: Column( - children: [ - SizedBox( - width: 400, - height: 400, - child: webView, - ), - ], - ), - ), - ); - - await resizeCompleter.future; - }); - - testWidgets('set custom userAgent', (WidgetTester tester) async { - final Completer controllerCompleter1 = - Completer(); - final GlobalKey _globalKey = GlobalKey(); - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: _globalKey, - initialUrl: 'about:blank', - javascriptMode: JavascriptMode.unrestricted, - userAgent: 'Custom_User_Agent1', - onWebViewCreated: (WebViewController controller) { - controllerCompleter1.complete(controller); - }, - ), - ), - ); - final WebViewController controller1 = await controllerCompleter1.future; - final String customUserAgent1 = await _getUserAgent(controller1); - expect(customUserAgent1, 'Custom_User_Agent1'); - // rebuild the WebView with a different user agent. - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: _globalKey, - initialUrl: 'about:blank', - javascriptMode: JavascriptMode.unrestricted, - userAgent: 'Custom_User_Agent2', - ), - ), - ); - - final String customUserAgent2 = await _getUserAgent(controller1); - expect(customUserAgent2, 'Custom_User_Agent2'); - }); - - testWidgets('use default platform userAgent after webView is rebuilt', - (WidgetTester tester) async { - final Completer controllerCompleter = - Completer(); - final GlobalKey _globalKey = GlobalKey(); - // Build the webView with no user agent to get the default platform user agent. - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: _globalKey, - initialUrl: 'https://flutter.dev/', - javascriptMode: JavascriptMode.unrestricted, - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - ), - ), - ); - final WebViewController controller = await controllerCompleter.future; - final String defaultPlatformUserAgent = await _getUserAgent(controller); - // rebuild the WebView with a custom user agent. - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: _globalKey, - initialUrl: 'about:blank', - javascriptMode: JavascriptMode.unrestricted, - userAgent: 'Custom_User_Agent', - ), - ), - ); - final String customUserAgent = await _getUserAgent(controller); - expect(customUserAgent, 'Custom_User_Agent'); - // rebuilds the WebView with no user agent. - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: _globalKey, - initialUrl: 'about:blank', - javascriptMode: JavascriptMode.unrestricted, - ), - ), - ); - - final String customUserAgent2 = await _getUserAgent(controller); - expect(customUserAgent2, defaultPlatformUserAgent); - }); - - group('Video playback policy', () { + // testWidgets('initalUrl', (WidgetTester tester) async { + // final Completer controllerCompleter = + // Completer(); + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: GlobalKey(), + // initialUrl: 'https://flutter.dev/', + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // ), + // ), + // ); + // final WebViewController controller = await controllerCompleter.future; + // final String currentUrl = await controller.currentUrl(); + // expect(currentUrl, 'https://flutter.dev/'); + // }); + + // testWidgets('loadUrl', (WidgetTester tester) async { + // final Completer controllerCompleter = + // Completer(); + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: GlobalKey(), + // initialUrl: 'https://flutter.dev/', + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // ), + // ), + // ); + // final WebViewController controller = await controllerCompleter.future; + // await controller.loadUrl('https://www.google.com/'); + // final String currentUrl = await controller.currentUrl(); + // expect(currentUrl, 'https://www.google.com/'); + // }); + + // // enable this once https://github.com/flutter/flutter/issues/31510 + // // is resolved. + // testWidgets('loadUrl with headers', (WidgetTester tester) async { + // final Completer controllerCompleter = + // Completer(); + // final StreamController pageStarts = StreamController(); + // final StreamController pageLoads = StreamController(); + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: GlobalKey(), + // initialUrl: 'https://flutter.dev/', + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // javascriptMode: JavascriptMode.unrestricted, + // onPageStarted: (String url) { + // pageStarts.add(url); + // }, + // onPageFinished: (String url) { + // pageLoads.add(url); + // }, + // ), + // ), + // ); + // final WebViewController controller = await controllerCompleter.future; + // final Map headers = { + // 'test_header': 'flutter_test_header' + // }; + // await controller.loadUrl('https://flutter-header-echo.herokuapp.com/', + // headers: headers); + // final String currentUrl = await controller.currentUrl(); + // expect(currentUrl, 'https://flutter-header-echo.herokuapp.com/'); + + // await pageStarts.stream.firstWhere((String url) => url == currentUrl); + // await pageLoads.stream.firstWhere((String url) => url == currentUrl); + + // final String content = await controller + // .evaluateJavascript('document.documentElement.innerText'); + // expect(content.contains('flutter_test_header'), isTrue); + // }); + + // testWidgets('JavaScriptChannel', (WidgetTester tester) async { + // final Completer controllerCompleter = + // Completer(); + // final Completer pageStarted = Completer(); + // final Completer pageLoaded = Completer(); + // final List messagesReceived = []; + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: GlobalKey(), + // // This is the data URL for: '' + // initialUrl: + // 'data:text/html;charset=utf-8;base64,PCFET0NUWVBFIGh0bWw+', + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // javascriptMode: JavascriptMode.unrestricted, + // javascriptChannels: { + // JavascriptChannel( + // name: 'Echo', + // onMessageReceived: (JavascriptMessage message) { + // messagesReceived.add(message.message); + // }, + // ), + // }, + // onPageStarted: (String url) { + // pageStarted.complete(null); + // }, + // onPageFinished: (String url) { + // pageLoaded.complete(null); + // }, + // ), + // ), + // ); + // final WebViewController controller = await controllerCompleter.future; + // await pageStarted.future; + // await pageLoaded.future; + + // expect(messagesReceived, isEmpty); + // // Append a return value "1" in the end will prevent an iOS platform exception. + // // See: https://github.com/flutter/flutter/issues/66318#issuecomment-701105380 + // // TODO(cyanglaz): remove the workaround "1" in the end when the below issue is fixed. + // // https://github.com/flutter/flutter/issues/66318 + // await controller.evaluateJavascript('Echo.postMessage("hello");1;'); + // expect(messagesReceived, equals(['hello'])); + // }); + + // testWidgets('resize webview', (WidgetTester tester) async { + // final String resizeTest = ''' + // + // Resize test + // + // + // + // + // + // '''; + // final String resizeTestBase64 = + // base64Encode(const Utf8Encoder().convert(resizeTest)); + // final Completer resizeCompleter = Completer(); + // final Completer pageStarted = Completer(); + // final Completer pageLoaded = Completer(); + // final Completer controllerCompleter = + // Completer(); + // final GlobalKey key = GlobalKey(); + + // final WebView webView = WebView( + // key: key, + // initialUrl: 'data:text/html;charset=utf-8;base64,$resizeTestBase64', + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // javascriptChannels: { + // JavascriptChannel( + // name: 'Resize', + // onMessageReceived: (JavascriptMessage message) { + // resizeCompleter.complete(true); + // }, + // ), + // }, + // onPageStarted: (String url) { + // pageStarted.complete(null); + // }, + // onPageFinished: (String url) { + // pageLoaded.complete(null); + // }, + // javascriptMode: JavascriptMode.unrestricted, + // ); + + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: Column( + // children: [ + // SizedBox( + // width: 200, + // height: 200, + // child: webView, + // ), + // ], + // ), + // ), + // ); + + // await controllerCompleter.future; + // await pageStarted.future; + // await pageLoaded.future; + + // expect(resizeCompleter.isCompleted, false); + + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: Column( + // children: [ + // SizedBox( + // width: 400, + // height: 400, + // child: webView, + // ), + // ], + // ), + // ), + // ); + + // await resizeCompleter.future; + // }); + + // testWidgets('set custom userAgent', (WidgetTester tester) async { + // final Completer controllerCompleter1 = + // Completer(); + // final GlobalKey _globalKey = GlobalKey(); + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: _globalKey, + // initialUrl: 'about:blank', + // javascriptMode: JavascriptMode.unrestricted, + // userAgent: 'Custom_User_Agent1', + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter1.complete(controller); + // }, + // ), + // ), + // ); + // final WebViewController controller1 = await controllerCompleter1.future; + // final String customUserAgent1 = await _getUserAgent(controller1); + // expect(customUserAgent1, 'Custom_User_Agent1'); + // // rebuild the WebView with a different user agent. + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: _globalKey, + // initialUrl: 'about:blank', + // javascriptMode: JavascriptMode.unrestricted, + // userAgent: 'Custom_User_Agent2', + // ), + // ), + // ); + + // final String customUserAgent2 = await _getUserAgent(controller1); + // expect(customUserAgent2, 'Custom_User_Agent2'); + // }); + + // testWidgets('use default platform userAgent after webView is rebuilt', + // (WidgetTester tester) async { + // final Completer controllerCompleter = + // Completer(); + // final GlobalKey _globalKey = GlobalKey(); + // // Build the webView with no user agent to get the default platform user agent. + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: _globalKey, + // initialUrl: 'https://flutter.dev/', + // javascriptMode: JavascriptMode.unrestricted, + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // ), + // ), + // ); + // final WebViewController controller = await controllerCompleter.future; + // final String defaultPlatformUserAgent = await _getUserAgent(controller); + // // rebuild the WebView with a custom user agent. + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: _globalKey, + // initialUrl: 'about:blank', + // javascriptMode: JavascriptMode.unrestricted, + // userAgent: 'Custom_User_Agent', + // ), + // ), + // ); + // final String customUserAgent = await _getUserAgent(controller); + // expect(customUserAgent, 'Custom_User_Agent'); + // // rebuilds the WebView with no user agent. + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: _globalKey, + // initialUrl: 'about:blank', + // javascriptMode: JavascriptMode.unrestricted, + // ), + // ), + // ); + + // final String customUserAgent2 = await _getUserAgent(controller); + // expect(customUserAgent2, defaultPlatformUserAgent); + // }); + + // group('Video playback policy', () { String videoTestBase64; setUpAll(() async { final ByteData videoData = @@ -343,6 +343,27 @@ void main() { function play() { var video = document.getElementById("video"); video.play(); + video.addEventListener('play', videoPausePlayHandler, false); + video.addEventListener('pause', videoPausePlayHandler, false); + video.addEventListener('durationchange', videoPausePlayHandler, false); + video.addEventListener('loadeddata', videoPausePlayHandler, false); + video.addEventListener('timeupdate', videoPausePlayHandler, false); + video.addEventListener('loadstart', videoPausePlayHandler, false); + video.addEventListener('canplay', videoPausePlayHandler, false); + } + function videoPausePlayHandler(e) { + VideoTest.postMessage(e.type); + // if (e.type == 'play') { + // VideoTest.postMessage("play"); + // } else if (e.type == 'pause') { + // VideoTest.postMessage("pause"); + // } else if (e.type == 'durationchange') { + // VideoTest.postMessage("durationchange"); + // } else if (e.type == 'loadeddata') { + // VideoTest.postMessage("loadeddata"); + // } else if (e.type == 'timeupdate') { + // VideoTest.postMessage("timeupdate"); + // } } function isPaused() { var video = document.getElementById("video"); @@ -352,6 +373,10 @@ void main() { var video = document.getElementById("video"); return video.webkitDisplayingFullscreen; } + function currentTime() { + var video = document.getElementById("video"); + return video.duration; + } @@ -364,139 +389,180 @@ void main() { videoTestBase64 = base64Encode(const Utf8Encoder().convert(videoTest)); }); - testWidgets('Auto media playback', (WidgetTester tester) async { - Completer controllerCompleter = - Completer(); - Completer pageLoaded = Completer(); - - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: GlobalKey(), - initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - javascriptMode: JavascriptMode.unrestricted, - onPageFinished: (String url) { - pageLoaded.complete(null); - }, - initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, - ), - ), - ); - WebViewController controller = await controllerCompleter.future; - await pageLoaded.future; - - String isPaused = await controller.evaluateJavascript('isPaused();'); - expect(isPaused, _webviewBool(false)); - - controllerCompleter = Completer(); - pageLoaded = Completer(); - - // We change the key to re-create a new webview as we change the initialMediaPlaybackPolicy - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: GlobalKey(), - initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - javascriptMode: JavascriptMode.unrestricted, - onPageFinished: (String url) { - pageLoaded.complete(null); - }, - initialMediaPlaybackPolicy: - AutoMediaPlaybackPolicy.require_user_action_for_all_media_types, - ), - ), - ); - - controller = await controllerCompleter.future; - await pageLoaded.future; - - isPaused = await controller.evaluateJavascript('isPaused();'); - expect(isPaused, _webviewBool(true)); - }, skip: true /* https://github.com/flutter/flutter/issues/72572 */); - - testWidgets('Changes to initialMediaPlaybackPolicy are ignored', - (WidgetTester tester) async { - final Completer controllerCompleter = - Completer(); - Completer pageLoaded = Completer(); - - final GlobalKey key = GlobalKey(); - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: key, - initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - javascriptMode: JavascriptMode.unrestricted, - onPageFinished: (String url) { - pageLoaded.complete(null); - }, - initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, - ), - ), - ); - final WebViewController controller = await controllerCompleter.future; - await pageLoaded.future; - - String isPaused = await controller.evaluateJavascript('isPaused();'); - expect(isPaused, _webviewBool(false)); - - pageLoaded = Completer(); - - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: key, - initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - javascriptMode: JavascriptMode.unrestricted, - onPageFinished: (String url) { - pageLoaded.complete(null); - }, - initialMediaPlaybackPolicy: - AutoMediaPlaybackPolicy.require_user_action_for_all_media_types, - ), - ), - ); - - await controller.reload(); - - await pageLoaded.future; - - isPaused = await controller.evaluateJavascript('isPaused();'); - expect(isPaused, _webviewBool(false)); - }, skip: true /* https://github.com/flutter/flutter/issues/72572 */); - - testWidgets('Video plays inline when allowsInlineMediaPlayback is true', + // testWidgets('Auto media playback', (WidgetTester tester) async { + // Completer controllerCompleter = + // Completer(); + // Completer pageLoaded = Completer(); + + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: GlobalKey(), + // initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // javascriptMode: JavascriptMode.unrestricted, + // onPageFinished: (String url) { + // pageLoaded.complete(null); + // }, + // initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, + // ), + // ), + // ); + // WebViewController controller = await controllerCompleter.future; + // await pageLoaded.future; + + // String isPaused = await controller.evaluateJavascript('isPaused();'); + // expect(isPaused, _webviewBool(false)); + + // controllerCompleter = Completer(); + // pageLoaded = Completer(); + + // // We change the key to re-create a new webview as we change the initialMediaPlaybackPolicy + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: GlobalKey(), + // initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // javascriptMode: JavascriptMode.unrestricted, + // onPageFinished: (String url) { + // pageLoaded.complete(null); + // }, + // initialMediaPlaybackPolicy: + // AutoMediaPlaybackPolicy.require_user_action_for_all_media_types, + // ), + // ), + // ); + + // controller = await controllerCompleter.future; + // await pageLoaded.future; + + // isPaused = await controller.evaluateJavascript('isPaused();'); + // expect(isPaused, _webviewBool(true)); + // }, skip: true /* https://github.com/flutter/flutter/issues/72572 */); + + // testWidgets('Changes to initialMediaPlaybackPolicy are ignored', + // (WidgetTester tester) async { + // final Completer controllerCompleter = + // Completer(); + // Completer pageLoaded = Completer(); + + // final GlobalKey key = GlobalKey(); + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: key, + // initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // javascriptMode: JavascriptMode.unrestricted, + // onPageFinished: (String url) { + // pageLoaded.complete(null); + // }, + // initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, + // ), + // ), + // ); + // final WebViewController controller = await controllerCompleter.future; + // await pageLoaded.future; + + // String isPaused = await controller.evaluateJavascript('isPaused();'); + // expect(isPaused, _webviewBool(false)); + + // pageLoaded = Completer(); + + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: key, + // initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // javascriptMode: JavascriptMode.unrestricted, + // onPageFinished: (String url) { + // pageLoaded.complete(null); + // }, + // initialMediaPlaybackPolicy: + // AutoMediaPlaybackPolicy.require_user_action_for_all_media_types, + // ), + // ), + // ); + + // await controller.reload(); + + // await pageLoaded.future; + + // isPaused = await controller.evaluateJavascript('isPaused();'); + // expect(isPaused, _webviewBool(false)); + // }, skip: true /* https://github.com/flutter/flutter/issues/72572 */); + + // testWidgets('Video plays inline when allowsInlineMediaPlayback is true', + // (WidgetTester tester) async { + // Completer controllerCompleter = + // Completer(); + // Completer pageLoaded = Completer(); + + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // javascriptMode: JavascriptMode.unrestricted, + // onPageFinished: (String url) { + // pageLoaded.complete(null); + // }, + // initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, + // allowsInlineMediaPlayback: true, + // ), + // ), + // ); + // WebViewController controller = await controllerCompleter.future; + // await pageLoaded.future; + + // String isFullScreen = + // await controller.evaluateJavascript('isFullScreen();'); + // expect(isFullScreen, _webviewBool(false)); + // }); + + testWidgets('Video plays full screen when allowsInlineMediaPlayback is false', (WidgetTester tester) async { Completer controllerCompleter = Completer(); Completer pageLoaded = Completer(); + String message1; + Completer messagesReceived = Completer(); await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: WebView( - key: GlobalKey(), initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', onWebViewCreated: (WebViewController controller) { controllerCompleter.complete(controller); }, javascriptMode: JavascriptMode.unrestricted, + javascriptChannels: { + JavascriptChannel( + name: 'VideoTest', + onMessageReceived: (JavascriptMessage message) { + print(message.message); + // message1 = message.message; + // messagesReceived.complete(message.message); + }, + ),}, onPageFinished: (String url) { pageLoaded.complete(null); }, @@ -507,828 +573,831 @@ void main() { ); WebViewController controller = await controllerCompleter.future; await pageLoaded.future; + // String message = await messagesReceived.future; + // print(message1); + + String duration = + await controller.evaluateJavascript('currentTime();'); + // print(duration); String isFullScreen = await controller.evaluateJavascript('isFullScreen();'); expect(isFullScreen, _webviewBool(false)); - controllerCompleter = Completer(); - pageLoaded = Completer(); - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: GlobalKey(), - initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - javascriptMode: JavascriptMode.unrestricted, - onPageFinished: (String url) { - pageLoaded.complete(null); - }, - initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, - allowsInlineMediaPlayback: false, - ), - ), - ); - - controller = await controllerCompleter.future; - await pageLoaded.future; - - isFullScreen = await controller.evaluateJavascript('isFullScreen();'); - expect(isFullScreen, _webviewBool(true)); - }, skip: true /* https://github.com/flutter/flutter/issues/72572 */); - }); - - group('Audio playback policy', () { - String audioTestBase64; - setUpAll(() async { - final ByteData audioData = - await rootBundle.load('assets/sample_audio.ogg'); - final String base64AudioData = - base64Encode(Uint8List.view(audioData.buffer)); - final String audioTest = ''' - - Audio auto play - - - - - - - '''; - audioTestBase64 = base64Encode(const Utf8Encoder().convert(audioTest)); - }); - - testWidgets('Auto media playback', (WidgetTester tester) async { - Completer controllerCompleter = + controllerCompleter = Completer(); - Completer pageStarted = Completer(); - Completer pageLoaded = Completer(); - - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: GlobalKey(), - initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64', - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - javascriptMode: JavascriptMode.unrestricted, - onPageStarted: (String url) { - pageStarted.complete(null); - }, - onPageFinished: (String url) { - pageLoaded.complete(null); - }, - initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, - ), - ), - ); - WebViewController controller = await controllerCompleter.future; - await pageStarted.future; - await pageLoaded.future; - - String isPaused = await controller.evaluateJavascript('isPaused();'); - expect(isPaused, _webviewBool(false)); - - controllerCompleter = Completer(); - pageStarted = Completer(); pageLoaded = Completer(); - // We change the key to re-create a new webview as we change the initialMediaPlaybackPolicy await tester.pumpWidget( Directionality( textDirection: TextDirection.ltr, child: WebView( - key: GlobalKey(), - initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64', - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - javascriptMode: JavascriptMode.unrestricted, - onPageStarted: (String url) { - pageStarted.complete(null); - }, - onPageFinished: (String url) { - pageLoaded.complete(null); - }, - initialMediaPlaybackPolicy: - AutoMediaPlaybackPolicy.require_user_action_for_all_media_types, - ), - ), - ); - - controller = await controllerCompleter.future; - await pageStarted.future; - await pageLoaded.future; - - isPaused = await controller.evaluateJavascript('isPaused();'); - expect(isPaused, _webviewBool(true)); - }, skip: true /* https://github.com/flutter/flutter/issues/72572 */); - - testWidgets('Changes to initialMediaPlaybackPolocy are ignored', - (WidgetTester tester) async { - final Completer controllerCompleter = - Completer(); - Completer pageStarted = Completer(); - Completer pageLoaded = Completer(); - - final GlobalKey key = GlobalKey(); - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: key, - initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64', + initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', onWebViewCreated: (WebViewController controller) { controllerCompleter.complete(controller); }, javascriptMode: JavascriptMode.unrestricted, - onPageStarted: (String url) { - pageStarted.complete(null); - }, onPageFinished: (String url) { pageLoaded.complete(null); }, initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, + allowsInlineMediaPlayback: true, ), ), ); - final WebViewController controller = await controllerCompleter.future; - await pageStarted.future; - await pageLoaded.future; - - String isPaused = await controller.evaluateJavascript('isPaused();'); - expect(isPaused, _webviewBool(false)); - - pageStarted = Completer(); - pageLoaded = Completer(); - - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: key, - initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64', - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - javascriptMode: JavascriptMode.unrestricted, - onPageStarted: (String url) { - pageStarted.complete(null); - }, - onPageFinished: (String url) { - pageLoaded.complete(null); - }, - initialMediaPlaybackPolicy: - AutoMediaPlaybackPolicy.require_user_action_for_all_media_types, - ), - ), - ); - - await controller.reload(); - - await pageStarted.future; - await pageLoaded.future; - - isPaused = await controller.evaluateJavascript('isPaused();'); - expect(isPaused, _webviewBool(false)); - }, skip: true /* https://github.com/flutter/flutter/issues/72572 */); - }); - - testWidgets('getTitle', (WidgetTester tester) async { - final String getTitleTest = ''' - - Some title - - - - - '''; - final String getTitleTestBase64 = - base64Encode(const Utf8Encoder().convert(getTitleTest)); - final Completer pageStarted = Completer(); - final Completer pageLoaded = Completer(); - final Completer controllerCompleter = - Completer(); - - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - initialUrl: 'data:text/html;charset=utf-8;base64,$getTitleTestBase64', - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - onPageStarted: (String url) { - pageStarted.complete(null); - }, - onPageFinished: (String url) { - pageLoaded.complete(null); - }, - ), - ), - ); - - final WebViewController controller = await controllerCompleter.future; - await pageStarted.future; - await pageLoaded.future; - - final String title = await controller.getTitle(); - expect(title, 'Some title'); - }); - - group('Programmatic Scroll', () { - testWidgets('setAndGetScrollPosition', (WidgetTester tester) async { - final String scrollTestPage = ''' - - - - - - -
- - - '''; - - final String scrollTestPageBase64 = - base64Encode(const Utf8Encoder().convert(scrollTestPage)); - - final Completer pageLoaded = Completer(); - final Completer controllerCompleter = - Completer(); - - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - initialUrl: - 'data:text/html;charset=utf-8;base64,$scrollTestPageBase64', - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - onPageFinished: (String url) { - pageLoaded.complete(null); - }, - ), - ), - ); - - final WebViewController controller = await controllerCompleter.future; + controller = await controllerCompleter.future; await pageLoaded.future; - - await tester.pumpAndSettle(Duration(seconds: 3)); - - // Check scrollTo() - const int X_SCROLL = 123; - const int Y_SCROLL = 321; - - await controller.scrollTo(X_SCROLL, Y_SCROLL); - int scrollPosX = await controller.getScrollX(); - int scrollPosY = await controller.getScrollY(); - expect(X_SCROLL, scrollPosX); - expect(Y_SCROLL, scrollPosY); - - // Check scrollBy() (on top of scrollTo()) - await controller.scrollBy(X_SCROLL, Y_SCROLL); - scrollPosX = await controller.getScrollX(); - scrollPosY = await controller.getScrollY(); - expect(X_SCROLL * 2, scrollPosX); - expect(Y_SCROLL * 2, scrollPosY); - }); - }); - - group('SurfaceAndroidWebView', () { - setUpAll(() { - WebView.platform = SurfaceAndroidWebView(); - }); - - tearDownAll(() { - WebView.platform = null; }); - - testWidgets('setAndGetScrollPosition', (WidgetTester tester) async { - final String scrollTestPage = ''' - - - - - - -
- - - '''; - - final String scrollTestPageBase64 = - base64Encode(const Utf8Encoder().convert(scrollTestPage)); - - final Completer pageLoaded = Completer(); - final Completer controllerCompleter = - Completer(); - - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - initialUrl: - 'data:text/html;charset=utf-8;base64,$scrollTestPageBase64', - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - onPageFinished: (String url) { - pageLoaded.complete(null); - }, - ), - ), - ); - - final WebViewController controller = await controllerCompleter.future; - await pageLoaded.future; - - await tester.pumpAndSettle(Duration(seconds: 3)); - - // Check scrollTo() - const int X_SCROLL = 123; - const int Y_SCROLL = 321; - - await controller.scrollTo(X_SCROLL, Y_SCROLL); - int scrollPosX = await controller.getScrollX(); - int scrollPosY = await controller.getScrollY(); - expect(X_SCROLL, scrollPosX); - expect(Y_SCROLL, scrollPosY); - - // Check scrollBy() (on top of scrollTo()) - await controller.scrollBy(X_SCROLL, Y_SCROLL); - scrollPosX = await controller.getScrollX(); - scrollPosY = await controller.getScrollY(); - expect(X_SCROLL * 2, scrollPosX); - expect(Y_SCROLL * 2, scrollPosY); - }, skip: !Platform.isAndroid); - - testWidgets('inputs are scrolled into view when focused', - (WidgetTester tester) async { - final String scrollTestPage = ''' - - - - - - -
- - - - '''; - - final String scrollTestPageBase64 = - base64Encode(const Utf8Encoder().convert(scrollTestPage)); - - final Completer pageLoaded = Completer(); - final Completer controllerCompleter = - Completer(); - - await tester.runAsync(() async { - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: SizedBox( - width: 200, - height: 200, - child: WebView( - initialUrl: - 'data:text/html;charset=utf-8;base64,$scrollTestPageBase64', - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - onPageFinished: (String url) { - pageLoaded.complete(null); - }, - javascriptMode: JavascriptMode.unrestricted, - ), - ), - ), - ); - await Future.delayed(Duration(milliseconds: 20)); - await tester.pump(); - }); - - final WebViewController controller = await controllerCompleter.future; - await pageLoaded.future; - final String viewportRectJSON = await _evaluateJavascript( - controller, 'JSON.stringify(viewport.getBoundingClientRect())'); - final Map viewportRectRelativeToViewport = - jsonDecode(viewportRectJSON); - - // Check that the input is originally outside of the viewport. - - final String initialInputClientRectJSON = await _evaluateJavascript( - controller, 'JSON.stringify(inputEl.getBoundingClientRect())'); - final Map initialInputClientRectRelativeToViewport = - jsonDecode(initialInputClientRectJSON); - - expect( - initialInputClientRectRelativeToViewport['bottom'] <= - viewportRectRelativeToViewport['bottom'], - isFalse); - - await controller.evaluateJavascript('inputEl.focus()'); - - // Check that focusing the input brought it into view. - - final String lastInputClientRectJSON = await _evaluateJavascript( - controller, 'JSON.stringify(inputEl.getBoundingClientRect())'); - final Map lastInputClientRectRelativeToViewport = - jsonDecode(lastInputClientRectJSON); - - expect( - lastInputClientRectRelativeToViewport['top'] >= - viewportRectRelativeToViewport['top'], - isTrue); - expect( - lastInputClientRectRelativeToViewport['bottom'] <= - viewportRectRelativeToViewport['bottom'], - isTrue); - - expect( - lastInputClientRectRelativeToViewport['left'] >= - viewportRectRelativeToViewport['left'], - isTrue); - expect( - lastInputClientRectRelativeToViewport['right'] <= - viewportRectRelativeToViewport['right'], - isTrue); - }, skip: !Platform.isAndroid); - }); - - group('NavigationDelegate', () { - final String blankPage = ""; - final String blankPageEncoded = 'data:text/html;charset=utf-8;base64,' + - base64Encode(const Utf8Encoder().convert(blankPage)); - - testWidgets('can allow requests', (WidgetTester tester) async { - final Completer controllerCompleter = - Completer(); - final StreamController pageLoads = - StreamController.broadcast(); - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: GlobalKey(), - initialUrl: blankPageEncoded, - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - javascriptMode: JavascriptMode.unrestricted, - navigationDelegate: (NavigationRequest request) { - return (request.url.contains('youtube.com')) - ? NavigationDecision.prevent - : NavigationDecision.navigate; - }, - onPageFinished: (String url) => pageLoads.add(url), - ), - ), - ); - - await pageLoads.stream.first; // Wait for initial page load. - final WebViewController controller = await controllerCompleter.future; - await controller - .evaluateJavascript('location.href = "https://www.google.com/"'); - - await pageLoads.stream.first; // Wait for the next page load. - final String currentUrl = await controller.currentUrl(); - expect(currentUrl, 'https://www.google.com/'); - }); - - testWidgets('onWebResourceError', (WidgetTester tester) async { - final Completer errorCompleter = - Completer(); - - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: GlobalKey(), - initialUrl: 'https://www.notawebsite..com', - onWebResourceError: (WebResourceError error) { - errorCompleter.complete(error); - }, - ), - ), - ); - - final WebResourceError error = await errorCompleter.future; - expect(error, isNotNull); - - if (Platform.isIOS) { - expect(error.domain, isNotNull); - expect(error.failingUrl, isNull); - } else if (Platform.isAndroid) { - expect(error.errorType, isNotNull); - expect(error.failingUrl.startsWith('https://www.notawebsite..com'), - isTrue); - } - }); - - testWidgets('onWebResourceError is not called with valid url', - (WidgetTester tester) async { - final Completer errorCompleter = - Completer(); - - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: GlobalKey(), - initialUrl: - 'data:text/html;charset=utf-8;base64,PCFET0NUWVBFIGh0bWw+', - onWebResourceError: (WebResourceError error) { - errorCompleter.complete(error); - }, - ), - ), - ); - - expect(errorCompleter.future, doesNotComplete); - }); - - testWidgets('can block requests', (WidgetTester tester) async { - final Completer controllerCompleter = - Completer(); - final StreamController pageLoads = - StreamController.broadcast(); - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: GlobalKey(), - initialUrl: blankPageEncoded, - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - javascriptMode: JavascriptMode.unrestricted, - navigationDelegate: (NavigationRequest request) { - return (request.url.contains('youtube.com')) - ? NavigationDecision.prevent - : NavigationDecision.navigate; - }, - onPageFinished: (String url) => pageLoads.add(url), - ), - ), - ); - - await pageLoads.stream.first; // Wait for initial page load. - final WebViewController controller = await controllerCompleter.future; - await controller - .evaluateJavascript('location.href = "https://www.youtube.com/"'); - - // There should never be any second page load, since our new URL is - // blocked. Still wait for a potential page change for some time in order - // to give the test a chance to fail. - await pageLoads.stream.first - .timeout(const Duration(milliseconds: 500), onTimeout: () => null); - final String currentUrl = await controller.currentUrl(); - expect(currentUrl, isNot(contains('youtube.com'))); - }); - - testWidgets('supports asynchronous decisions', (WidgetTester tester) async { - final Completer controllerCompleter = - Completer(); - final StreamController pageLoads = - StreamController.broadcast(); - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: GlobalKey(), - initialUrl: blankPageEncoded, - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - javascriptMode: JavascriptMode.unrestricted, - navigationDelegate: (NavigationRequest request) async { - NavigationDecision decision = NavigationDecision.prevent; - decision = await Future.delayed( - const Duration(milliseconds: 10), - () => NavigationDecision.navigate); - return decision; - }, - onPageFinished: (String url) => pageLoads.add(url), - ), - ), - ); - - await pageLoads.stream.first; // Wait for initial page load. - final WebViewController controller = await controllerCompleter.future; - await controller - .evaluateJavascript('location.href = "https://www.google.com"'); - - await pageLoads.stream.first; // Wait for second page to load. - final String currentUrl = await controller.currentUrl(); - expect(currentUrl, 'https://www.google.com/'); - }); - }); - - testWidgets('launches with gestureNavigationEnabled on iOS', - (WidgetTester tester) async { - final Completer controllerCompleter = - Completer(); - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: SizedBox( - width: 400, - height: 300, - child: WebView( - key: GlobalKey(), - initialUrl: 'https://flutter.dev/', - gestureNavigationEnabled: true, - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - ), - ), - ), - ); - final WebViewController controller = await controllerCompleter.future; - final String currentUrl = await controller.currentUrl(); - expect(currentUrl, 'https://flutter.dev/'); - }); - - testWidgets('target _blank opens in same window', - (WidgetTester tester) async { - final Completer controllerCompleter = - Completer(); - final Completer pageLoaded = Completer(); - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: GlobalKey(), - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - javascriptMode: JavascriptMode.unrestricted, - onPageFinished: (String url) { - pageLoaded.complete(null); - }, - ), - ), - ); - final WebViewController controller = await controllerCompleter.future; - await controller.evaluateJavascript('window.open("about:blank", "_blank")'); - await pageLoaded.future; - final String currentUrl = await controller.currentUrl(); - expect(currentUrl, 'about:blank'); - }); - - testWidgets( - 'can open new window and go back', - (WidgetTester tester) async { - final Completer controllerCompleter = - Completer(); - final Completer pageLoaded = Completer(); - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: GlobalKey(), - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - javascriptMode: JavascriptMode.unrestricted, - onPageFinished: (String url) { - pageLoaded.complete(); - }, - initialUrl: 'https://flutter.dev', - ), - ), - ); - final WebViewController controller = await controllerCompleter.future; - await controller - .evaluateJavascript('window.open("https://www.google.com")'); - await pageLoaded.future; - expect(controller.currentUrl(), completion('https://www.google.com/')); - - await controller.goBack(); - expect(controller.currentUrl(), completion('https://www.flutter.dev')); - }, - skip: !Platform.isAndroid, - ); - - testWidgets( - 'javascript does not run in parent window', - (WidgetTester tester) async { - final String iframe = ''' - - - '''; - final String iframeTestBase64 = - base64Encode(const Utf8Encoder().convert(iframe)); - - final String openWindowTest = ''' - - - - XSS test - - - - - - '''; - final String openWindowTestBase64 = - base64Encode(const Utf8Encoder().convert(openWindowTest)); - final Completer controllerCompleter = - Completer(); - final Completer pageLoadCompleter = Completer(); - - await tester.pumpWidget( - Directionality( - textDirection: TextDirection.ltr, - child: WebView( - key: GlobalKey(), - onWebViewCreated: (WebViewController controller) { - controllerCompleter.complete(controller); - }, - javascriptMode: JavascriptMode.unrestricted, - initialUrl: - 'data:text/html;charset=utf-8;base64,$openWindowTestBase64', - onPageFinished: (String url) { - pageLoadCompleter.complete(); - }, - ), - ), - ); - - final WebViewController controller = await controllerCompleter.future; - await pageLoadCompleter.future; - - expect(controller.evaluateJavascript('iframeLoaded'), completion('true')); - expect( - controller.evaluateJavascript( - 'document.querySelector("p") && document.querySelector("p").textContent'), - completion('null'), - ); - }, - skip: !Platform.isAndroid, - ); + // }); + + // group('Audio playback policy', () { + // String audioTestBase64; + // setUpAll(() async { + // final ByteData audioData = + // await rootBundle.load('assets/sample_audio.ogg'); + // final String base64AudioData = + // base64Encode(Uint8List.view(audioData.buffer)); + // final String audioTest = ''' + // + // Audio auto play + // + // + // + // + // + // + // '''; + // audioTestBase64 = base64Encode(const Utf8Encoder().convert(audioTest)); + // }); + + // testWidgets('Auto media playback', (WidgetTester tester) async { + // Completer controllerCompleter = + // Completer(); + // Completer pageStarted = Completer(); + // Completer pageLoaded = Completer(); + + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: GlobalKey(), + // initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64', + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // javascriptMode: JavascriptMode.unrestricted, + // onPageStarted: (String url) { + // pageStarted.complete(null); + // }, + // onPageFinished: (String url) { + // pageLoaded.complete(null); + // }, + // initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, + // ), + // ), + // ); + // WebViewController controller = await controllerCompleter.future; + // await pageStarted.future; + // await pageLoaded.future; + + // String isPaused = await controller.evaluateJavascript('isPaused();'); + // expect(isPaused, _webviewBool(false)); + + // controllerCompleter = Completer(); + // pageStarted = Completer(); + // pageLoaded = Completer(); + + // // We change the key to re-create a new webview as we change the initialMediaPlaybackPolicy + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: GlobalKey(), + // initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64', + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // javascriptMode: JavascriptMode.unrestricted, + // onPageStarted: (String url) { + // pageStarted.complete(null); + // }, + // onPageFinished: (String url) { + // pageLoaded.complete(null); + // }, + // initialMediaPlaybackPolicy: + // AutoMediaPlaybackPolicy.require_user_action_for_all_media_types, + // ), + // ), + // ); + + // controller = await controllerCompleter.future; + // await pageStarted.future; + // await pageLoaded.future; + + // isPaused = await controller.evaluateJavascript('isPaused();'); + // expect(isPaused, _webviewBool(true)); + // }, skip: true /* https://github.com/flutter/flutter/issues/72572 */); + + // testWidgets('Changes to initialMediaPlaybackPolocy are ignored', + // (WidgetTester tester) async { + // final Completer controllerCompleter = + // Completer(); + // Completer pageStarted = Completer(); + // Completer pageLoaded = Completer(); + + // final GlobalKey key = GlobalKey(); + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: key, + // initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64', + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // javascriptMode: JavascriptMode.unrestricted, + // onPageStarted: (String url) { + // pageStarted.complete(null); + // }, + // onPageFinished: (String url) { + // pageLoaded.complete(null); + // }, + // initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, + // ), + // ), + // ); + // final WebViewController controller = await controllerCompleter.future; + // await pageStarted.future; + // await pageLoaded.future; + + // String isPaused = await controller.evaluateJavascript('isPaused();'); + // expect(isPaused, _webviewBool(false)); + + // pageStarted = Completer(); + // pageLoaded = Completer(); + + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: key, + // initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64', + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // javascriptMode: JavascriptMode.unrestricted, + // onPageStarted: (String url) { + // pageStarted.complete(null); + // }, + // onPageFinished: (String url) { + // pageLoaded.complete(null); + // }, + // initialMediaPlaybackPolicy: + // AutoMediaPlaybackPolicy.require_user_action_for_all_media_types, + // ), + // ), + // ); + + // await controller.reload(); + + // await pageStarted.future; + // await pageLoaded.future; + + // isPaused = await controller.evaluateJavascript('isPaused();'); + // expect(isPaused, _webviewBool(false)); + // }, skip: true /* https://github.com/flutter/flutter/issues/72572 */); + // }); + + // testWidgets('getTitle', (WidgetTester tester) async { + // final String getTitleTest = ''' + // + // Some title + // + // + // + // + // '''; + // final String getTitleTestBase64 = + // base64Encode(const Utf8Encoder().convert(getTitleTest)); + // final Completer pageStarted = Completer(); + // final Completer pageLoaded = Completer(); + // final Completer controllerCompleter = + // Completer(); + + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // initialUrl: 'data:text/html;charset=utf-8;base64,$getTitleTestBase64', + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // onPageStarted: (String url) { + // pageStarted.complete(null); + // }, + // onPageFinished: (String url) { + // pageLoaded.complete(null); + // }, + // ), + // ), + // ); + + // final WebViewController controller = await controllerCompleter.future; + // await pageStarted.future; + // await pageLoaded.future; + + // final String title = await controller.getTitle(); + // expect(title, 'Some title'); + // }); + + // group('Programmatic Scroll', () { + // testWidgets('setAndGetScrollPosition', (WidgetTester tester) async { + // final String scrollTestPage = ''' + // + // + // + // + // + // + //
+ // + // + // '''; + + // final String scrollTestPageBase64 = + // base64Encode(const Utf8Encoder().convert(scrollTestPage)); + + // final Completer pageLoaded = Completer(); + // final Completer controllerCompleter = + // Completer(); + + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // initialUrl: + // 'data:text/html;charset=utf-8;base64,$scrollTestPageBase64', + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // onPageFinished: (String url) { + // pageLoaded.complete(null); + // }, + // ), + // ), + // ); + + // final WebViewController controller = await controllerCompleter.future; + // await pageLoaded.future; + + // await tester.pumpAndSettle(Duration(seconds: 3)); + + // // Check scrollTo() + // const int X_SCROLL = 123; + // const int Y_SCROLL = 321; + + // await controller.scrollTo(X_SCROLL, Y_SCROLL); + // int scrollPosX = await controller.getScrollX(); + // int scrollPosY = await controller.getScrollY(); + // expect(X_SCROLL, scrollPosX); + // expect(Y_SCROLL, scrollPosY); + + // // Check scrollBy() (on top of scrollTo()) + // await controller.scrollBy(X_SCROLL, Y_SCROLL); + // scrollPosX = await controller.getScrollX(); + // scrollPosY = await controller.getScrollY(); + // expect(X_SCROLL * 2, scrollPosX); + // expect(Y_SCROLL * 2, scrollPosY); + // }); + // }); + + // group('SurfaceAndroidWebView', () { + // setUpAll(() { + // WebView.platform = SurfaceAndroidWebView(); + // }); + + // tearDownAll(() { + // WebView.platform = null; + // }); + + // testWidgets('setAndGetScrollPosition', (WidgetTester tester) async { + // final String scrollTestPage = ''' + // + // + // + // + // + // + //
+ // + // + // '''; + + // final String scrollTestPageBase64 = + // base64Encode(const Utf8Encoder().convert(scrollTestPage)); + + // final Completer pageLoaded = Completer(); + // final Completer controllerCompleter = + // Completer(); + + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // initialUrl: + // 'data:text/html;charset=utf-8;base64,$scrollTestPageBase64', + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // onPageFinished: (String url) { + // pageLoaded.complete(null); + // }, + // ), + // ), + // ); + + // final WebViewController controller = await controllerCompleter.future; + // await pageLoaded.future; + + // await tester.pumpAndSettle(Duration(seconds: 3)); + + // // Check scrollTo() + // const int X_SCROLL = 123; + // const int Y_SCROLL = 321; + + // await controller.scrollTo(X_SCROLL, Y_SCROLL); + // int scrollPosX = await controller.getScrollX(); + // int scrollPosY = await controller.getScrollY(); + // expect(X_SCROLL, scrollPosX); + // expect(Y_SCROLL, scrollPosY); + + // // Check scrollBy() (on top of scrollTo()) + // await controller.scrollBy(X_SCROLL, Y_SCROLL); + // scrollPosX = await controller.getScrollX(); + // scrollPosY = await controller.getScrollY(); + // expect(X_SCROLL * 2, scrollPosX); + // expect(Y_SCROLL * 2, scrollPosY); + // }, skip: !Platform.isAndroid); + + // testWidgets('inputs are scrolled into view when focused', + // (WidgetTester tester) async { + // final String scrollTestPage = ''' + // + // + // + // + // + // + //
+ // + // + // + // '''; + + // final String scrollTestPageBase64 = + // base64Encode(const Utf8Encoder().convert(scrollTestPage)); + + // final Completer pageLoaded = Completer(); + // final Completer controllerCompleter = + // Completer(); + + // await tester.runAsync(() async { + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: SizedBox( + // width: 200, + // height: 200, + // child: WebView( + // initialUrl: + // 'data:text/html;charset=utf-8;base64,$scrollTestPageBase64', + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // onPageFinished: (String url) { + // pageLoaded.complete(null); + // }, + // javascriptMode: JavascriptMode.unrestricted, + // ), + // ), + // ), + // ); + // await Future.delayed(Duration(milliseconds: 20)); + // await tester.pump(); + // }); + + // final WebViewController controller = await controllerCompleter.future; + // await pageLoaded.future; + // final String viewportRectJSON = await _evaluateJavascript( + // controller, 'JSON.stringify(viewport.getBoundingClientRect())'); + // final Map viewportRectRelativeToViewport = + // jsonDecode(viewportRectJSON); + + // // Check that the input is originally outside of the viewport. + + // final String initialInputClientRectJSON = await _evaluateJavascript( + // controller, 'JSON.stringify(inputEl.getBoundingClientRect())'); + // final Map initialInputClientRectRelativeToViewport = + // jsonDecode(initialInputClientRectJSON); + + // expect( + // initialInputClientRectRelativeToViewport['bottom'] <= + // viewportRectRelativeToViewport['bottom'], + // isFalse); + + // await controller.evaluateJavascript('inputEl.focus()'); + + // // Check that focusing the input brought it into view. + + // final String lastInputClientRectJSON = await _evaluateJavascript( + // controller, 'JSON.stringify(inputEl.getBoundingClientRect())'); + // final Map lastInputClientRectRelativeToViewport = + // jsonDecode(lastInputClientRectJSON); + + // expect( + // lastInputClientRectRelativeToViewport['top'] >= + // viewportRectRelativeToViewport['top'], + // isTrue); + // expect( + // lastInputClientRectRelativeToViewport['bottom'] <= + // viewportRectRelativeToViewport['bottom'], + // isTrue); + + // expect( + // lastInputClientRectRelativeToViewport['left'] >= + // viewportRectRelativeToViewport['left'], + // isTrue); + // expect( + // lastInputClientRectRelativeToViewport['right'] <= + // viewportRectRelativeToViewport['right'], + // isTrue); + // }, skip: !Platform.isAndroid); + // }); + + // group('NavigationDelegate', () { + // final String blankPage = ""; + // final String blankPageEncoded = 'data:text/html;charset=utf-8;base64,' + + // base64Encode(const Utf8Encoder().convert(blankPage)); + + // testWidgets('can allow requests', (WidgetTester tester) async { + // final Completer controllerCompleter = + // Completer(); + // final StreamController pageLoads = + // StreamController.broadcast(); + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: GlobalKey(), + // initialUrl: blankPageEncoded, + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // javascriptMode: JavascriptMode.unrestricted, + // navigationDelegate: (NavigationRequest request) { + // return (request.url.contains('youtube.com')) + // ? NavigationDecision.prevent + // : NavigationDecision.navigate; + // }, + // onPageFinished: (String url) => pageLoads.add(url), + // ), + // ), + // ); + + // await pageLoads.stream.first; // Wait for initial page load. + // final WebViewController controller = await controllerCompleter.future; + // await controller + // .evaluateJavascript('location.href = "https://www.google.com/"'); + + // await pageLoads.stream.first; // Wait for the next page load. + // final String currentUrl = await controller.currentUrl(); + // expect(currentUrl, 'https://www.google.com/'); + // }); + + // testWidgets('onWebResourceError', (WidgetTester tester) async { + // final Completer errorCompleter = + // Completer(); + + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: GlobalKey(), + // initialUrl: 'https://www.notawebsite..com', + // onWebResourceError: (WebResourceError error) { + // errorCompleter.complete(error); + // }, + // ), + // ), + // ); + + // final WebResourceError error = await errorCompleter.future; + // expect(error, isNotNull); + + // if (Platform.isIOS) { + // expect(error.domain, isNotNull); + // expect(error.failingUrl, isNull); + // } else if (Platform.isAndroid) { + // expect(error.errorType, isNotNull); + // expect(error.failingUrl.startsWith('https://www.notawebsite..com'), + // isTrue); + // } + // }); + + // testWidgets('onWebResourceError is not called with valid url', + // (WidgetTester tester) async { + // final Completer errorCompleter = + // Completer(); + + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: GlobalKey(), + // initialUrl: + // 'data:text/html;charset=utf-8;base64,PCFET0NUWVBFIGh0bWw+', + // onWebResourceError: (WebResourceError error) { + // errorCompleter.complete(error); + // }, + // ), + // ), + // ); + + // expect(errorCompleter.future, doesNotComplete); + // }); + + // testWidgets('can block requests', (WidgetTester tester) async { + // final Completer controllerCompleter = + // Completer(); + // final StreamController pageLoads = + // StreamController.broadcast(); + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: GlobalKey(), + // initialUrl: blankPageEncoded, + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // javascriptMode: JavascriptMode.unrestricted, + // navigationDelegate: (NavigationRequest request) { + // return (request.url.contains('youtube.com')) + // ? NavigationDecision.prevent + // : NavigationDecision.navigate; + // }, + // onPageFinished: (String url) => pageLoads.add(url), + // ), + // ), + // ); + + // await pageLoads.stream.first; // Wait for initial page load. + // final WebViewController controller = await controllerCompleter.future; + // await controller + // .evaluateJavascript('location.href = "https://www.youtube.com/"'); + + // // There should never be any second page load, since our new URL is + // // blocked. Still wait for a potential page change for some time in order + // // to give the test a chance to fail. + // await pageLoads.stream.first + // .timeout(const Duration(milliseconds: 500), onTimeout: () => null); + // final String currentUrl = await controller.currentUrl(); + // expect(currentUrl, isNot(contains('youtube.com'))); + // }); + + // testWidgets('supports asynchronous decisions', (WidgetTester tester) async { + // final Completer controllerCompleter = + // Completer(); + // final StreamController pageLoads = + // StreamController.broadcast(); + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: GlobalKey(), + // initialUrl: blankPageEncoded, + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // javascriptMode: JavascriptMode.unrestricted, + // navigationDelegate: (NavigationRequest request) async { + // NavigationDecision decision = NavigationDecision.prevent; + // decision = await Future.delayed( + // const Duration(milliseconds: 10), + // () => NavigationDecision.navigate); + // return decision; + // }, + // onPageFinished: (String url) => pageLoads.add(url), + // ), + // ), + // ); + + // await pageLoads.stream.first; // Wait for initial page load. + // final WebViewController controller = await controllerCompleter.future; + // await controller + // .evaluateJavascript('location.href = "https://www.google.com"'); + + // await pageLoads.stream.first; // Wait for second page to load. + // final String currentUrl = await controller.currentUrl(); + // expect(currentUrl, 'https://www.google.com/'); + // }); + // }); + + // testWidgets('launches with gestureNavigationEnabled on iOS', + // (WidgetTester tester) async { + // final Completer controllerCompleter = + // Completer(); + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: SizedBox( + // width: 400, + // height: 300, + // child: WebView( + // key: GlobalKey(), + // initialUrl: 'https://flutter.dev/', + // gestureNavigationEnabled: true, + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // ), + // ), + // ), + // ); + // final WebViewController controller = await controllerCompleter.future; + // final String currentUrl = await controller.currentUrl(); + // expect(currentUrl, 'https://flutter.dev/'); + // }); + + // testWidgets('target _blank opens in same window', + // (WidgetTester tester) async { + // final Completer controllerCompleter = + // Completer(); + // final Completer pageLoaded = Completer(); + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: GlobalKey(), + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // javascriptMode: JavascriptMode.unrestricted, + // onPageFinished: (String url) { + // pageLoaded.complete(null); + // }, + // ), + // ), + // ); + // final WebViewController controller = await controllerCompleter.future; + // await controller.evaluateJavascript('window.open("about:blank", "_blank")'); + // await pageLoaded.future; + // final String currentUrl = await controller.currentUrl(); + // expect(currentUrl, 'about:blank'); + // }); + + // testWidgets( + // 'can open new window and go back', + // (WidgetTester tester) async { + // final Completer controllerCompleter = + // Completer(); + // final Completer pageLoaded = Completer(); + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: GlobalKey(), + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // javascriptMode: JavascriptMode.unrestricted, + // onPageFinished: (String url) { + // pageLoaded.complete(); + // }, + // initialUrl: 'https://flutter.dev', + // ), + // ), + // ); + // final WebViewController controller = await controllerCompleter.future; + // await controller + // .evaluateJavascript('window.open("https://www.google.com")'); + // await pageLoaded.future; + // expect(controller.currentUrl(), completion('https://www.google.com/')); + + // await controller.goBack(); + // expect(controller.currentUrl(), completion('https://www.flutter.dev')); + // }, + // skip: !Platform.isAndroid, + // ); + + // testWidgets( + // 'javascript does not run in parent window', + // (WidgetTester tester) async { + // final String iframe = ''' + // + // + // '''; + // final String iframeTestBase64 = + // base64Encode(const Utf8Encoder().convert(iframe)); + + // final String openWindowTest = ''' + // + // + // + // XSS test + // + // + // + // + // + // '''; + // final String openWindowTestBase64 = + // base64Encode(const Utf8Encoder().convert(openWindowTest)); + // final Completer controllerCompleter = + // Completer(); + // final Completer pageLoadCompleter = Completer(); + + // await tester.pumpWidget( + // Directionality( + // textDirection: TextDirection.ltr, + // child: WebView( + // key: GlobalKey(), + // onWebViewCreated: (WebViewController controller) { + // controllerCompleter.complete(controller); + // }, + // javascriptMode: JavascriptMode.unrestricted, + // initialUrl: + // 'data:text/html;charset=utf-8;base64,$openWindowTestBase64', + // onPageFinished: (String url) { + // pageLoadCompleter.complete(); + // }, + // ), + // ), + // ); + + // final WebViewController controller = await controllerCompleter.future; + // await pageLoadCompleter.future; + + // expect(controller.evaluateJavascript('iframeLoaded'), completion('true')); + // expect( + // controller.evaluateJavascript( + // 'document.querySelector("p") && document.querySelector("p").textContent'), + // completion('null'), + // ); + // }, + // skip: !Platform.isAndroid, + // ); } // JavaScript booleans evaluate to different string values on Android and iOS. diff --git a/packages/webview_flutter/ios/Classes/FlutterWebView.m b/packages/webview_flutter/ios/Classes/FlutterWebView.m index 7ca36e33031c..b0e6f3afed85 100644 --- a/packages/webview_flutter/ios/Classes/FlutterWebView.m +++ b/packages/webview_flutter/ios/Classes/FlutterWebView.m @@ -89,9 +89,11 @@ - (instancetype)initWithFrame:(CGRect)frame NSDictionary* settings = args[@"settings"]; WKWebViewConfiguration* configuration = [[WKWebViewConfiguration alloc] init]; + [self applyConfigurationSetting:settings inConfiguration:configuration]; configuration.userContentController = userContentController; [self updateAutoMediaPlaybackPolicy:args[@"autoMediaPlaybackPolicy"] inConfiguration:configuration]; + NSLog(@"configuration %@", @(configuration.allowsInlineMediaPlayback)); _webView = [[FLTWKWebView alloc] initWithFrame:frame configuration:configuration]; _navigationDelegate = [[FLTWKNavigationDelegate alloc] initWithChannel:_channel]; @@ -347,9 +349,6 @@ - (NSString*)applySettings:(NSDictionary*)settings { } else if ([key isEqualToString:@"userAgent"]) { NSString* userAgent = settings[key]; [self updateUserAgent:[userAgent isEqual:[NSNull null]] ? nil : userAgent]; - } else if ([key isEqualToString:@"allowsInlineMediaPlayback"]) { - NSNumber* allowsInlineMediaPlayback = settings[key]; - _webView.configuration.allowsInlineMediaPlayback = [allowsInlineMediaPlayback boolValue]; } else { [unknownKeys addObject:key]; } @@ -361,6 +360,16 @@ - (NSString*)applySettings:(NSDictionary*)settings { [unknownKeys componentsJoinedByString:@", "]]; } +- (void)applyConfigurationSetting:(NSDictionary*)settings inConfiguration:(WKWebViewConfiguration*)configuration { + NSAssert(configuration != _webView.configuration, @"configuration needs to be updated before webView.configuration."); + for (NSString* key in settings) { + if ([key isEqualToString:@"allowsInlineMediaPlayback"]) { + NSNumber* allowsInlineMediaPlayback = settings[key]; + configuration.allowsInlineMediaPlayback = [allowsInlineMediaPlayback boolValue]; + } + } +} + - (void)updateJsMode:(NSNumber*)mode { WKPreferences* preferences = [[_webView configuration] preferences]; switch ([mode integerValue]) { From 24f6c206d8cfd2a4dfb921fef0c0a15e7c8608bf Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Tue, 6 Apr 2021 11:48:22 -0700 Subject: [PATCH 2/9] draft --- .../webview_flutter_test.dart | 25 ++++++++++++++++--- .../contents.xcworkspacedata | 2 +- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/packages/webview_flutter/example/integration_test/webview_flutter_test.dart b/packages/webview_flutter/example/integration_test/webview_flutter_test.dart index b41a123e6d42..415cf6d4dd83 100644 --- a/packages/webview_flutter/example/integration_test/webview_flutter_test.dart +++ b/packages/webview_flutter/example/integration_test/webview_flutter_test.dart @@ -348,8 +348,8 @@ void main() { video.addEventListener('durationchange', videoPausePlayHandler, false); video.addEventListener('loadeddata', videoPausePlayHandler, false); video.addEventListener('timeupdate', videoPausePlayHandler, false); - video.addEventListener('loadstart', videoPausePlayHandler, false); - video.addEventListener('canplay', videoPausePlayHandler, false); + video.addEventListener('loadstart', videoPausePlayHandler, false); + video.addEventListener('canplay', videoPausePlayHandler, false); } function videoPausePlayHandler(e) { VideoTest.postMessage(e.type); @@ -567,7 +567,7 @@ void main() { pageLoaded.complete(null); }, initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, - allowsInlineMediaPlayback: true, + allowsInlineMediaPlayback: false, ), ), ); @@ -601,13 +601,30 @@ void main() { onPageFinished: (String url) { pageLoaded.complete(null); }, + javascriptChannels: { + JavascriptChannel( + name: 'VideoTest', + onMessageReceived: (JavascriptMessage message) { + print(message.message); + if (message.message == 'playing'){ + messagesReceived.complete(message.message); + } + // message1 = message.message; + }, + ),}, initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, - allowsInlineMediaPlayback: true, + allowsInlineMediaPlayback: false, ), ), ); controller = await controllerCompleter.future; await pageLoaded.future; + await messagesReceived.future; + + + String fullScreen = + await controller.evaluateJavascript('isFullScreen();'); + expect(fullScreen, _webviewBool(true)); }); // }); diff --git a/packages/webview_flutter/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/webview_flutter/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 1d526a16ed0f..919434a6254f 100644 --- a/packages/webview_flutter/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/packages/webview_flutter/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:"> From 43db4eb01cf67a00e9c06568b63be86048a70e9c Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Tue, 6 Apr 2021 15:47:00 -0700 Subject: [PATCH 3/9] fix tests --- .../webview_flutter_test.dart | 2562 ++++++++--------- .../ios/Classes/FlutterWebView.m | 1 - 2 files changed, 1261 insertions(+), 1302 deletions(-) diff --git a/packages/webview_flutter/example/integration_test/webview_flutter_test.dart b/packages/webview_flutter/example/integration_test/webview_flutter_test.dart index 415cf6d4dd83..4de507202997 100644 --- a/packages/webview_flutter/example/integration_test/webview_flutter_test.dart +++ b/packages/webview_flutter/example/integration_test/webview_flutter_test.dart @@ -20,316 +20,314 @@ import 'package:integration_test/integration_test.dart'; void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); - // testWidgets('initalUrl', (WidgetTester tester) async { - // final Completer controllerCompleter = - // Completer(); - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: GlobalKey(), - // initialUrl: 'https://flutter.dev/', - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // ), - // ), - // ); - // final WebViewController controller = await controllerCompleter.future; - // final String currentUrl = await controller.currentUrl(); - // expect(currentUrl, 'https://flutter.dev/'); - // }); - - // testWidgets('loadUrl', (WidgetTester tester) async { - // final Completer controllerCompleter = - // Completer(); - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: GlobalKey(), - // initialUrl: 'https://flutter.dev/', - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // ), - // ), - // ); - // final WebViewController controller = await controllerCompleter.future; - // await controller.loadUrl('https://www.google.com/'); - // final String currentUrl = await controller.currentUrl(); - // expect(currentUrl, 'https://www.google.com/'); - // }); - - // // enable this once https://github.com/flutter/flutter/issues/31510 - // // is resolved. - // testWidgets('loadUrl with headers', (WidgetTester tester) async { - // final Completer controllerCompleter = - // Completer(); - // final StreamController pageStarts = StreamController(); - // final StreamController pageLoads = StreamController(); - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: GlobalKey(), - // initialUrl: 'https://flutter.dev/', - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // javascriptMode: JavascriptMode.unrestricted, - // onPageStarted: (String url) { - // pageStarts.add(url); - // }, - // onPageFinished: (String url) { - // pageLoads.add(url); - // }, - // ), - // ), - // ); - // final WebViewController controller = await controllerCompleter.future; - // final Map headers = { - // 'test_header': 'flutter_test_header' - // }; - // await controller.loadUrl('https://flutter-header-echo.herokuapp.com/', - // headers: headers); - // final String currentUrl = await controller.currentUrl(); - // expect(currentUrl, 'https://flutter-header-echo.herokuapp.com/'); - - // await pageStarts.stream.firstWhere((String url) => url == currentUrl); - // await pageLoads.stream.firstWhere((String url) => url == currentUrl); - - // final String content = await controller - // .evaluateJavascript('document.documentElement.innerText'); - // expect(content.contains('flutter_test_header'), isTrue); - // }); - - // testWidgets('JavaScriptChannel', (WidgetTester tester) async { - // final Completer controllerCompleter = - // Completer(); - // final Completer pageStarted = Completer(); - // final Completer pageLoaded = Completer(); - // final List messagesReceived = []; - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: GlobalKey(), - // // This is the data URL for: '' - // initialUrl: - // 'data:text/html;charset=utf-8;base64,PCFET0NUWVBFIGh0bWw+', - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // javascriptMode: JavascriptMode.unrestricted, - // javascriptChannels: { - // JavascriptChannel( - // name: 'Echo', - // onMessageReceived: (JavascriptMessage message) { - // messagesReceived.add(message.message); - // }, - // ), - // }, - // onPageStarted: (String url) { - // pageStarted.complete(null); - // }, - // onPageFinished: (String url) { - // pageLoaded.complete(null); - // }, - // ), - // ), - // ); - // final WebViewController controller = await controllerCompleter.future; - // await pageStarted.future; - // await pageLoaded.future; - - // expect(messagesReceived, isEmpty); - // // Append a return value "1" in the end will prevent an iOS platform exception. - // // See: https://github.com/flutter/flutter/issues/66318#issuecomment-701105380 - // // TODO(cyanglaz): remove the workaround "1" in the end when the below issue is fixed. - // // https://github.com/flutter/flutter/issues/66318 - // await controller.evaluateJavascript('Echo.postMessage("hello");1;'); - // expect(messagesReceived, equals(['hello'])); - // }); - - // testWidgets('resize webview', (WidgetTester tester) async { - // final String resizeTest = ''' - // - // Resize test - // - // - // - // - // - // '''; - // final String resizeTestBase64 = - // base64Encode(const Utf8Encoder().convert(resizeTest)); - // final Completer resizeCompleter = Completer(); - // final Completer pageStarted = Completer(); - // final Completer pageLoaded = Completer(); - // final Completer controllerCompleter = - // Completer(); - // final GlobalKey key = GlobalKey(); - - // final WebView webView = WebView( - // key: key, - // initialUrl: 'data:text/html;charset=utf-8;base64,$resizeTestBase64', - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // javascriptChannels: { - // JavascriptChannel( - // name: 'Resize', - // onMessageReceived: (JavascriptMessage message) { - // resizeCompleter.complete(true); - // }, - // ), - // }, - // onPageStarted: (String url) { - // pageStarted.complete(null); - // }, - // onPageFinished: (String url) { - // pageLoaded.complete(null); - // }, - // javascriptMode: JavascriptMode.unrestricted, - // ); - - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: Column( - // children: [ - // SizedBox( - // width: 200, - // height: 200, - // child: webView, - // ), - // ], - // ), - // ), - // ); - - // await controllerCompleter.future; - // await pageStarted.future; - // await pageLoaded.future; - - // expect(resizeCompleter.isCompleted, false); - - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: Column( - // children: [ - // SizedBox( - // width: 400, - // height: 400, - // child: webView, - // ), - // ], - // ), - // ), - // ); - - // await resizeCompleter.future; - // }); - - // testWidgets('set custom userAgent', (WidgetTester tester) async { - // final Completer controllerCompleter1 = - // Completer(); - // final GlobalKey _globalKey = GlobalKey(); - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: _globalKey, - // initialUrl: 'about:blank', - // javascriptMode: JavascriptMode.unrestricted, - // userAgent: 'Custom_User_Agent1', - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter1.complete(controller); - // }, - // ), - // ), - // ); - // final WebViewController controller1 = await controllerCompleter1.future; - // final String customUserAgent1 = await _getUserAgent(controller1); - // expect(customUserAgent1, 'Custom_User_Agent1'); - // // rebuild the WebView with a different user agent. - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: _globalKey, - // initialUrl: 'about:blank', - // javascriptMode: JavascriptMode.unrestricted, - // userAgent: 'Custom_User_Agent2', - // ), - // ), - // ); - - // final String customUserAgent2 = await _getUserAgent(controller1); - // expect(customUserAgent2, 'Custom_User_Agent2'); - // }); - - // testWidgets('use default platform userAgent after webView is rebuilt', - // (WidgetTester tester) async { - // final Completer controllerCompleter = - // Completer(); - // final GlobalKey _globalKey = GlobalKey(); - // // Build the webView with no user agent to get the default platform user agent. - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: _globalKey, - // initialUrl: 'https://flutter.dev/', - // javascriptMode: JavascriptMode.unrestricted, - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // ), - // ), - // ); - // final WebViewController controller = await controllerCompleter.future; - // final String defaultPlatformUserAgent = await _getUserAgent(controller); - // // rebuild the WebView with a custom user agent. - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: _globalKey, - // initialUrl: 'about:blank', - // javascriptMode: JavascriptMode.unrestricted, - // userAgent: 'Custom_User_Agent', - // ), - // ), - // ); - // final String customUserAgent = await _getUserAgent(controller); - // expect(customUserAgent, 'Custom_User_Agent'); - // // rebuilds the WebView with no user agent. - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: _globalKey, - // initialUrl: 'about:blank', - // javascriptMode: JavascriptMode.unrestricted, - // ), - // ), - // ); - - // final String customUserAgent2 = await _getUserAgent(controller); - // expect(customUserAgent2, defaultPlatformUserAgent); - // }); - - // group('Video playback policy', () { + testWidgets('initalUrl', (WidgetTester tester) async { + final Completer controllerCompleter = + Completer(); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: GlobalKey(), + initialUrl: 'https://flutter.dev/', + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + ), + ), + ); + final WebViewController controller = await controllerCompleter.future; + final String currentUrl = await controller.currentUrl(); + expect(currentUrl, 'https://flutter.dev/'); + }); + + testWidgets('loadUrl', (WidgetTester tester) async { + final Completer controllerCompleter = + Completer(); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: GlobalKey(), + initialUrl: 'https://flutter.dev/', + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + ), + ), + ); + final WebViewController controller = await controllerCompleter.future; + await controller.loadUrl('https://www.google.com/'); + final String currentUrl = await controller.currentUrl(); + expect(currentUrl, 'https://www.google.com/'); + }); + + testWidgets('loadUrl with headers', (WidgetTester tester) async { + final Completer controllerCompleter = + Completer(); + final StreamController pageStarts = StreamController(); + final StreamController pageLoads = StreamController(); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: GlobalKey(), + initialUrl: 'https://flutter.dev/', + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + javascriptMode: JavascriptMode.unrestricted, + onPageStarted: (String url) { + pageStarts.add(url); + }, + onPageFinished: (String url) { + pageLoads.add(url); + }, + ), + ), + ); + final WebViewController controller = await controllerCompleter.future; + final Map headers = { + 'test_header': 'flutter_test_header' + }; + await controller.loadUrl('https://flutter-header-echo.herokuapp.com/', + headers: headers); + final String currentUrl = await controller.currentUrl(); + expect(currentUrl, 'https://flutter-header-echo.herokuapp.com/'); + + await pageStarts.stream.firstWhere((String url) => url == currentUrl); + await pageLoads.stream.firstWhere((String url) => url == currentUrl); + + final String content = await controller + .evaluateJavascript('document.documentElement.innerText'); + expect(content.contains('flutter_test_header'), isTrue); + }); + + testWidgets('JavaScriptChannel', (WidgetTester tester) async { + final Completer controllerCompleter = + Completer(); + final Completer pageStarted = Completer(); + final Completer pageLoaded = Completer(); + final List messagesReceived = []; + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: GlobalKey(), + // This is the data URL for: '' + initialUrl: + 'data:text/html;charset=utf-8;base64,PCFET0NUWVBFIGh0bWw+', + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + javascriptMode: JavascriptMode.unrestricted, + javascriptChannels: { + JavascriptChannel( + name: 'Echo', + onMessageReceived: (JavascriptMessage message) { + messagesReceived.add(message.message); + }, + ), + }, + onPageStarted: (String url) { + pageStarted.complete(null); + }, + onPageFinished: (String url) { + pageLoaded.complete(null); + }, + ), + ), + ); + final WebViewController controller = await controllerCompleter.future; + await pageStarted.future; + await pageLoaded.future; + + expect(messagesReceived, isEmpty); + // Append a return value "1" in the end will prevent an iOS platform exception. + // See: https://github.com/flutter/flutter/issues/66318#issuecomment-701105380 + // TODO(cyanglaz): remove the workaround "1" in the end when the below issue is fixed. + // https://github.com/flutter/flutter/issues/66318 + await controller.evaluateJavascript('Echo.postMessage("hello");1;'); + expect(messagesReceived, equals(['hello'])); + }); + + testWidgets('resize webview', (WidgetTester tester) async { + final String resizeTest = ''' + + Resize test + + + + + + '''; + final String resizeTestBase64 = + base64Encode(const Utf8Encoder().convert(resizeTest)); + final Completer resizeCompleter = Completer(); + final Completer pageStarted = Completer(); + final Completer pageLoaded = Completer(); + final Completer controllerCompleter = + Completer(); + final GlobalKey key = GlobalKey(); + + final WebView webView = WebView( + key: key, + initialUrl: 'data:text/html;charset=utf-8;base64,$resizeTestBase64', + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + javascriptChannels: { + JavascriptChannel( + name: 'Resize', + onMessageReceived: (JavascriptMessage message) { + resizeCompleter.complete(true); + }, + ), + }, + onPageStarted: (String url) { + pageStarted.complete(null); + }, + onPageFinished: (String url) { + pageLoaded.complete(null); + }, + javascriptMode: JavascriptMode.unrestricted, + ); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: Column( + children: [ + SizedBox( + width: 200, + height: 200, + child: webView, + ), + ], + ), + ), + ); + + await controllerCompleter.future; + await pageStarted.future; + await pageLoaded.future; + + expect(resizeCompleter.isCompleted, false); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: Column( + children: [ + SizedBox( + width: 400, + height: 400, + child: webView, + ), + ], + ), + ), + ); + + await resizeCompleter.future; + }); + + testWidgets('set custom userAgent', (WidgetTester tester) async { + final Completer controllerCompleter1 = + Completer(); + final GlobalKey _globalKey = GlobalKey(); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: _globalKey, + initialUrl: 'about:blank', + javascriptMode: JavascriptMode.unrestricted, + userAgent: 'Custom_User_Agent1', + onWebViewCreated: (WebViewController controller) { + controllerCompleter1.complete(controller); + }, + ), + ), + ); + final WebViewController controller1 = await controllerCompleter1.future; + final String customUserAgent1 = await _getUserAgent(controller1); + expect(customUserAgent1, 'Custom_User_Agent1'); + // rebuild the WebView with a different user agent. + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: _globalKey, + initialUrl: 'about:blank', + javascriptMode: JavascriptMode.unrestricted, + userAgent: 'Custom_User_Agent2', + ), + ), + ); + + final String customUserAgent2 = await _getUserAgent(controller1); + expect(customUserAgent2, 'Custom_User_Agent2'); + }); + + testWidgets('use default platform userAgent after webView is rebuilt', + (WidgetTester tester) async { + final Completer controllerCompleter = + Completer(); + final GlobalKey _globalKey = GlobalKey(); + // Build the webView with no user agent to get the default platform user agent. + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: _globalKey, + initialUrl: 'https://flutter.dev/', + javascriptMode: JavascriptMode.unrestricted, + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + ), + ), + ); + final WebViewController controller = await controllerCompleter.future; + final String defaultPlatformUserAgent = await _getUserAgent(controller); + // rebuild the WebView with a custom user agent. + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: _globalKey, + initialUrl: 'about:blank', + javascriptMode: JavascriptMode.unrestricted, + userAgent: 'Custom_User_Agent', + ), + ), + ); + final String customUserAgent = await _getUserAgent(controller); + expect(customUserAgent, 'Custom_User_Agent'); + // rebuilds the WebView with no user agent. + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: _globalKey, + initialUrl: 'about:blank', + javascriptMode: JavascriptMode.unrestricted, + ), + ), + ); + + final String customUserAgent2 = await _getUserAgent(controller); + expect(customUserAgent2, defaultPlatformUserAgent); + }); + + group('Video playback policy', () { String videoTestBase64; setUpAll(() async { final ByteData videoData = @@ -343,27 +341,11 @@ void main() { function play() { var video = document.getElementById("video"); video.play(); - video.addEventListener('play', videoPausePlayHandler, false); - video.addEventListener('pause', videoPausePlayHandler, false); - video.addEventListener('durationchange', videoPausePlayHandler, false); - video.addEventListener('loadeddata', videoPausePlayHandler, false); - video.addEventListener('timeupdate', videoPausePlayHandler, false); - video.addEventListener('loadstart', videoPausePlayHandler, false); - video.addEventListener('canplay', videoPausePlayHandler, false); + video.addEventListener('timeupdate', videoTimeUpdateHandler, false); } - function videoPausePlayHandler(e) { - VideoTest.postMessage(e.type); - // if (e.type == 'play') { - // VideoTest.postMessage("play"); - // } else if (e.type == 'pause') { - // VideoTest.postMessage("pause"); - // } else if (e.type == 'durationchange') { - // VideoTest.postMessage("durationchange"); - // } else if (e.type == 'loadeddata') { - // VideoTest.postMessage("loadeddata"); - // } else if (e.type == 'timeupdate') { - // VideoTest.postMessage("timeupdate"); - // } + function videoTimeUpdateHandler(e) { + var video = document.getElementById("video"); + VideoTestTime.postMessage(video.currentTime); } function isPaused() { var video = document.getElementById("video"); @@ -373,10 +355,6 @@ void main() { var video = document.getElementById("video"); return video.webkitDisplayingFullscreen; } - function currentTime() { - var video = document.getElementById("video"); - return video.duration; - } @@ -389,161 +367,130 @@ void main() { videoTestBase64 = base64Encode(const Utf8Encoder().convert(videoTest)); }); - // testWidgets('Auto media playback', (WidgetTester tester) async { - // Completer controllerCompleter = - // Completer(); - // Completer pageLoaded = Completer(); - - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: GlobalKey(), - // initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // javascriptMode: JavascriptMode.unrestricted, - // onPageFinished: (String url) { - // pageLoaded.complete(null); - // }, - // initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, - // ), - // ), - // ); - // WebViewController controller = await controllerCompleter.future; - // await pageLoaded.future; - - // String isPaused = await controller.evaluateJavascript('isPaused();'); - // expect(isPaused, _webviewBool(false)); - - // controllerCompleter = Completer(); - // pageLoaded = Completer(); - - // // We change the key to re-create a new webview as we change the initialMediaPlaybackPolicy - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: GlobalKey(), - // initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // javascriptMode: JavascriptMode.unrestricted, - // onPageFinished: (String url) { - // pageLoaded.complete(null); - // }, - // initialMediaPlaybackPolicy: - // AutoMediaPlaybackPolicy.require_user_action_for_all_media_types, - // ), - // ), - // ); - - // controller = await controllerCompleter.future; - // await pageLoaded.future; - - // isPaused = await controller.evaluateJavascript('isPaused();'); - // expect(isPaused, _webviewBool(true)); - // }, skip: true /* https://github.com/flutter/flutter/issues/72572 */); - - // testWidgets('Changes to initialMediaPlaybackPolicy are ignored', - // (WidgetTester tester) async { - // final Completer controllerCompleter = - // Completer(); - // Completer pageLoaded = Completer(); - - // final GlobalKey key = GlobalKey(); - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: key, - // initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // javascriptMode: JavascriptMode.unrestricted, - // onPageFinished: (String url) { - // pageLoaded.complete(null); - // }, - // initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, - // ), - // ), - // ); - // final WebViewController controller = await controllerCompleter.future; - // await pageLoaded.future; - - // String isPaused = await controller.evaluateJavascript('isPaused();'); - // expect(isPaused, _webviewBool(false)); - - // pageLoaded = Completer(); - - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: key, - // initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // javascriptMode: JavascriptMode.unrestricted, - // onPageFinished: (String url) { - // pageLoaded.complete(null); - // }, - // initialMediaPlaybackPolicy: - // AutoMediaPlaybackPolicy.require_user_action_for_all_media_types, - // ), - // ), - // ); - - // await controller.reload(); - - // await pageLoaded.future; - - // isPaused = await controller.evaluateJavascript('isPaused();'); - // expect(isPaused, _webviewBool(false)); - // }, skip: true /* https://github.com/flutter/flutter/issues/72572 */); - - // testWidgets('Video plays inline when allowsInlineMediaPlayback is true', - // (WidgetTester tester) async { - // Completer controllerCompleter = - // Completer(); - // Completer pageLoaded = Completer(); - - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // javascriptMode: JavascriptMode.unrestricted, - // onPageFinished: (String url) { - // pageLoaded.complete(null); - // }, - // initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, - // allowsInlineMediaPlayback: true, - // ), - // ), - // ); - // WebViewController controller = await controllerCompleter.future; - // await pageLoaded.future; - - // String isFullScreen = - // await controller.evaluateJavascript('isFullScreen();'); - // expect(isFullScreen, _webviewBool(false)); - // }); - - testWidgets('Video plays full screen when allowsInlineMediaPlayback is false', + testWidgets('Auto media playback', (WidgetTester tester) async { + Completer controllerCompleter = + Completer(); + Completer pageLoaded = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: GlobalKey(), + initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + javascriptMode: JavascriptMode.unrestricted, + onPageFinished: (String url) { + pageLoaded.complete(null); + }, + initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, + ), + ), + ); + WebViewController controller = await controllerCompleter.future; + await pageLoaded.future; + + String isPaused = await controller.evaluateJavascript('isPaused();'); + expect(isPaused, _webviewBool(false)); + + controllerCompleter = Completer(); + pageLoaded = Completer(); + + // We change the key to re-create a new webview as we change the initialMediaPlaybackPolicy + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: GlobalKey(), + initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + javascriptMode: JavascriptMode.unrestricted, + onPageFinished: (String url) { + pageLoaded.complete(null); + }, + initialMediaPlaybackPolicy: + AutoMediaPlaybackPolicy.require_user_action_for_all_media_types, + ), + ), + ); + + controller = await controllerCompleter.future; + await pageLoaded.future; + + isPaused = await controller.evaluateJavascript('isPaused();'); + expect(isPaused, _webviewBool(true)); + }, skip: true /* https://github.com/flutter/flutter/issues/72572 */); + + testWidgets('Changes to initialMediaPlaybackPolicy are ignored', + (WidgetTester tester) async { + final Completer controllerCompleter = + Completer(); + Completer pageLoaded = Completer(); + + final GlobalKey key = GlobalKey(); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: key, + initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + javascriptMode: JavascriptMode.unrestricted, + onPageFinished: (String url) { + pageLoaded.complete(null); + }, + initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, + ), + ), + ); + final WebViewController controller = await controllerCompleter.future; + await pageLoaded.future; + + String isPaused = await controller.evaluateJavascript('isPaused();'); + expect(isPaused, _webviewBool(false)); + + pageLoaded = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: key, + initialUrl: 'data:text/html;charset=utf-8;base64,$videoTestBase64', + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + javascriptMode: JavascriptMode.unrestricted, + onPageFinished: (String url) { + pageLoaded.complete(null); + }, + initialMediaPlaybackPolicy: + AutoMediaPlaybackPolicy.require_user_action_for_all_media_types, + ), + ), + ); + + await controller.reload(); + + await pageLoaded.future; + + isPaused = await controller.evaluateJavascript('isPaused();'); + expect(isPaused, _webviewBool(false)); + }, skip: true /* https://github.com/flutter/flutter/issues/72572 */); + + testWidgets('Video plays inline when allowsInlineMediaPlayback is true', (WidgetTester tester) async { Completer controllerCompleter = Completer(); Completer pageLoaded = Completer(); - String message1; - Completer messagesReceived = Completer(); + // String message1; + Completer videoPlaying = Completer(); await tester.pumpWidget( Directionality( @@ -556,38 +503,46 @@ void main() { javascriptMode: JavascriptMode.unrestricted, javascriptChannels: { JavascriptChannel( - name: 'VideoTest', + name: 'VideoTestTime', onMessageReceived: (JavascriptMessage message) { - print(message.message); - // message1 = message.message; - // messagesReceived.complete(message.message); + final double currentTime = double.parse(message.message); + // Let it play for at least 1 second to make sure the related video's properties are set. + if (currentTime > 1) { + videoPlaying.complete(null); + } }, - ),}, + ), + }, onPageFinished: (String url) { pageLoaded.complete(null); }, initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, - allowsInlineMediaPlayback: false, + allowsInlineMediaPlayback: true, ), ), ); WebViewController controller = await controllerCompleter.future; await pageLoaded.future; - // String message = await messagesReceived.future; - // print(message1); - String duration = - await controller.evaluateJavascript('currentTime();'); - // print(duration); + // Pump once to trigger the video play. + await tester.pump(); - String isFullScreen = - await controller.evaluateJavascript('isFullScreen();'); - expect(isFullScreen, _webviewBool(false)); + // Makes sure we get the correct event that indicates the video is actually playing. + await videoPlaying.future; + String fullScreen = + await controller.evaluateJavascript('isFullScreen();'); + expect(fullScreen, _webviewBool(false)); + }); - controllerCompleter = + testWidgets( + 'Video plays full screen when allowsInlineMediaPlayback is false', + (WidgetTester tester) async { + Completer controllerCompleter = Completer(); - pageLoaded = Completer(); + Completer pageLoaded = Completer(); + // String message1; + Completer videoPlaying = Completer(); await tester.pumpWidget( Directionality( @@ -598,823 +553,828 @@ void main() { controllerCompleter.complete(controller); }, javascriptMode: JavascriptMode.unrestricted, - onPageFinished: (String url) { - pageLoaded.complete(null); - }, javascriptChannels: { JavascriptChannel( - name: 'VideoTest', + name: 'VideoTestTime', onMessageReceived: (JavascriptMessage message) { - print(message.message); - if (message.message == 'playing'){ - messagesReceived.complete(message.message); + final double currentTime = double.parse(message.message); + // Let it play for at least 1 second to make sure the related video's properties are set. + if (currentTime > 1) { + videoPlaying.complete(null); } - // message1 = message.message; }, - ),}, + ), + }, + onPageFinished: (String url) { + pageLoaded.complete(null); + }, initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, allowsInlineMediaPlayback: false, ), ), ); - controller = await controllerCompleter.future; + WebViewController controller = await controllerCompleter.future; await pageLoaded.future; - await messagesReceived.future; + // Pump once to trigger the video play. + await tester.pump(); + + // Makes sure we get the correct event that indicates the video is actually playing. + await videoPlaying.future; String fullScreen = await controller.evaluateJavascript('isFullScreen();'); expect(fullScreen, _webviewBool(true)); }); - // }); - - // group('Audio playback policy', () { - // String audioTestBase64; - // setUpAll(() async { - // final ByteData audioData = - // await rootBundle.load('assets/sample_audio.ogg'); - // final String base64AudioData = - // base64Encode(Uint8List.view(audioData.buffer)); - // final String audioTest = ''' - // - // Audio auto play - // - // - // - // - // - // - // '''; - // audioTestBase64 = base64Encode(const Utf8Encoder().convert(audioTest)); - // }); - - // testWidgets('Auto media playback', (WidgetTester tester) async { - // Completer controllerCompleter = - // Completer(); - // Completer pageStarted = Completer(); - // Completer pageLoaded = Completer(); - - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: GlobalKey(), - // initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64', - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // javascriptMode: JavascriptMode.unrestricted, - // onPageStarted: (String url) { - // pageStarted.complete(null); - // }, - // onPageFinished: (String url) { - // pageLoaded.complete(null); - // }, - // initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, - // ), - // ), - // ); - // WebViewController controller = await controllerCompleter.future; - // await pageStarted.future; - // await pageLoaded.future; - - // String isPaused = await controller.evaluateJavascript('isPaused();'); - // expect(isPaused, _webviewBool(false)); - - // controllerCompleter = Completer(); - // pageStarted = Completer(); - // pageLoaded = Completer(); - - // // We change the key to re-create a new webview as we change the initialMediaPlaybackPolicy - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: GlobalKey(), - // initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64', - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // javascriptMode: JavascriptMode.unrestricted, - // onPageStarted: (String url) { - // pageStarted.complete(null); - // }, - // onPageFinished: (String url) { - // pageLoaded.complete(null); - // }, - // initialMediaPlaybackPolicy: - // AutoMediaPlaybackPolicy.require_user_action_for_all_media_types, - // ), - // ), - // ); - - // controller = await controllerCompleter.future; - // await pageStarted.future; - // await pageLoaded.future; - - // isPaused = await controller.evaluateJavascript('isPaused();'); - // expect(isPaused, _webviewBool(true)); - // }, skip: true /* https://github.com/flutter/flutter/issues/72572 */); - - // testWidgets('Changes to initialMediaPlaybackPolocy are ignored', - // (WidgetTester tester) async { - // final Completer controllerCompleter = - // Completer(); - // Completer pageStarted = Completer(); - // Completer pageLoaded = Completer(); - - // final GlobalKey key = GlobalKey(); - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: key, - // initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64', - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // javascriptMode: JavascriptMode.unrestricted, - // onPageStarted: (String url) { - // pageStarted.complete(null); - // }, - // onPageFinished: (String url) { - // pageLoaded.complete(null); - // }, - // initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, - // ), - // ), - // ); - // final WebViewController controller = await controllerCompleter.future; - // await pageStarted.future; - // await pageLoaded.future; - - // String isPaused = await controller.evaluateJavascript('isPaused();'); - // expect(isPaused, _webviewBool(false)); - - // pageStarted = Completer(); - // pageLoaded = Completer(); - - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: key, - // initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64', - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // javascriptMode: JavascriptMode.unrestricted, - // onPageStarted: (String url) { - // pageStarted.complete(null); - // }, - // onPageFinished: (String url) { - // pageLoaded.complete(null); - // }, - // initialMediaPlaybackPolicy: - // AutoMediaPlaybackPolicy.require_user_action_for_all_media_types, - // ), - // ), - // ); - - // await controller.reload(); - - // await pageStarted.future; - // await pageLoaded.future; - - // isPaused = await controller.evaluateJavascript('isPaused();'); - // expect(isPaused, _webviewBool(false)); - // }, skip: true /* https://github.com/flutter/flutter/issues/72572 */); - // }); - - // testWidgets('getTitle', (WidgetTester tester) async { - // final String getTitleTest = ''' - // - // Some title - // - // - // - // - // '''; - // final String getTitleTestBase64 = - // base64Encode(const Utf8Encoder().convert(getTitleTest)); - // final Completer pageStarted = Completer(); - // final Completer pageLoaded = Completer(); - // final Completer controllerCompleter = - // Completer(); - - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // initialUrl: 'data:text/html;charset=utf-8;base64,$getTitleTestBase64', - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // onPageStarted: (String url) { - // pageStarted.complete(null); - // }, - // onPageFinished: (String url) { - // pageLoaded.complete(null); - // }, - // ), - // ), - // ); - - // final WebViewController controller = await controllerCompleter.future; - // await pageStarted.future; - // await pageLoaded.future; - - // final String title = await controller.getTitle(); - // expect(title, 'Some title'); - // }); - - // group('Programmatic Scroll', () { - // testWidgets('setAndGetScrollPosition', (WidgetTester tester) async { - // final String scrollTestPage = ''' - // - // - // - // - // - // - //
- // - // - // '''; - - // final String scrollTestPageBase64 = - // base64Encode(const Utf8Encoder().convert(scrollTestPage)); - - // final Completer pageLoaded = Completer(); - // final Completer controllerCompleter = - // Completer(); - - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // initialUrl: - // 'data:text/html;charset=utf-8;base64,$scrollTestPageBase64', - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // onPageFinished: (String url) { - // pageLoaded.complete(null); - // }, - // ), - // ), - // ); - - // final WebViewController controller = await controllerCompleter.future; - // await pageLoaded.future; - - // await tester.pumpAndSettle(Duration(seconds: 3)); - - // // Check scrollTo() - // const int X_SCROLL = 123; - // const int Y_SCROLL = 321; - - // await controller.scrollTo(X_SCROLL, Y_SCROLL); - // int scrollPosX = await controller.getScrollX(); - // int scrollPosY = await controller.getScrollY(); - // expect(X_SCROLL, scrollPosX); - // expect(Y_SCROLL, scrollPosY); - - // // Check scrollBy() (on top of scrollTo()) - // await controller.scrollBy(X_SCROLL, Y_SCROLL); - // scrollPosX = await controller.getScrollX(); - // scrollPosY = await controller.getScrollY(); - // expect(X_SCROLL * 2, scrollPosX); - // expect(Y_SCROLL * 2, scrollPosY); - // }); - // }); - - // group('SurfaceAndroidWebView', () { - // setUpAll(() { - // WebView.platform = SurfaceAndroidWebView(); - // }); - - // tearDownAll(() { - // WebView.platform = null; - // }); - - // testWidgets('setAndGetScrollPosition', (WidgetTester tester) async { - // final String scrollTestPage = ''' - // - // - // - // - // - // - //
- // - // - // '''; - - // final String scrollTestPageBase64 = - // base64Encode(const Utf8Encoder().convert(scrollTestPage)); - - // final Completer pageLoaded = Completer(); - // final Completer controllerCompleter = - // Completer(); - - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // initialUrl: - // 'data:text/html;charset=utf-8;base64,$scrollTestPageBase64', - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // onPageFinished: (String url) { - // pageLoaded.complete(null); - // }, - // ), - // ), - // ); - - // final WebViewController controller = await controllerCompleter.future; - // await pageLoaded.future; - - // await tester.pumpAndSettle(Duration(seconds: 3)); - - // // Check scrollTo() - // const int X_SCROLL = 123; - // const int Y_SCROLL = 321; - - // await controller.scrollTo(X_SCROLL, Y_SCROLL); - // int scrollPosX = await controller.getScrollX(); - // int scrollPosY = await controller.getScrollY(); - // expect(X_SCROLL, scrollPosX); - // expect(Y_SCROLL, scrollPosY); - - // // Check scrollBy() (on top of scrollTo()) - // await controller.scrollBy(X_SCROLL, Y_SCROLL); - // scrollPosX = await controller.getScrollX(); - // scrollPosY = await controller.getScrollY(); - // expect(X_SCROLL * 2, scrollPosX); - // expect(Y_SCROLL * 2, scrollPosY); - // }, skip: !Platform.isAndroid); - - // testWidgets('inputs are scrolled into view when focused', - // (WidgetTester tester) async { - // final String scrollTestPage = ''' - // - // - // - // - // - // - //
- // - // - // - // '''; - - // final String scrollTestPageBase64 = - // base64Encode(const Utf8Encoder().convert(scrollTestPage)); - - // final Completer pageLoaded = Completer(); - // final Completer controllerCompleter = - // Completer(); - - // await tester.runAsync(() async { - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: SizedBox( - // width: 200, - // height: 200, - // child: WebView( - // initialUrl: - // 'data:text/html;charset=utf-8;base64,$scrollTestPageBase64', - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // onPageFinished: (String url) { - // pageLoaded.complete(null); - // }, - // javascriptMode: JavascriptMode.unrestricted, - // ), - // ), - // ), - // ); - // await Future.delayed(Duration(milliseconds: 20)); - // await tester.pump(); - // }); - - // final WebViewController controller = await controllerCompleter.future; - // await pageLoaded.future; - // final String viewportRectJSON = await _evaluateJavascript( - // controller, 'JSON.stringify(viewport.getBoundingClientRect())'); - // final Map viewportRectRelativeToViewport = - // jsonDecode(viewportRectJSON); - - // // Check that the input is originally outside of the viewport. - - // final String initialInputClientRectJSON = await _evaluateJavascript( - // controller, 'JSON.stringify(inputEl.getBoundingClientRect())'); - // final Map initialInputClientRectRelativeToViewport = - // jsonDecode(initialInputClientRectJSON); - - // expect( - // initialInputClientRectRelativeToViewport['bottom'] <= - // viewportRectRelativeToViewport['bottom'], - // isFalse); - - // await controller.evaluateJavascript('inputEl.focus()'); - - // // Check that focusing the input brought it into view. - - // final String lastInputClientRectJSON = await _evaluateJavascript( - // controller, 'JSON.stringify(inputEl.getBoundingClientRect())'); - // final Map lastInputClientRectRelativeToViewport = - // jsonDecode(lastInputClientRectJSON); - - // expect( - // lastInputClientRectRelativeToViewport['top'] >= - // viewportRectRelativeToViewport['top'], - // isTrue); - // expect( - // lastInputClientRectRelativeToViewport['bottom'] <= - // viewportRectRelativeToViewport['bottom'], - // isTrue); - - // expect( - // lastInputClientRectRelativeToViewport['left'] >= - // viewportRectRelativeToViewport['left'], - // isTrue); - // expect( - // lastInputClientRectRelativeToViewport['right'] <= - // viewportRectRelativeToViewport['right'], - // isTrue); - // }, skip: !Platform.isAndroid); - // }); - - // group('NavigationDelegate', () { - // final String blankPage = ""; - // final String blankPageEncoded = 'data:text/html;charset=utf-8;base64,' + - // base64Encode(const Utf8Encoder().convert(blankPage)); - - // testWidgets('can allow requests', (WidgetTester tester) async { - // final Completer controllerCompleter = - // Completer(); - // final StreamController pageLoads = - // StreamController.broadcast(); - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: GlobalKey(), - // initialUrl: blankPageEncoded, - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // javascriptMode: JavascriptMode.unrestricted, - // navigationDelegate: (NavigationRequest request) { - // return (request.url.contains('youtube.com')) - // ? NavigationDecision.prevent - // : NavigationDecision.navigate; - // }, - // onPageFinished: (String url) => pageLoads.add(url), - // ), - // ), - // ); - - // await pageLoads.stream.first; // Wait for initial page load. - // final WebViewController controller = await controllerCompleter.future; - // await controller - // .evaluateJavascript('location.href = "https://www.google.com/"'); - - // await pageLoads.stream.first; // Wait for the next page load. - // final String currentUrl = await controller.currentUrl(); - // expect(currentUrl, 'https://www.google.com/'); - // }); - - // testWidgets('onWebResourceError', (WidgetTester tester) async { - // final Completer errorCompleter = - // Completer(); - - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: GlobalKey(), - // initialUrl: 'https://www.notawebsite..com', - // onWebResourceError: (WebResourceError error) { - // errorCompleter.complete(error); - // }, - // ), - // ), - // ); - - // final WebResourceError error = await errorCompleter.future; - // expect(error, isNotNull); - - // if (Platform.isIOS) { - // expect(error.domain, isNotNull); - // expect(error.failingUrl, isNull); - // } else if (Platform.isAndroid) { - // expect(error.errorType, isNotNull); - // expect(error.failingUrl.startsWith('https://www.notawebsite..com'), - // isTrue); - // } - // }); - - // testWidgets('onWebResourceError is not called with valid url', - // (WidgetTester tester) async { - // final Completer errorCompleter = - // Completer(); - - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: GlobalKey(), - // initialUrl: - // 'data:text/html;charset=utf-8;base64,PCFET0NUWVBFIGh0bWw+', - // onWebResourceError: (WebResourceError error) { - // errorCompleter.complete(error); - // }, - // ), - // ), - // ); - - // expect(errorCompleter.future, doesNotComplete); - // }); - - // testWidgets('can block requests', (WidgetTester tester) async { - // final Completer controllerCompleter = - // Completer(); - // final StreamController pageLoads = - // StreamController.broadcast(); - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: GlobalKey(), - // initialUrl: blankPageEncoded, - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // javascriptMode: JavascriptMode.unrestricted, - // navigationDelegate: (NavigationRequest request) { - // return (request.url.contains('youtube.com')) - // ? NavigationDecision.prevent - // : NavigationDecision.navigate; - // }, - // onPageFinished: (String url) => pageLoads.add(url), - // ), - // ), - // ); - - // await pageLoads.stream.first; // Wait for initial page load. - // final WebViewController controller = await controllerCompleter.future; - // await controller - // .evaluateJavascript('location.href = "https://www.youtube.com/"'); - - // // There should never be any second page load, since our new URL is - // // blocked. Still wait for a potential page change for some time in order - // // to give the test a chance to fail. - // await pageLoads.stream.first - // .timeout(const Duration(milliseconds: 500), onTimeout: () => null); - // final String currentUrl = await controller.currentUrl(); - // expect(currentUrl, isNot(contains('youtube.com'))); - // }); - - // testWidgets('supports asynchronous decisions', (WidgetTester tester) async { - // final Completer controllerCompleter = - // Completer(); - // final StreamController pageLoads = - // StreamController.broadcast(); - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: GlobalKey(), - // initialUrl: blankPageEncoded, - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // javascriptMode: JavascriptMode.unrestricted, - // navigationDelegate: (NavigationRequest request) async { - // NavigationDecision decision = NavigationDecision.prevent; - // decision = await Future.delayed( - // const Duration(milliseconds: 10), - // () => NavigationDecision.navigate); - // return decision; - // }, - // onPageFinished: (String url) => pageLoads.add(url), - // ), - // ), - // ); - - // await pageLoads.stream.first; // Wait for initial page load. - // final WebViewController controller = await controllerCompleter.future; - // await controller - // .evaluateJavascript('location.href = "https://www.google.com"'); - - // await pageLoads.stream.first; // Wait for second page to load. - // final String currentUrl = await controller.currentUrl(); - // expect(currentUrl, 'https://www.google.com/'); - // }); - // }); - - // testWidgets('launches with gestureNavigationEnabled on iOS', - // (WidgetTester tester) async { - // final Completer controllerCompleter = - // Completer(); - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: SizedBox( - // width: 400, - // height: 300, - // child: WebView( - // key: GlobalKey(), - // initialUrl: 'https://flutter.dev/', - // gestureNavigationEnabled: true, - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // ), - // ), - // ), - // ); - // final WebViewController controller = await controllerCompleter.future; - // final String currentUrl = await controller.currentUrl(); - // expect(currentUrl, 'https://flutter.dev/'); - // }); - - // testWidgets('target _blank opens in same window', - // (WidgetTester tester) async { - // final Completer controllerCompleter = - // Completer(); - // final Completer pageLoaded = Completer(); - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: GlobalKey(), - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // javascriptMode: JavascriptMode.unrestricted, - // onPageFinished: (String url) { - // pageLoaded.complete(null); - // }, - // ), - // ), - // ); - // final WebViewController controller = await controllerCompleter.future; - // await controller.evaluateJavascript('window.open("about:blank", "_blank")'); - // await pageLoaded.future; - // final String currentUrl = await controller.currentUrl(); - // expect(currentUrl, 'about:blank'); - // }); - - // testWidgets( - // 'can open new window and go back', - // (WidgetTester tester) async { - // final Completer controllerCompleter = - // Completer(); - // final Completer pageLoaded = Completer(); - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: GlobalKey(), - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // javascriptMode: JavascriptMode.unrestricted, - // onPageFinished: (String url) { - // pageLoaded.complete(); - // }, - // initialUrl: 'https://flutter.dev', - // ), - // ), - // ); - // final WebViewController controller = await controllerCompleter.future; - // await controller - // .evaluateJavascript('window.open("https://www.google.com")'); - // await pageLoaded.future; - // expect(controller.currentUrl(), completion('https://www.google.com/')); - - // await controller.goBack(); - // expect(controller.currentUrl(), completion('https://www.flutter.dev')); - // }, - // skip: !Platform.isAndroid, - // ); - - // testWidgets( - // 'javascript does not run in parent window', - // (WidgetTester tester) async { - // final String iframe = ''' - // - // - // '''; - // final String iframeTestBase64 = - // base64Encode(const Utf8Encoder().convert(iframe)); - - // final String openWindowTest = ''' - // - // - // - // XSS test - // - // - // - // - // - // '''; - // final String openWindowTestBase64 = - // base64Encode(const Utf8Encoder().convert(openWindowTest)); - // final Completer controllerCompleter = - // Completer(); - // final Completer pageLoadCompleter = Completer(); - - // await tester.pumpWidget( - // Directionality( - // textDirection: TextDirection.ltr, - // child: WebView( - // key: GlobalKey(), - // onWebViewCreated: (WebViewController controller) { - // controllerCompleter.complete(controller); - // }, - // javascriptMode: JavascriptMode.unrestricted, - // initialUrl: - // 'data:text/html;charset=utf-8;base64,$openWindowTestBase64', - // onPageFinished: (String url) { - // pageLoadCompleter.complete(); - // }, - // ), - // ), - // ); - - // final WebViewController controller = await controllerCompleter.future; - // await pageLoadCompleter.future; - - // expect(controller.evaluateJavascript('iframeLoaded'), completion('true')); - // expect( - // controller.evaluateJavascript( - // 'document.querySelector("p") && document.querySelector("p").textContent'), - // completion('null'), - // ); - // }, - // skip: !Platform.isAndroid, - // ); + }); + + group('Audio playback policy', () { + String audioTestBase64; + setUpAll(() async { + final ByteData audioData = + await rootBundle.load('assets/sample_audio.ogg'); + final String base64AudioData = + base64Encode(Uint8List.view(audioData.buffer)); + final String audioTest = ''' + + Audio auto play + + + + + + + '''; + audioTestBase64 = base64Encode(const Utf8Encoder().convert(audioTest)); + }); + + testWidgets('Auto media playback', (WidgetTester tester) async { + Completer controllerCompleter = + Completer(); + Completer pageStarted = Completer(); + Completer pageLoaded = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: GlobalKey(), + initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64', + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + javascriptMode: JavascriptMode.unrestricted, + onPageStarted: (String url) { + pageStarted.complete(null); + }, + onPageFinished: (String url) { + pageLoaded.complete(null); + }, + initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, + ), + ), + ); + WebViewController controller = await controllerCompleter.future; + await pageStarted.future; + await pageLoaded.future; + + String isPaused = await controller.evaluateJavascript('isPaused();'); + expect(isPaused, _webviewBool(false)); + + controllerCompleter = Completer(); + pageStarted = Completer(); + pageLoaded = Completer(); + + // We change the key to re-create a new webview as we change the initialMediaPlaybackPolicy + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: GlobalKey(), + initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64', + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + javascriptMode: JavascriptMode.unrestricted, + onPageStarted: (String url) { + pageStarted.complete(null); + }, + onPageFinished: (String url) { + pageLoaded.complete(null); + }, + initialMediaPlaybackPolicy: + AutoMediaPlaybackPolicy.require_user_action_for_all_media_types, + ), + ), + ); + + controller = await controllerCompleter.future; + await pageStarted.future; + await pageLoaded.future; + + isPaused = await controller.evaluateJavascript('isPaused();'); + expect(isPaused, _webviewBool(true)); + }, skip: true /* https://github.com/flutter/flutter/issues/72572 */); + + testWidgets('Changes to initialMediaPlaybackPolocy are ignored', + (WidgetTester tester) async { + final Completer controllerCompleter = + Completer(); + Completer pageStarted = Completer(); + Completer pageLoaded = Completer(); + + final GlobalKey key = GlobalKey(); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: key, + initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64', + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + javascriptMode: JavascriptMode.unrestricted, + onPageStarted: (String url) { + pageStarted.complete(null); + }, + onPageFinished: (String url) { + pageLoaded.complete(null); + }, + initialMediaPlaybackPolicy: AutoMediaPlaybackPolicy.always_allow, + ), + ), + ); + final WebViewController controller = await controllerCompleter.future; + await pageStarted.future; + await pageLoaded.future; + + String isPaused = await controller.evaluateJavascript('isPaused();'); + expect(isPaused, _webviewBool(false)); + + pageStarted = Completer(); + pageLoaded = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: key, + initialUrl: 'data:text/html;charset=utf-8;base64,$audioTestBase64', + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + javascriptMode: JavascriptMode.unrestricted, + onPageStarted: (String url) { + pageStarted.complete(null); + }, + onPageFinished: (String url) { + pageLoaded.complete(null); + }, + initialMediaPlaybackPolicy: + AutoMediaPlaybackPolicy.require_user_action_for_all_media_types, + ), + ), + ); + + await controller.reload(); + + await pageStarted.future; + await pageLoaded.future; + + isPaused = await controller.evaluateJavascript('isPaused();'); + expect(isPaused, _webviewBool(false)); + }, skip: true /* https://github.com/flutter/flutter/issues/72572 */); + }); + + testWidgets('getTitle', (WidgetTester tester) async { + final String getTitleTest = ''' + + Some title + + + + + '''; + final String getTitleTestBase64 = + base64Encode(const Utf8Encoder().convert(getTitleTest)); + final Completer pageStarted = Completer(); + final Completer pageLoaded = Completer(); + final Completer controllerCompleter = + Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + initialUrl: 'data:text/html;charset=utf-8;base64,$getTitleTestBase64', + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + onPageStarted: (String url) { + pageStarted.complete(null); + }, + onPageFinished: (String url) { + pageLoaded.complete(null); + }, + ), + ), + ); + + final WebViewController controller = await controllerCompleter.future; + await pageStarted.future; + await pageLoaded.future; + + final String title = await controller.getTitle(); + expect(title, 'Some title'); + }); + + group('Programmatic Scroll', () { + testWidgets('setAndGetScrollPosition', (WidgetTester tester) async { + final String scrollTestPage = ''' + + + + + + +
+ + + '''; + + final String scrollTestPageBase64 = + base64Encode(const Utf8Encoder().convert(scrollTestPage)); + + final Completer pageLoaded = Completer(); + final Completer controllerCompleter = + Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + initialUrl: + 'data:text/html;charset=utf-8;base64,$scrollTestPageBase64', + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + onPageFinished: (String url) { + pageLoaded.complete(null); + }, + ), + ), + ); + + final WebViewController controller = await controllerCompleter.future; + await pageLoaded.future; + + await tester.pumpAndSettle(Duration(seconds: 3)); + + // Check scrollTo() + const int X_SCROLL = 123; + const int Y_SCROLL = 321; + + await controller.scrollTo(X_SCROLL, Y_SCROLL); + int scrollPosX = await controller.getScrollX(); + int scrollPosY = await controller.getScrollY(); + expect(X_SCROLL, scrollPosX); + expect(Y_SCROLL, scrollPosY); + + // Check scrollBy() (on top of scrollTo()) + await controller.scrollBy(X_SCROLL, Y_SCROLL); + scrollPosX = await controller.getScrollX(); + scrollPosY = await controller.getScrollY(); + expect(X_SCROLL * 2, scrollPosX); + expect(Y_SCROLL * 2, scrollPosY); + }); + }); + + group('SurfaceAndroidWebView', () { + setUpAll(() { + WebView.platform = SurfaceAndroidWebView(); + }); + + tearDownAll(() { + WebView.platform = null; + }); + + testWidgets('setAndGetScrollPosition', (WidgetTester tester) async { + final String scrollTestPage = ''' + + + + + + +
+ + + '''; + + final String scrollTestPageBase64 = + base64Encode(const Utf8Encoder().convert(scrollTestPage)); + + final Completer pageLoaded = Completer(); + final Completer controllerCompleter = + Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + initialUrl: + 'data:text/html;charset=utf-8;base64,$scrollTestPageBase64', + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + onPageFinished: (String url) { + pageLoaded.complete(null); + }, + ), + ), + ); + + final WebViewController controller = await controllerCompleter.future; + await pageLoaded.future; + + await tester.pumpAndSettle(Duration(seconds: 3)); + + // Check scrollTo() + const int X_SCROLL = 123; + const int Y_SCROLL = 321; + + await controller.scrollTo(X_SCROLL, Y_SCROLL); + int scrollPosX = await controller.getScrollX(); + int scrollPosY = await controller.getScrollY(); + expect(X_SCROLL, scrollPosX); + expect(Y_SCROLL, scrollPosY); + + // Check scrollBy() (on top of scrollTo()) + await controller.scrollBy(X_SCROLL, Y_SCROLL); + scrollPosX = await controller.getScrollX(); + scrollPosY = await controller.getScrollY(); + expect(X_SCROLL * 2, scrollPosX); + expect(Y_SCROLL * 2, scrollPosY); + }, skip: !Platform.isAndroid); + + testWidgets('inputs are scrolled into view when focused', + (WidgetTester tester) async { + final String scrollTestPage = ''' + + + + + + +
+ + + + '''; + + final String scrollTestPageBase64 = + base64Encode(const Utf8Encoder().convert(scrollTestPage)); + + final Completer pageLoaded = Completer(); + final Completer controllerCompleter = + Completer(); + + await tester.runAsync(() async { + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: SizedBox( + width: 200, + height: 200, + child: WebView( + initialUrl: + 'data:text/html;charset=utf-8;base64,$scrollTestPageBase64', + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + onPageFinished: (String url) { + pageLoaded.complete(null); + }, + javascriptMode: JavascriptMode.unrestricted, + ), + ), + ), + ); + await Future.delayed(Duration(milliseconds: 20)); + await tester.pump(); + }); + + final WebViewController controller = await controllerCompleter.future; + await pageLoaded.future; + final String viewportRectJSON = await _evaluateJavascript( + controller, 'JSON.stringify(viewport.getBoundingClientRect())'); + final Map viewportRectRelativeToViewport = + jsonDecode(viewportRectJSON); + + // Check that the input is originally outside of the viewport. + + final String initialInputClientRectJSON = await _evaluateJavascript( + controller, 'JSON.stringify(inputEl.getBoundingClientRect())'); + final Map initialInputClientRectRelativeToViewport = + jsonDecode(initialInputClientRectJSON); + + expect( + initialInputClientRectRelativeToViewport['bottom'] <= + viewportRectRelativeToViewport['bottom'], + isFalse); + + await controller.evaluateJavascript('inputEl.focus()'); + + // Check that focusing the input brought it into view. + + final String lastInputClientRectJSON = await _evaluateJavascript( + controller, 'JSON.stringify(inputEl.getBoundingClientRect())'); + final Map lastInputClientRectRelativeToViewport = + jsonDecode(lastInputClientRectJSON); + + expect( + lastInputClientRectRelativeToViewport['top'] >= + viewportRectRelativeToViewport['top'], + isTrue); + expect( + lastInputClientRectRelativeToViewport['bottom'] <= + viewportRectRelativeToViewport['bottom'], + isTrue); + + expect( + lastInputClientRectRelativeToViewport['left'] >= + viewportRectRelativeToViewport['left'], + isTrue); + expect( + lastInputClientRectRelativeToViewport['right'] <= + viewportRectRelativeToViewport['right'], + isTrue); + }, skip: !Platform.isAndroid); + }); + + group('NavigationDelegate', () { + final String blankPage = ""; + final String blankPageEncoded = 'data:text/html;charset=utf-8;base64,' + + base64Encode(const Utf8Encoder().convert(blankPage)); + + testWidgets('can allow requests', (WidgetTester tester) async { + final Completer controllerCompleter = + Completer(); + final StreamController pageLoads = + StreamController.broadcast(); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: GlobalKey(), + initialUrl: blankPageEncoded, + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + javascriptMode: JavascriptMode.unrestricted, + navigationDelegate: (NavigationRequest request) { + return (request.url.contains('youtube.com')) + ? NavigationDecision.prevent + : NavigationDecision.navigate; + }, + onPageFinished: (String url) => pageLoads.add(url), + ), + ), + ); + + await pageLoads.stream.first; // Wait for initial page load. + final WebViewController controller = await controllerCompleter.future; + await controller + .evaluateJavascript('location.href = "https://www.google.com/"'); + + await pageLoads.stream.first; // Wait for the next page load. + final String currentUrl = await controller.currentUrl(); + expect(currentUrl, 'https://www.google.com/'); + }); + + testWidgets('onWebResourceError', (WidgetTester tester) async { + final Completer errorCompleter = + Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: GlobalKey(), + initialUrl: 'https://www.notawebsite..com', + onWebResourceError: (WebResourceError error) { + errorCompleter.complete(error); + }, + ), + ), + ); + + final WebResourceError error = await errorCompleter.future; + expect(error, isNotNull); + + if (Platform.isIOS) { + expect(error.domain, isNotNull); + expect(error.failingUrl, isNull); + } else if (Platform.isAndroid) { + expect(error.errorType, isNotNull); + expect(error.failingUrl.startsWith('https://www.notawebsite..com'), + isTrue); + } + }); + + testWidgets('onWebResourceError is not called with valid url', + (WidgetTester tester) async { + final Completer errorCompleter = + Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: GlobalKey(), + initialUrl: + 'data:text/html;charset=utf-8;base64,PCFET0NUWVBFIGh0bWw+', + onWebResourceError: (WebResourceError error) { + errorCompleter.complete(error); + }, + ), + ), + ); + + expect(errorCompleter.future, doesNotComplete); + }); + + testWidgets('can block requests', (WidgetTester tester) async { + final Completer controllerCompleter = + Completer(); + final StreamController pageLoads = + StreamController.broadcast(); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: GlobalKey(), + initialUrl: blankPageEncoded, + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + javascriptMode: JavascriptMode.unrestricted, + navigationDelegate: (NavigationRequest request) { + return (request.url.contains('youtube.com')) + ? NavigationDecision.prevent + : NavigationDecision.navigate; + }, + onPageFinished: (String url) => pageLoads.add(url), + ), + ), + ); + + await pageLoads.stream.first; // Wait for initial page load. + final WebViewController controller = await controllerCompleter.future; + await controller + .evaluateJavascript('location.href = "https://www.youtube.com/"'); + + // There should never be any second page load, since our new URL is + // blocked. Still wait for a potential page change for some time in order + // to give the test a chance to fail. + await pageLoads.stream.first + .timeout(const Duration(milliseconds: 500), onTimeout: () => null); + final String currentUrl = await controller.currentUrl(); + expect(currentUrl, isNot(contains('youtube.com'))); + }); + + testWidgets('supports asynchronous decisions', (WidgetTester tester) async { + final Completer controllerCompleter = + Completer(); + final StreamController pageLoads = + StreamController.broadcast(); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: GlobalKey(), + initialUrl: blankPageEncoded, + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + javascriptMode: JavascriptMode.unrestricted, + navigationDelegate: (NavigationRequest request) async { + NavigationDecision decision = NavigationDecision.prevent; + decision = await Future.delayed( + const Duration(milliseconds: 10), + () => NavigationDecision.navigate); + return decision; + }, + onPageFinished: (String url) => pageLoads.add(url), + ), + ), + ); + + await pageLoads.stream.first; // Wait for initial page load. + final WebViewController controller = await controllerCompleter.future; + await controller + .evaluateJavascript('location.href = "https://www.google.com"'); + + await pageLoads.stream.first; // Wait for second page to load. + final String currentUrl = await controller.currentUrl(); + expect(currentUrl, 'https://www.google.com/'); + }); + }); + + testWidgets('launches with gestureNavigationEnabled on iOS', + (WidgetTester tester) async { + final Completer controllerCompleter = + Completer(); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: SizedBox( + width: 400, + height: 300, + child: WebView( + key: GlobalKey(), + initialUrl: 'https://flutter.dev/', + gestureNavigationEnabled: true, + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + ), + ), + ), + ); + final WebViewController controller = await controllerCompleter.future; + final String currentUrl = await controller.currentUrl(); + expect(currentUrl, 'https://flutter.dev/'); + }); + + testWidgets('target _blank opens in same window', + (WidgetTester tester) async { + final Completer controllerCompleter = + Completer(); + final Completer pageLoaded = Completer(); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: GlobalKey(), + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + javascriptMode: JavascriptMode.unrestricted, + onPageFinished: (String url) { + pageLoaded.complete(null); + }, + ), + ), + ); + final WebViewController controller = await controllerCompleter.future; + await controller.evaluateJavascript('window.open("about:blank", "_blank")'); + await pageLoaded.future; + final String currentUrl = await controller.currentUrl(); + expect(currentUrl, 'about:blank'); + }); + + testWidgets( + 'can open new window and go back', + (WidgetTester tester) async { + final Completer controllerCompleter = + Completer(); + final Completer pageLoaded = Completer(); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: GlobalKey(), + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + javascriptMode: JavascriptMode.unrestricted, + onPageFinished: (String url) { + pageLoaded.complete(); + }, + initialUrl: 'https://flutter.dev', + ), + ), + ); + final WebViewController controller = await controllerCompleter.future; + await controller + .evaluateJavascript('window.open("https://www.google.com")'); + await pageLoaded.future; + expect(controller.currentUrl(), completion('https://www.google.com/')); + + await controller.goBack(); + expect(controller.currentUrl(), completion('https://www.flutter.dev')); + }, + skip: !Platform.isAndroid, + ); + + testWidgets( + 'javascript does not run in parent window', + (WidgetTester tester) async { + final String iframe = ''' + + + '''; + final String iframeTestBase64 = + base64Encode(const Utf8Encoder().convert(iframe)); + + final String openWindowTest = ''' + + + + XSS test + + + + + + '''; + final String openWindowTestBase64 = + base64Encode(const Utf8Encoder().convert(openWindowTest)); + final Completer controllerCompleter = + Completer(); + final Completer pageLoadCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: WebView( + key: GlobalKey(), + onWebViewCreated: (WebViewController controller) { + controllerCompleter.complete(controller); + }, + javascriptMode: JavascriptMode.unrestricted, + initialUrl: + 'data:text/html;charset=utf-8;base64,$openWindowTestBase64', + onPageFinished: (String url) { + pageLoadCompleter.complete(); + }, + ), + ), + ); + + final WebViewController controller = await controllerCompleter.future; + await pageLoadCompleter.future; + + expect(controller.evaluateJavascript('iframeLoaded'), completion('true')); + expect( + controller.evaluateJavascript( + 'document.querySelector("p") && document.querySelector("p").textContent'), + completion('null'), + ); + }, + skip: !Platform.isAndroid, + ); } // JavaScript booleans evaluate to different string values on Android and iOS. diff --git a/packages/webview_flutter/ios/Classes/FlutterWebView.m b/packages/webview_flutter/ios/Classes/FlutterWebView.m index b0e6f3afed85..73ca5b0f71ad 100644 --- a/packages/webview_flutter/ios/Classes/FlutterWebView.m +++ b/packages/webview_flutter/ios/Classes/FlutterWebView.m @@ -93,7 +93,6 @@ - (instancetype)initWithFrame:(CGRect)frame configuration.userContentController = userContentController; [self updateAutoMediaPlaybackPolicy:args[@"autoMediaPlaybackPolicy"] inConfiguration:configuration]; - NSLog(@"configuration %@", @(configuration.allowsInlineMediaPlayback)); _webView = [[FLTWKWebView alloc] initWithFrame:frame configuration:configuration]; _navigationDelegate = [[FLTWKNavigationDelegate alloc] initWithChannel:_channel]; From d19923e1edae61e245737aa11c1e7af8507c359b Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Tue, 6 Apr 2021 17:07:58 -0700 Subject: [PATCH 4/9] enable skipped tests --- .../example/integration_test/webview_flutter_test.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/webview_flutter/example/integration_test/webview_flutter_test.dart b/packages/webview_flutter/example/integration_test/webview_flutter_test.dart index 4de507202997..51a24bd27a5e 100644 --- a/packages/webview_flutter/example/integration_test/webview_flutter_test.dart +++ b/packages/webview_flutter/example/integration_test/webview_flutter_test.dart @@ -423,7 +423,7 @@ void main() { isPaused = await controller.evaluateJavascript('isPaused();'); expect(isPaused, _webviewBool(true)); - }, skip: true /* https://github.com/flutter/flutter/issues/72572 */); + }); testWidgets('Changes to initialMediaPlaybackPolicy are ignored', (WidgetTester tester) async { @@ -482,7 +482,7 @@ void main() { isPaused = await controller.evaluateJavascript('isPaused();'); expect(isPaused, _webviewBool(false)); - }, skip: true /* https://github.com/flutter/flutter/issues/72572 */); + }); testWidgets('Video plays inline when allowsInlineMediaPlayback is true', (WidgetTester tester) async { @@ -685,7 +685,7 @@ void main() { isPaused = await controller.evaluateJavascript('isPaused();'); expect(isPaused, _webviewBool(true)); - }, skip: true /* https://github.com/flutter/flutter/issues/72572 */); + }); testWidgets('Changes to initialMediaPlaybackPolocy are ignored', (WidgetTester tester) async { @@ -754,7 +754,7 @@ void main() { isPaused = await controller.evaluateJavascript('isPaused();'); expect(isPaused, _webviewBool(false)); - }, skip: true /* https://github.com/flutter/flutter/issues/72572 */); + }); }); testWidgets('getTitle', (WidgetTester tester) async { From 0b5ba7c117083f822d339149210b2688efc197f1 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Tue, 6 Apr 2021 17:09:04 -0700 Subject: [PATCH 5/9] format --- packages/webview_flutter/ios/Classes/FlutterWebView.m | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/webview_flutter/ios/Classes/FlutterWebView.m b/packages/webview_flutter/ios/Classes/FlutterWebView.m index 73ca5b0f71ad..e44832a09aa4 100644 --- a/packages/webview_flutter/ios/Classes/FlutterWebView.m +++ b/packages/webview_flutter/ios/Classes/FlutterWebView.m @@ -359,8 +359,10 @@ - (NSString*)applySettings:(NSDictionary*)settings { [unknownKeys componentsJoinedByString:@", "]]; } -- (void)applyConfigurationSetting:(NSDictionary*)settings inConfiguration:(WKWebViewConfiguration*)configuration { - NSAssert(configuration != _webView.configuration, @"configuration needs to be updated before webView.configuration."); +- (void)applyConfigurationSetting:(NSDictionary*)settings + inConfiguration:(WKWebViewConfiguration*)configuration { + NSAssert(configuration != _webView.configuration, + @"configuration needs to be updated before webView.configuration."); for (NSString* key in settings) { if ([key isEqualToString:@"allowsInlineMediaPlayback"]) { NSNumber* allowsInlineMediaPlayback = settings[key]; From bb1afa1bee982f5e27fc8d20a145f9b2632b8669 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Tue, 6 Apr 2021 17:12:27 -0700 Subject: [PATCH 6/9] version --- packages/webview_flutter/CHANGELOG.md | 4 ++++ packages/webview_flutter/pubspec.yaml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/webview_flutter/CHANGELOG.md b/packages/webview_flutter/CHANGELOG.md index b8e5e0bba5e0..85767577c403 100644 --- a/packages/webview_flutter/CHANGELOG.md +++ b/packages/webview_flutter/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.0.4 + +* Fix a bug where `allowsInlineMediaPlayback` is not respected on iOS. + ## 2.0.3 * Fixes bug where scroll bars on the Android non-hybrid WebView are rendered on diff --git a/packages/webview_flutter/pubspec.yaml b/packages/webview_flutter/pubspec.yaml index a89ded4e9014..f4fb0efe83e2 100644 --- a/packages/webview_flutter/pubspec.yaml +++ b/packages/webview_flutter/pubspec.yaml @@ -1,7 +1,7 @@ name: webview_flutter description: A Flutter plugin that provides a WebView widget on Android and iOS. homepage: https://github.com/flutter/plugins/tree/master/packages/webview_flutter -version: 2.0.3 +version: 2.0.4 environment: sdk: ">=2.12.0-259.9.beta <3.0.0" From 01b8d80297fdda601e9a96bd7b7a21c225b6c788 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Tue, 6 Apr 2021 19:39:25 -0700 Subject: [PATCH 7/9] review --- .../example/integration_test/webview_flutter_test.dart | 2 -- packages/webview_flutter/ios/Classes/FlutterWebView.m | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/webview_flutter/example/integration_test/webview_flutter_test.dart b/packages/webview_flutter/example/integration_test/webview_flutter_test.dart index 51a24bd27a5e..408eec5730df 100644 --- a/packages/webview_flutter/example/integration_test/webview_flutter_test.dart +++ b/packages/webview_flutter/example/integration_test/webview_flutter_test.dart @@ -489,7 +489,6 @@ void main() { Completer controllerCompleter = Completer(); Completer pageLoaded = Completer(); - // String message1; Completer videoPlaying = Completer(); await tester.pumpWidget( @@ -541,7 +540,6 @@ void main() { Completer controllerCompleter = Completer(); Completer pageLoaded = Completer(); - // String message1; Completer videoPlaying = Completer(); await tester.pumpWidget( diff --git a/packages/webview_flutter/ios/Classes/FlutterWebView.m b/packages/webview_flutter/ios/Classes/FlutterWebView.m index e44832a09aa4..873fc9e195d3 100644 --- a/packages/webview_flutter/ios/Classes/FlutterWebView.m +++ b/packages/webview_flutter/ios/Classes/FlutterWebView.m @@ -359,8 +359,8 @@ - (NSString*)applySettings:(NSDictionary*)settings { [unknownKeys componentsJoinedByString:@", "]]; } -- (void)applyConfigurationSetting:(NSDictionary*)settings - inConfiguration:(WKWebViewConfiguration*)configuration { +- (void)applyConfigurationSettings:(NSDictionary*)settings + toConfiguration:(WKWebViewConfiguration*)configuration { NSAssert(configuration != _webView.configuration, @"configuration needs to be updated before webView.configuration."); for (NSString* key in settings) { From d2da73b05e57f48ca56f1504a458cabe4c4ee2e2 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Tue, 6 Apr 2021 19:45:33 -0700 Subject: [PATCH 8/9] fix --- packages/webview_flutter/ios/Classes/FlutterWebView.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/webview_flutter/ios/Classes/FlutterWebView.m b/packages/webview_flutter/ios/Classes/FlutterWebView.m index 873fc9e195d3..6651a07cafb8 100644 --- a/packages/webview_flutter/ios/Classes/FlutterWebView.m +++ b/packages/webview_flutter/ios/Classes/FlutterWebView.m @@ -89,7 +89,7 @@ - (instancetype)initWithFrame:(CGRect)frame NSDictionary* settings = args[@"settings"]; WKWebViewConfiguration* configuration = [[WKWebViewConfiguration alloc] init]; - [self applyConfigurationSetting:settings inConfiguration:configuration]; + [self applyConfigurationSettings:settings toConfiguration:configuration]; configuration.userContentController = userContentController; [self updateAutoMediaPlaybackPolicy:args[@"autoMediaPlaybackPolicy"] inConfiguration:configuration]; From 6d6ee461d091c04152566c038f7954b786b8eff7 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Tue, 6 Apr 2021 20:05:24 -0700 Subject: [PATCH 9/9] format --- packages/webview_flutter/ios/Classes/FlutterWebView.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/webview_flutter/ios/Classes/FlutterWebView.m b/packages/webview_flutter/ios/Classes/FlutterWebView.m index 6651a07cafb8..8f4053a0b822 100644 --- a/packages/webview_flutter/ios/Classes/FlutterWebView.m +++ b/packages/webview_flutter/ios/Classes/FlutterWebView.m @@ -360,7 +360,7 @@ - (NSString*)applySettings:(NSDictionary*)settings { } - (void)applyConfigurationSettings:(NSDictionary*)settings - toConfiguration:(WKWebViewConfiguration*)configuration { + toConfiguration:(WKWebViewConfiguration*)configuration { NSAssert(configuration != _webView.configuration, @"configuration needs to be updated before webView.configuration."); for (NSString* key in settings) {