fixed web support, updated tests

This commit is contained in:
Lorenzo Pichilli 2022-04-30 21:22:31 +02:00
parent abcc3a3415
commit f728248dbd
39 changed files with 122 additions and 68 deletions

2
example/.gitignore vendored
View File

@ -71,4 +71,4 @@ build/
!**/ios/**/default.perspectivev3
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
integration_test/.env.dart
integration_test/env.dart

View File

@ -1,3 +1,4 @@
import 'package:flutter/foundation.dart';
import 'package:flutter_test/flutter_test.dart';
import 'custom_action_button.dart';
@ -7,11 +8,13 @@ import 'open_and_close.dart';
import 'trusted_web_activity.dart';
void main() {
final shouldSkip = kIsWeb;
group('ChromeSafariBrowser', () {
openAndClose();
customMenuItem();
customActionButton();
customTabs();
trustedWebActivity();
});
}, skip: shouldSkip);
}

View File

@ -1,9 +1,12 @@
import 'package:flutter/foundation.dart';
import 'package:flutter_test/flutter_test.dart';
import 'set_get_delete.dart';
void main() {
final shouldSkip = kIsWeb;
group('Cookie Manager', () {
setGetDelete();
});
}, skip: shouldSkip);
}

View File

@ -1,3 +1,4 @@
import 'package:flutter/foundation.dart';
import 'package:flutter_test/flutter_test.dart';
import 'open_data_and_close.dart';
@ -6,10 +7,12 @@ import 'open_url_and_close.dart';
import 'set_get_settings.dart';
void main() {
final shouldSkip = kIsWeb;
group('InAppBrowser', () {
openUrlAndClose();
openFileAndClose();
openDataAndClose();
setGetSettings();
});
}, skip: shouldSkip);
}

View File

@ -1,9 +1,12 @@
import 'package:flutter/foundation.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:flutter_test/flutter_test.dart';
import 'load_asset_file.dart';
void main() {
final shouldSkip = kIsWeb;
group('InAppLocalhostServer', () {
final InAppLocalhostServer localhostServer = InAppLocalhostServer();
@ -16,5 +19,5 @@ void main() {
tearDownAll(() async {
await localhostServer.close();
});
});
}, skip: shouldSkip);
}

View File

@ -41,6 +41,8 @@ void getContentHeight() {
final InAppWebViewController controller = await controllerCompleter.future;
await pageLoaded.future;
await tester.pump();
final contentHeight = await controller.getContentHeight();
expect(contentHeight, isNonZero);
expect(contentHeight, isPositive);

View File

@ -5,7 +5,7 @@ import 'package:flutter/widgets.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:flutter_test/flutter_test.dart';
import '../.env.dart';
import '../env.dart';
void httpAuthCredentialDatabase() {
final shouldSkip = kIsWeb

View File

@ -6,7 +6,7 @@ import 'package:flutter/widgets.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:flutter_test/flutter_test.dart';
import '../.env.dart';
import '../env.dart';
void interceptAjaxRequest() {
final shouldSkip = kIsWeb

View File

@ -6,7 +6,7 @@ import 'package:flutter/widgets.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:flutter_test/flutter_test.dart';
import '../.env.dart';
import '../env.dart';
void interceptFetchRequest() {
final shouldSkip = kIsWeb

View File

@ -5,7 +5,7 @@ import 'package:flutter/widgets.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:flutter_test/flutter_test.dart';
import '../.env.dart';
import '../env.dart';
void onDownloadStartRequest() {
final shouldSkip = kIsWeb

View File

@ -46,8 +46,9 @@ void onScrollChanged() {
final InAppWebViewController controller = await controllerCompleter.future;
await pageLoaded.future;
await tester.pump();
controller.scrollTo(x: 0, y: 500);
await tester.pumpAndSettle(Duration(seconds: 1));
await expectLater(onScrollChangedCompleter.future, completes);
}, skip: shouldSkip);

View File

@ -46,6 +46,7 @@ void onTitleChanged() {
final InAppWebViewController controller = await controllerCompleter.future;
await pageLoaded.future;
await tester.pump();
await controller.evaluateJavascript(
source: "document.title = 'title test';");
await expectLater(onTitleChangedCompleter.future, completes);

View File

@ -7,7 +7,7 @@ import 'package:flutter/widgets.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:flutter_test/flutter_test.dart';
import '../.env.dart';
import '../env.dart';
void postRequests() {
final shouldSkip = kIsWeb

View File

@ -5,7 +5,7 @@ import 'package:flutter/widgets.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:flutter_test/flutter_test.dart';
import '../.env.dart';
import '../env.dart';
void sslRequest() {
final shouldSkip = kIsWeb

View File

@ -147,11 +147,12 @@ void webHistory() {
final InAppWebViewController controller =
await controllerCompleter.future;
await tester.pump();
var url = await pageLoads.stream.first;
expect(url, TEST_WEB_PLATFORM_URL_1.toString());
await controller.loadUrl(
urlRequest: URLRequest(url: TEST_WEB_PLATFORM_URL_2));
await controller.evaluateJavascript(source: "document.getElementById('link-page-2').click();");
url = await pageLoads.stream.first;
expect(url, TEST_WEB_PLATFORM_URL_2.toString());

View File

@ -303,8 +303,9 @@ void webViewWindows() {
);
}, skip: shouldSkipTest5);
final shouldSkipTest6 = !kIsWeb;
// final shouldSkipTest6 = !kIsWeb;
final shouldSkipTest6 = true;
// on Web, opening a new window during tests makes crash
testWidgets('onCreateWindow called on Web', (WidgetTester tester) async {
final Completer controllerCompleter = Completer<InAppWebViewController>();
final Completer<String> onCreateWindowCalled = Completer<String>();
@ -333,7 +334,7 @@ void webViewWindows() {
final InAppWebViewController controller =
await controllerCompleter.future;
await controller.evaluateJavascript(
source: "window.open('$TEST_CROSS_PLATFORM_URL_1')");
source: "window.open('$TEST_CROSS_PLATFORM_URL_1');");
var url = await onCreateWindowCalled.future;
expect(url, TEST_CROSS_PLATFORM_URL_1.toString());

View File

@ -1,11 +1,14 @@
import 'package:flutter/foundation.dart';
import 'package:flutter_test/flutter_test.dart';
import 'set_service_worker_client.dart';
import 'should_intercept_request.dart';
void main() {
final shouldSkip = kIsWeb;
group('Service Worker', () {
shouldInterceptRequest();
setServiceWorkerClient();
});
}, skip: shouldSkip);
}

View File

@ -3,11 +3,12 @@
export "FLUTTER_ROOT=/Users/lorenzopichilli/fvm/versions/2.10.4"
export "FLUTTER_APPLICATION_PATH=/Users/lorenzopichilli/Desktop/flutter_inappwebview/example"
export "COCOAPODS_PARALLEL_CODE_SIGN=true"
export "FLUTTER_TARGET=lib/main.dart"
export "FLUTTER_TARGET=integration_test/webview_flutter_test.dart"
export "FLUTTER_BUILD_DIR=build"
export "FLUTTER_BUILD_NAME=1.0.0"
export "FLUTTER_BUILD_NUMBER=1"
export "DART_DEFINES=RkxVVFRFUl9XRUJfQVVUT19ERVRFQ1Q9dHJ1ZQ=="
export "DART_OBFUSCATION=false"
export "TRACK_WIDGET_CREATION=false"
export "TRACK_WIDGET_CREATION=true"
export "TREE_SHAKE_ICONS=false"
export "PACKAGE_CONFIG=.packages"
export "PACKAGE_CONFIG=/Users/lorenzopichilli/Desktop/flutter_inappwebview/example/.dart_tool/package_config.json"

View File

@ -21,7 +21,7 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
mediaPlaybackRequiresUserGesture: false,
allowsInlineMediaPlayback: true,
iframeAllow: "camera; microphone",
iframeAllowFullscreen: true,
iframeAllowFullscreen: true
);
PullToRefreshController? pullToRefreshController;
@ -113,16 +113,16 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
children: [
InAppWebView(
key: webViewKey,
initialUrlRequest:
URLRequest(url: Uri.parse("https://flutter.dev")),
// initialUrlRequest:
// URLRequest(url: Uri.parse(Uri.base.toString().replaceFirst("/#/", "/") + 'page.html')),
// URLRequest(url: Uri.parse("https://flutter.dev")),
initialUrlRequest:
URLRequest(url: Uri.parse(Uri.base.toString().replaceFirst("/#/", "/") + 'page.html')),
// initialFile: "assets/index.html",
initialUserScripts: UnmodifiableListView<UserScript>([]),
initialSettings: settings,
// contextMenu: contextMenu,
pullToRefreshController: pullToRefreshController,
onWebViewCreated: (controller) {
onWebViewCreated: (controller) async {
webViewController = controller;
},
onLoadStart: (controller, url) async {
@ -167,7 +167,6 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
this.url = url.toString();
urlController.text = this.url;
});
print("getContentHeight: " + (await controller.getContentHeight()).toString());
},
onLoadError: (controller, url, code, message) {
pullToRefreshController?.endRefreshing();
@ -218,12 +217,6 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
webViewController?.reload();
},
),
ElevatedButton(
child: Icon(Icons.refresh),
onPressed: () {
webViewController?.evaluateJavascript(source: "window.open('https://github.com/flutter');");
},
),
],
),
])));

View File

@ -12,6 +12,7 @@
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-title" content="flutter_inappwebview_example">
<link rel="apple-touch-icon" href="icons/Icon-192.png">
<meta name="theme-color" content="#0175C2">
<!-- Favicon -->
<link rel="icon" type="image/png" href="favicon.png"/>
@ -19,11 +20,11 @@
<title>page</title>
<link rel="manifest" href="manifest.json">
</head>
<body style="min-height: 3000px;min-width: 3000px;">
<body style="min-height: 3000px; min-width: 3000px;">
<h1>Simple Page 1</h1>
<a href="/page-2.html">Go to page 2</a>
<a href="/page-2.html" id="link-page-2">Go to page 2</a>
<br>
<a href="/heavy-page.html">Go to heavy-page</a>
<a href="/heavy-page.html" id="link-heavy-page">Go to heavy-page</a>
<script>
window.addEventListener('load', function (event) {
setTimeout(function () {

View File

@ -94,7 +94,7 @@ public class HeadlessInAppWebView : FlutterMethodCallDelegate {
}
deinit {
print("HeadlessInAppWebView - dealloc")
debugPrint("HeadlessInAppWebView - dealloc")
dispose()
}
}

View File

@ -11,7 +11,7 @@ public class InAppBrowserNavigationController: UINavigationController {
var tmpWindow: UIWindow?
deinit {
print("InAppBrowserNavigationController - dealloc")
debugPrint("InAppBrowserNavigationController - dealloc")
tmpWindow?.windowLevel = UIWindow.Level(rawValue: 0.0)
tmpWindow = nil
UIApplication.shared.delegate?.window??.makeKeyAndVisible()

View File

@ -181,7 +181,7 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega
}
deinit {
print("InAppBrowserWebViewController - dealloc")
debugPrint("InAppBrowserWebViewController - dealloc")
dispose()
}

View File

@ -173,7 +173,7 @@ public class FlutterWebViewController: NSObject, FlutterPlatformView {
}
deinit {
print("FlutterWebViewController - dealloc")
debugPrint("FlutterWebViewController - dealloc")
dispose()
}
}

View File

@ -3122,7 +3122,7 @@ if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) {
}
deinit {
print("InAppWebView - dealloc")
debugPrint("InAppWebView - dealloc")
}
// https://stackoverflow.com/a/58001395/4637638

View File

@ -603,7 +603,7 @@ public class InAppWebViewMethodHandler: FlutterMethodCallDelegate {
}
deinit {
print("InAppWebViewMethodHandler - dealloc")
debugPrint("InAppWebViewMethodHandler - dealloc")
dispose()
}
}

View File

@ -20,6 +20,6 @@ public class LeakAvoider: NSObject {
}
deinit {
print("LeakAvoider - dealloc")
debugPrint("LeakAvoider - dealloc")
}
}

View File

@ -108,7 +108,7 @@ public class PullToRefreshControl : UIRefreshControl, FlutterPlugin {
}
deinit {
print("PullToRefreshControl - dealloc")
debugPrint("PullToRefreshControl - dealloc")
dispose()
}
}

View File

@ -21,7 +21,7 @@ public class SafariViewController: SFSafariViewController, FlutterPlugin, SFSafa
}
deinit {
print("SafariViewController - dealloc")
debugPrint("SafariViewController - dealloc")
dispose()
}

View File

@ -22,7 +22,7 @@ public class WebMessage : NSObject {
}
deinit {
print("WebMessage - dealloc")
debugPrint("WebMessage - dealloc")
dispose()
}
}

View File

@ -145,7 +145,7 @@ public class WebMessageChannel : FlutterMethodCallDelegate {
}
deinit {
print("WebMessageChannel - dealloc")
debugPrint("WebMessageChannel - dealloc")
dispose()
}
}

View File

@ -221,7 +221,7 @@ public class WebMessageListener : FlutterMethodCallDelegate {
}
deinit {
print("WebMessageListener - dealloc")
debugPrint("WebMessageListener - dealloc")
dispose()
}
}

View File

@ -117,7 +117,7 @@ public class WebMessagePort : NSObject {
}
deinit {
print("WebMessagePort - dealloc")
debugPrint("WebMessagePort - dealloc")
dispose()
}
}

View File

@ -139,7 +139,7 @@ window.flutter_inappwebview = {
webView.documentTitle = initialTitle;
window.flutter_inappwebview.nativeCommunication('onTitleChanged', viewId, [initialTitle]);
new MutationObserver(function(mutations) {
var title = mutations[0].target.nodeValue;
var title = mutations[0].target.innerText;
if (title != webView.documentTitle) {
webView.documentTitle = title;
window.flutter_inappwebview.nativeCommunication('onTitleChanged', viewId, [title]);
@ -542,6 +542,28 @@ window.flutter_inappwebview = {
}
return false;
},
getSize: function() {
var iframe = webView.iframe;
var width = 0.0;
var height = 0.0;
if (iframe.style.width != null && iframe.style.width != '' && iframe.style.width.indexOf('px') > 0) {
width = parseFloat(iframe.style.width);
}
if (width == null || width == 0.0) {
width = iframe.getBoundingClientRect().width;
}
if (iframe.style.height != null && iframe.style.height != '' && iframe.style.height.indexOf('px') > 0) {
height = parseFloat(iframe.style.height);
}
if (height == null || height == 0.0) {
height = iframe.getBoundingClientRect().height;
}
return {
width: width,
height: height
};
}
};
return webView;

View File

@ -1033,7 +1033,7 @@ class InAppWebViewSettings
///
///**Supported Platforms/Implementations**:
///- Web
List<Sandbox>? iframeSandbox;
Set<Sandbox>? iframeSandbox;
///A string that reflects the `referrerpolicy` HTML attribute indicating which referrer to use when fetching the linked resource.
///
@ -1324,7 +1324,7 @@ class InAppWebViewSettings
"upgradeKnownHostsToHTTPS": upgradeKnownHostsToHTTPS,
"iframeAllow": iframeAllow,
"iframeAllowFullscreen": iframeAllowFullscreen,
"iframeSandbox": iframeSandbox?.map((e) => e.toValue()),
"iframeSandbox": iframeSandbox?.map((e) => e.toValue()).toList(),
"iframeReferrerPolicy": iframeReferrerPolicy,
"iframeName": iframeName,
"iframeCsp": iframeCsp,
@ -1387,8 +1387,10 @@ class InAppWebViewSettings
if (kIsWeb) {
settings.iframeAllow = map["iframeAllow"];
settings.iframeAllowFullscreen = map["iframeAllowFullscreen"];
settings.iframeSandbox = (map["iframeSandbox"] as List<String?>?)
?.map((e) => Sandbox.fromValue(e)) as List<Sandbox>?;
settings.iframeSandbox = map["iframeSandbox"] != null
? Set.from((map["iframeSandbox"].cast<String>() as List<String>)
.map((e) => Sandbox.fromValue(e)))
: null;
settings.iframeReferrerPolicy =
ReferrerPolicy.fromValue(map["iframeReferrerPolicy"]);
settings.iframeName = map["iframeName"];

View File

@ -32,11 +32,11 @@ class HeadlessInAppWebViewWebElement {
dispose();
break;
case "setSize":
Size size = MapSize.fromMap(call.arguments['size'])!;
Size size = MapSize.fromMap(call.arguments['size'].cast<String, dynamic>())!;
setSize(size);
break;
case "getSize":
return getSize().toMap();
return webView?.getSize().toMap();
default:
throw PlatformException(
code: 'Unimplemented',
@ -55,13 +55,6 @@ class HeadlessInAppWebViewWebElement {
webView?.iframe.style.height = size.height.toString() + "px";
}
Size getSize() {
var width = webView?.iframe.getBoundingClientRect().width.toDouble() ?? 0.0;
var height =
webView?.iframe.getBoundingClientRect().height.toDouble() ?? 0.0;
return Size(width, height);
}
void dispose() {
_channel?.setMethodCallHandler(null);
_channel = null;

View File

@ -43,9 +43,20 @@ class HeadlessInAppWebViewManager {
var headlessWebView = HeadlessInAppWebViewWebElement(
id: id, messenger: _messenger, webView: webView);
WebPlatformManager.webViews.putIfAbsent(id, () => webView);
prepare(webView, params);
headlessWebView.onWebViewCreated();
webView.makeInitialLoad();
}
void prepare(InAppWebViewWebElement webView, Map<String, dynamic> params) {
webView.iframe.style.display = 'none';
Map<String, num>? initialSize = params["initialSize"]?.cast<String, num>();
if (initialSize != null) {
webView.iframe.style.width = initialSize["width"].toString() + 'px';
webView.iframe.style.height = initialSize["height"].toString() + 'px';
}
Map<String, dynamic> initialSettings =
params["initialSettings"].cast<String, dynamic>();
params["initialSettings"].cast<String, dynamic>();
if (initialSettings.isEmpty) {
webView.initialSettings = InAppWebViewSettings();
} else {
@ -58,7 +69,5 @@ class HeadlessInAppWebViewManager {
params["initialData"]?.cast<String, dynamic>());
document.body?.append(webView.iframe);
webView.prepare();
headlessWebView.onWebViewCreated();
webView.makeInitialLoad();
}
}

View File

@ -1,5 +1,6 @@
import 'dart:async';
import 'dart:typed_data';
import 'dart:ui';
import 'package:flutter/services.dart';
import 'dart:html';
import 'dart:js' as js;
@ -87,7 +88,7 @@ class InAppWebViewWebElement {
await stopLoading();
break;
case "getSettings":
return await settings.toMap();
return await getSettings();
case "setSettings":
InAppWebViewSettings newSettings = InAppWebViewSettings.fromMap(
call.arguments["settings"].cast<String, dynamic>());
@ -183,6 +184,7 @@ class InAppWebViewWebElement {
iframe.removeAttribute("sandbox");
} else if (sandbox != Sandbox.values) {
iframe.setAttribute("sandbox", sandbox.map((e) => e.toValue()).join(" "));
settings.iframeSandbox = sandbox;
}
_callMethod("prepare", [js.JsObject.jsify(settings.toMap())]);
@ -367,6 +369,11 @@ class InAppWebViewWebElement {
return values.isEmpty ? Set.from(Sandbox.values) : values;
}
Size getSize() {
var size = _callMethod("getSize") as js.JsObject;
return Size(size["width"]!.toDouble(), size["height"]!.toDouble());
}
Future<void> setSettings(InAppWebViewSettings newSettings) async {
Set<Sandbox> sandbox = getSandbox();
@ -405,12 +412,17 @@ class InAppWebViewWebElement {
} else if (sandbox != Sandbox.values) {
iframe.setAttribute("sandbox", sandbox.map((e) => e.toValue()).join(" "));
}
newSettings.iframeSandbox = sandbox;
_callMethod("setSettings", [js.JsObject.jsify(newSettings.toMap())]);
settings = newSettings;
}
Future<Map<String, dynamic>> getSettings() async {
return settings.toMap();
}
void onLoadStart(String url) async {
isLoading = true;

View File

@ -7,7 +7,7 @@ Future<void> main() async {
'NODE_SERVER_IP': Platform.environment['NODE_SERVER_IP'],
};
final filename = 'example/integration_test/.env.dart';
final filename = 'example/integration_test/env.dart';
await File(filename)
.writeAsString('final environment = ${json.encode(config)};');
}