updated web support

This commit is contained in:
Lorenzo Pichilli 2022-04-27 16:59:49 +02:00
parent 3bad02d6e4
commit 68f25d0d4d
11 changed files with 375 additions and 56 deletions

4
.gitignore vendored
View File

@ -29,4 +29,6 @@
build/
.fvm/
flutter_driver_tests.log
flutter_driver_tests.log
tool/chromedriver
tool/chromedriver.*

View File

@ -1,4 +1,5 @@
import 'dart:collection';
import 'dart:typed_data';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
@ -114,16 +115,17 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
children: [
InAppWebView(
key: webViewKey,
// initialUrlRequest:
// URLRequest(url: Uri.parse("https://flutter.dev")),
initialUrlRequest:
URLRequest(url: Uri.parse("https://flutter.dev")),
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) async {
onWebViewCreated: (controller) {
webViewController = controller;
print(await controller.getUrl());
},
onLoadStart: (controller, url) async {
setState(() {
@ -149,10 +151,10 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
"javascript",
"about"
].contains(uri.scheme)) {
if (await canLaunch(url)) {
if (await canLaunchUrl(uri)) {
// Launch the App
await launch(
url,
await launchUrl(
uri,
);
// and cancel the request
return NavigationActionPolicy.CANCEL;

View File

@ -16,7 +16,7 @@
<!-- Favicon -->
<link rel="icon" type="image/png" href="favicon.png"/>
<title>flutter_inappwebview_example</title>
<title>heavy page</title>
<link rel="manifest" href="manifest.json">
</head>
<body>

View File

@ -15,7 +15,7 @@
<!-- Favicon -->
<link rel="icon" type="image/png" href="favicon.png"/>
<title>flutter_inappwebview_example</title>
<title>page 2</title>
<link rel="manifest" href="manifest.json">
</head>
<body>

View File

@ -16,7 +16,7 @@
<!-- Favicon -->
<link rel="icon" type="image/png" href="favicon.png"/>
<title>flutter_inappwebview_example</title>
<title>page</title>
<link rel="manifest" href="manifest.json">
</head>
<body style="min-height: 3000px;min-width: 3000px;">

View File

@ -16,7 +16,7 @@ window.flutter_inappwebview = {
event.stopPropagation();
return false;
},
prepare: function (settings) {
prepare: function(settings) {
webView.settings = settings;
var iframe = document.getElementById(iframeId);
@ -117,7 +117,7 @@ window.flutter_inappwebview = {
};
var originalPrint = iframe.contentWindow.print;
iframe.contentWindow.print = function () {
iframe.contentWindow.print = function() {
var iframeUrl = iframe.src;
try {
iframeUrl = iframe.contentWindow.location.href;
@ -194,7 +194,7 @@ window.flutter_inappwebview = {
try {
if (!webView.settings.javaScriptCanOpenWindowsAutomatically) {
iframe.contentWindow.open = function () {
iframe.contentWindow.open = function() {
throw new Error('JavaScript cannot open windows automatically');
};
}
@ -231,12 +231,12 @@ window.flutter_inappwebview = {
});
}
},
setSettings: function (newSettings) {
setSettings: function(newSettings) {
var iframe = webView.iframe;
try {
if (webView.settings.javaScriptCanOpenWindowsAutomatically != newSettings.javaScriptCanOpenWindowsAutomatically) {
if (!newSettings.javaScriptCanOpenWindowsAutomatically) {
iframe.contentWindow.open = function () {
iframe.contentWindow.open = function() {
throw new Error('JavaScript cannot open windows automatically');
};
} else {
@ -294,7 +294,7 @@ window.flutter_inappwebview = {
webView.settings = newSettings;
},
reload: function () {
reload: function() {
var iframe = webView.iframe;
if (iframe != null && iframe.contentWindow != null) {
try {
@ -305,7 +305,7 @@ window.flutter_inappwebview = {
}
}
},
goBack: function () {
goBack: function() {
var iframe = webView.iframe;
if (iframe != null) {
try {
@ -315,7 +315,7 @@ window.flutter_inappwebview = {
}
}
},
goForward: function () {
goForward: function() {
var iframe = webView.iframe;
if (iframe != null) {
try {
@ -325,7 +325,7 @@ window.flutter_inappwebview = {
}
}
},
goForwardOrForward: function (steps) {
goForwardOrForward: function(steps) {
var iframe = webView.iframe;
if (iframe != null) {
try {
@ -335,7 +335,7 @@ window.flutter_inappwebview = {
}
}
},
evaluateJavascript: function (source) {
evaluateJavascript: function(source) {
var iframe = webView.iframe;
var result = null;
if (iframe != null) {
@ -345,7 +345,7 @@ window.flutter_inappwebview = {
}
return result;
},
stopLoading: function (steps) {
stopLoading: function(steps) {
var iframe = webView.iframe;
if (iframe != null) {
try {
@ -355,7 +355,7 @@ window.flutter_inappwebview = {
}
}
},
getUrl: function () {
getUrl: function() {
var iframe = webView.iframe;
var url = iframe.src;
try {
@ -365,6 +365,138 @@ window.flutter_inappwebview = {
}
return url;
},
getTitle: function() {
var iframe = webView.iframe;
var title = null;
try {
title = iframe.contentDocument.title;
} catch (e) {
console.log(e);
}
return title;
},
injectJavascriptFileFromUrl: function(urlFile, scriptHtmlTagAttributes) {
var iframe = webView.iframe;
try {
var d = iframe.contentDocument;
var script = d.createElement('script');
for (var key of Object.keys(scriptHtmlTagAttributes)) {
if (scriptHtmlTagAttributes[key] != null) {
script[key] = scriptHtmlTagAttributes[key];
}
}
if (script.id != null) {
script.onload = function() {
window.flutter_inappwebview.nativeCommunication('onInjectedScriptLoaded', webView.viewId, [script.id]);
}
script.onerror = function() {
window.flutter_inappwebview.nativeCommunication('onInjectedScriptError', webView.viewId, [script.id]);
}
}
script.src = urlFile;
if (d.body != null) {
d.body.appendChild(script);
}
} catch (e) {
console.log(e);
}
},
injectCSSCode: function(source) {
var iframe = webView.iframe;
try {
var d = iframe.contentDocument;
var style = d.createElement('style');
style.innerHTML = source;
if (d.head != null) {
d.head.appendChild(style);
}
} catch (e) {
console.log(e);
}
},
injectCSSFileFromUrl: function(urlFile, cssLinkHtmlTagAttributes) {
var iframe = webView.iframe;
try {
var d = iframe.contentDocument;
var link = d.createElement('link');
for (var key of Object.keys(cssLinkHtmlTagAttributes)) {
if (cssLinkHtmlTagAttributes[key] != null) {
link[key] = cssLinkHtmlTagAttributes[key];
}
}
link.type = 'text/css';
var alternateStylesheet = "";
if (cssLinkHtmlTagAttributes.alternateStylesheet) {
alternateStylesheet = "alternate ";
}
link.rel = alternateStylesheet + "stylesheet";
link.href = urlFile;
if (d.head != null) {
d.head.appendChild(link);
}
} catch (e) {
console.log(e);
}
},
scrollTo: function(x, y, animated) {
var iframe = webView.iframe;
try {
if (animated) {
iframe.contentWindow.scrollTo({top: y, left: x, behavior: 'smooth'});
} else {
iframe.contentWindow.scrollTo(x, y);
}
} catch (e) {
console.log(e);
}
},
scrollBy: function(x, y, animated) {
var iframe = webView.iframe;
try {
if (animated) {
iframe.contentWindow.scrollBy({top: y, left: x, behavior: 'smooth'});
} else {
iframe.contentWindow.scrollBy(x, y);
}
} catch (e) {
console.log(e);
}
},
printCurrentPage: function() {
var iframe = webView.iframe;
try {
iframe.contentWindow.print();
} catch (e) {
console.log(e);
}
},
getContentHeight: function() {
var iframe = webView.iframe;
try {
return iframe.contentDocument.documentElement.scrollHeight;
} catch (e) {
console.log(e);
}
return null;
},
getSelectedText: function() {
var iframe = webView.iframe;
try {
var txt;
var w = iframe.contentWindow;
if (w.getSelection) {
txt = w.getSelection().toString();
} else if (w.document.getSelection) {
txt = w.document.getSelection().toString();
} else if (w.document.selection) {
txt = w.document.selection.createRange().text;
}
return txt;
} catch (e) {
console.log(e);
}
return null;
},
};
return webView;

View File

@ -1034,6 +1034,22 @@ class InAppWebViewController
_inAppBrowser!.onPrint(uri);
}
break;
case "onInjectedScriptLoaded":
String id = call.arguments[0];
var onLoadCallback = _injectedScriptsFromURL[id]?.onLoad;
if ((_webview != null || _inAppBrowser != null) &&
onLoadCallback != null) {
onLoadCallback();
}
return null;
case "onInjectedScriptError":
String id = call.arguments[0];
var onErrorCallback = _injectedScriptsFromURL[id]?.onError;
if ((_webview != null || _inAppBrowser != null) &&
onErrorCallback != null) {
onErrorCallback();
}
return null;
case "onCallJsHandler":
String handlerName = call.arguments["handlerName"];
// decode args to json
@ -1165,7 +1181,7 @@ class InAppWebViewController
try {
return jsonEncode(await javaScriptHandlersMap[handlerName]!(args));
} catch (error) {
print(error);
developer.log(error.toString(), name: this.runtimeType.toString());
return null;
}
}
@ -1194,9 +1210,12 @@ class InAppWebViewController
///Gets the title for the current page.
///
///**NOTE for Web**: this method will have effect only if the iframe has the same origin.
///
///**Supported Platforms/Implementations**:
///- Android native WebView ([Official API - WebView.getTitle](https://developer.android.com/reference/android/webkit/WebView#getTitle()))
///- iOS ([Official API - WKWebView.title](https://developer.apple.com/documentation/webkit/wkwebview/1415015-title))
///- Web
Future<String?> getTitle() async {
Map<String, dynamic> args = <String, dynamic>{};
return await _channel.invokeMethod('getTitle', args);
@ -1222,6 +1241,7 @@ class InAppWebViewController
///**Supported Platforms/Implementations**:
///- Android native WebView
///- iOS
///- Web
Future<String?> getHtml() async {
String? html;
@ -1245,13 +1265,13 @@ class InAppWebViewController
html = utf8.decode(bytes.buffer.asUint8List());
} catch (e) {}
} else {
HttpClient client = new HttpClient();
try {
HttpClient client = HttpClient();
var htmlRequest = await client.getUrl(webviewUrl);
html =
await (await htmlRequest.close()).transform(Utf8Decoder()).join();
} catch (e) {
print(e);
developer.log(e.toString(), name: this.runtimeType.toString());
}
}
@ -1260,13 +1280,15 @@ class InAppWebViewController
///Gets the list of all favicons for the current page.
///
///**NOTE for Web**: this method will have effect only if the iframe has the same origin.
///
///**Supported Platforms/Implementations**:
///- Android native WebView
///- iOS
///- Web
Future<List<Favicon>> getFavicons() async {
List<Favicon> favicons = [];
HttpClient client = new HttpClient();
var webviewUrl = await getUrl();
if (webviewUrl == null) {
@ -1336,6 +1358,7 @@ class InAppWebViewController
// try to get /favicon.ico
try {
HttpClient client = HttpClient();
var faviconUrl =
webviewUrl.scheme + "://" + webviewUrl.host + "/favicon.ico";
var faviconUri = Uri.parse(faviconUrl);
@ -1345,8 +1368,8 @@ class InAppWebViewController
favicons.add(Favicon(url: faviconUri, rel: "shortcut icon"));
}
} catch (e) {
print("/favicon.ico file not found: " + e.toString());
// print(stacktrace);
developer.log("/favicon.ico file not found: " + e.toString(),
name: this.runtimeType.toString());
}
// try to get the manifest file
@ -1358,13 +1381,14 @@ class InAppWebViewController
webviewUrl.scheme + "://" + webviewUrl.host + "/manifest.json";
}
try {
HttpClient client = HttpClient();
manifestRequest = await client.getUrl(Uri.parse(manifestUrl));
manifestResponse = await manifestRequest.close();
manifestFound = manifestResponse.statusCode == 200 &&
manifestResponse.headers.contentType?.mimeType == "application/json";
} catch (e) {
print("Manifest file not found: " + e.toString());
// print(stacktrace);
developer.log("Manifest file not found: " + e.toString(),
name: this.runtimeType.toString());
}
if (manifestFound) {
@ -1470,9 +1494,12 @@ class InAppWebViewController
///controller.postUrl(url: Uri.parse("https://www.example.com/"), postData: postData);
///```
///
///**NOTE for Web**: it will try to create an XMLHttpRequest and load the result inside the iframe.
///
///**Supported Platforms/Implementations**:
///- Android native WebView ([Official API - WebView.postUrl](https://developer.android.com/reference/android/webkit/WebView#postUrl(java.lang.String,%20byte[])))
///- iOS
///- Web
Future<void> postUrl({required Uri url, required Uint8List postData}) async {
assert(url.toString().isNotEmpty);
Map<String, dynamic> args = <String, dynamic>{};
@ -1745,9 +1772,12 @@ class InAppWebViewController
///Instead, you should call this method, for example, inside the [WebView.onLoadStop] event or in any other events
///where you know the page is ready "enough".
///
///**NOTE for Web**: this method will have effect only if the iframe has the same origin.
///
///**Supported Platforms/Implementations**:
///- Android native WebView
///- iOS
///- Web
Future<void> injectJavascriptFileFromUrl(
{required Uri urlFile,
ScriptHtmlTagAttributes? scriptHtmlTagAttributes}) async {
@ -1770,9 +1800,12 @@ class InAppWebViewController
///Instead, you should call this method, for example, inside the [WebView.onLoadStop] event or in any other events
///where you know the page is ready "enough".
///
///**NOTE for Web**: this method will have effect only if the iframe has the same origin.
///
///**Supported Platforms/Implementations**:
///- Android native WebView
///- iOS
///- Web
Future<dynamic> injectJavascriptFileFromAsset(
{required String assetFilePath}) async {
String source = await rootBundle.loadString(assetFilePath);
@ -1786,9 +1819,12 @@ class InAppWebViewController
///Instead, you should call this method, for example, inside the [WebView.onLoadStop] event or in any other events
///where you know the page is ready "enough".
///
///**NOTE for Web**: this method will have effect only if the iframe has the same origin.
///
///**Supported Platforms/Implementations**:
///- Android native WebView
///- iOS
///- Web
Future<void> injectCSSCode({required String source}) async {
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('source', () => source);
@ -1804,9 +1840,12 @@ class InAppWebViewController
///Instead, you should call this method, for example, inside the [WebView.onLoadStop] event or in any other events
///where you know the page is ready "enough".
///
///**NOTE for Web**: this method will have effect only if the iframe has the same origin.
///
///**Supported Platforms/Implementations**:
///- Android native WebView
///- iOS
///- Web
Future<void> injectCSSFileFromUrl(
{required Uri urlFile,
CSSLinkHtmlTagAttributes? cssLinkHtmlTagAttributes}) async {
@ -1825,9 +1864,12 @@ class InAppWebViewController
///Instead, you should call this method, for example, inside the [WebView.onLoadStop] event or in any other events
///where you know the page is ready "enough".
///
///**NOTE for Web**: this method will have effect only if the iframe has the same origin.
///
///**Supported Platforms/Implementations**:
///- Android native WebView
///- iOS
///- Web
Future<void> injectCSSFileFromAsset({required String assetFilePath}) async {
String source = await rootBundle.loadString(assetFilePath);
await injectCSSCode(source: source);
@ -2076,9 +2118,12 @@ class InAppWebViewController
///
///[animated] `true` to animate the scroll transition, `false` to make the scoll transition immediate.
///
///**NOTE for Web**: this method will have effect only if the iframe has the same origin.
///
///**Supported Platforms/Implementations**:
///- Android native WebView ([Official API - View.scrollTo](https://developer.android.com/reference/android/view/View#scrollTo(int,%20int)))
///- iOS ([Official API - UIScrollView.setContentOffset](https://developer.apple.com/documentation/uikit/uiscrollview/1619400-setcontentoffset))
///- Web ([Official API - Window.scrollTo](https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollTo))
Future<void> scrollTo(
{required int x, required int y, bool animated = false}) async {
Map<String, dynamic> args = <String, dynamic>{};
@ -2096,9 +2141,12 @@ class InAppWebViewController
///
///[animated] `true` to animate the scroll transition, `false` to make the scoll transition immediate.
///
///**NOTE for Web**: this method will have effect only if the iframe has the same origin.
///
///**Supported Platforms/Implementations**:
///- Android native WebView ([Official API - View.scrollBy](https://developer.android.com/reference/android/view/View#scrollBy(int,%20int)))
///- iOS ([Official API - UIScrollView.setContentOffset](https://developer.apple.com/documentation/uikit/uiscrollview/1619400-setcontentoffset))
///- Web ([Official API - Window.scrollBy](https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollBy))
Future<void> scrollBy(
{required int x, required int y, bool animated = false}) async {
Map<String, dynamic> args = <String, dynamic>{};
@ -2137,9 +2185,12 @@ class InAppWebViewController
///
///**NOTE**: available on Android 21+.
///
///**NOTE for Web**: this method will have effect only if the iframe has the same origin.
///
///**Supported Platforms/Implementations**:
///- Android native WebView ([Official API - PrintManager](https://developer.android.com/reference/android/print/PrintManager))
///- iOS ([Official API - UIPrintInteractionController](https://developer.apple.com/documentation/uikit/uiprintinteractioncontroller))
///- Web ([Official API - Window.print](https://developer.mozilla.org/en-US/docs/Web/API/Window/print))
Future<void> printCurrentPage() async {
Map<String, dynamic> args = <String, dynamic>{};
await _channel.invokeMethod('printCurrentPage', args);
@ -2147,9 +2198,12 @@ class InAppWebViewController
///Gets the height of the HTML content.
///
///**NOTE for Web**: this method will have effect only if the iframe has the same origin.
///
///**Supported Platforms/Implementations**:
///- Android native WebView ([Official API - WebView.getContentHeight](https://developer.android.com/reference/android/webkit/WebView#getContentHeight()))
///- iOS ([Official API - UIScrollView.contentSize](https://developer.apple.com/documentation/uikit/uiscrollview/1619399-contentsize))
///- Web ([Official API - Document.documentElement.scrollHeight](https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight))
Future<int?> getContentHeight() async {
Map<String, dynamic> args = <String, dynamic>{};
return await _channel.invokeMethod('getContentHeight', args);
@ -2186,9 +2240,12 @@ class InAppWebViewController
///This is not always the same as the URL passed to [InAppWebView.onLoadStart] because although the load for that URL has begun,
///the current page may not have changed. Also, there may have been redirects resulting in a different URL to that originally requested.
///
///**NOTE for Web**: it will return the current value of the `iframe.src` attribute.
///
///**Supported Platforms/Implementations**:
///- Android native WebView ([Official API - WebView.getOriginalUrl](https://developer.android.com/reference/android/webkit/WebView#getOriginalUrl()))
///- iOS
///- Web
Future<Uri?> getOriginalUrl() async {
Map<String, dynamic> args = <String, dynamic>{};
String? url = await _channel.invokeMethod('getOriginalUrl', args);
@ -2217,9 +2274,12 @@ class InAppWebViewController
///
///**NOTE for Android native WebView**: available only on Android 19+.
///
///**NOTE for Web**: this method will have effect only if the iframe has the same origin.
///
///**Supported Platforms/Implementations**:
///- Android native WebView
///- iOS
///- Web
Future<String?> getSelectedText() async {
Map<String, dynamic> args = <String, dynamic>{};
return await _channel.invokeMethod('getSelectedText', args);
@ -2314,9 +2374,12 @@ class InAppWebViewController
///
///**NOTE**: It is implemented using JavaScript.
///
///**NOTE for Web**: this method will have effect only if the iframe has the same origin.
///
///**Supported Platforms/Implementations**:
///- Android native WebView
///- iOS
///- Web
Future<List<MetaTag>> getMetaTags() async {
List<MetaTag> metaTags = [];
@ -2379,11 +2442,14 @@ class InAppWebViewController
///Returns an instance of [Color] representing the `content` value of the
///`<meta name="theme-color" content="">` tag of the current WebView, if available, otherwise `null`.
///
///**NOTE**: on Android and iOS < 15.0, it is implemented using JavaScript.
///**NOTE**: on Android, Web and iOS < 15.0, it is implemented using JavaScript.
///
///**NOTE for Web**: this method will have effect only if the iframe has the same origin.
///
///**Supported Platforms/Implementations**:
///- Android native WebView
///- iOS ([Official API - WKWebView.themeColor](https://developer.apple.com/documentation/webkit/wkwebview/3794258-themecolor))
///- Web
Future<Color?> getMetaThemeColor() async {
Color? themeColor;
@ -2391,16 +2457,12 @@ class InAppWebViewController
Map<String, dynamic> args = <String, dynamic>{};
themeColor = UtilColor.fromStringRepresentation(
await _channel.invokeMethod('getMetaThemeColor', args));
return themeColor;
} catch (e) {
// not implemented
}
if (themeColor != null) {
return themeColor;
}
// try using javascript
var metaTags = await getMetaTags();
MetaTag? metaTagThemeColor;

View File

@ -1,4 +1,5 @@
import 'dart:async';
import 'dart:typed_data';
import 'package:flutter/services.dart';
import 'dart:html';
import 'dart:js' as js;
@ -49,7 +50,7 @@ class InAppWebViewWebElement {
Future<dynamic> handleMethodCall(MethodCall call) async {
switch (call.method) {
case "getIFrameId":
return iframe.id;
return getIFrameId();
case "loadUrl":
URLRequest urlRequest = URLRequest.fromMap(
call.arguments["urlRequest"].cast<String, dynamic>())!;
@ -90,10 +91,51 @@ class InAppWebViewWebElement {
case "setSettings":
InAppWebViewSettings newSettings = InAppWebViewSettings.fromMap(
call.arguments["settings"].cast<String, dynamic>());
setSettings(newSettings);
await setSettings(newSettings);
break;
case "getUrl":
return getUrl();
return await getUrl();
case "getTitle":
return await getTitle();
case "postUrl":
String url = call.arguments["url"];
Uint8List postData = call.arguments["postData"];
return await postUrl(url: url, postData: postData);
case "injectJavascriptFileFromUrl":
String urlFile = call.arguments["urlFile"];
Map<String, dynamic> scriptHtmlTagAttributes = call.arguments["scriptHtmlTagAttributes"].cast<String, dynamic>();
await injectJavascriptFileFromUrl(urlFile: urlFile, scriptHtmlTagAttributes: scriptHtmlTagAttributes);
break;
case "injectCSSCode":
String source = call.arguments["source"];
await injectCSSCode(source: source);
break;
case "injectCSSFileFromUrl":
String urlFile = call.arguments["urlFile"];
Map<String, dynamic> cssLinkHtmlTagAttributes = call.arguments["cssLinkHtmlTagAttributes"].cast<String, dynamic>();
await injectCSSFileFromUrl(urlFile: urlFile, cssLinkHtmlTagAttributes: cssLinkHtmlTagAttributes);
break;
case "scrollTo":
int x = call.arguments["x"];
int y = call.arguments["y"];
bool animated = call.arguments["animated"];
await scrollTo(x: x, y: y, animated: animated);
break;
case "scrollBy":
int x = call.arguments["x"];
int y = call.arguments["y"];
bool animated = call.arguments["animated"];
await scrollBy(x: x, y: y, animated: animated);
break;
case "printCurrentPage":
await printCurrentPage();
break;
case "getContentHeight":
return await getContentHeight();
case "getOriginalUrl":
return await getOriginalUrl();
case "getSelectedText":
return await getSelectedText();
case "dispose":
dispose();
break;
@ -177,6 +219,10 @@ class InAppWebViewWebElement {
Uri.encodeFull(httpRequest.responseText ?? '');
}
String getIFrameId() {
return iframe.id;
}
Future<void> loadUrl({required URLRequest urlRequest}) async {
if ((urlRequest.method == null || urlRequest.method == "GET") &&
(urlRequest.headers == null || urlRequest.headers!.isEmpty)) {
@ -227,6 +273,56 @@ class InAppWebViewWebElement {
return url;
}
Future<String?> getTitle() async {
return _callMethod("getTitle");
}
Future<void> postUrl({required String url, required Uint8List postData}) async {
await loadUrl(urlRequest: URLRequest(url: Uri.parse(url), method: "POST", body: postData));
}
Future<void> injectJavascriptFileFromUrl({required String urlFile,
Map<String, dynamic>? scriptHtmlTagAttributes}) async {
_callMethod("injectJavascriptFileFromUrl",
[urlFile, scriptHtmlTagAttributes != null ?
js.JsObject.jsify(scriptHtmlTagAttributes) : null]);
}
Future<void> injectCSSCode({required String source}) async {
_callMethod("injectCSSCode", [source]);
}
Future<void> injectCSSFileFromUrl({required String urlFile,
Map<String, dynamic>? cssLinkHtmlTagAttributes}) async {
_callMethod("injectCSSFileFromUrl",
[urlFile, cssLinkHtmlTagAttributes != null ?
js.JsObject.jsify(cssLinkHtmlTagAttributes) : null]);
}
Future<void> scrollTo({required int x, required int y, bool animated = false}) async {
_callMethod('scrollTo', [x, y, animated]);
}
Future<void> scrollBy({required int x, required int y, bool animated = false}) async {
_callMethod('scrollBy', [x, y, animated]);
}
Future<void> printCurrentPage() async {
_callMethod('printCurrentPage');
}
Future<int?> getContentHeight() async {
return _callMethod('getContentHeight');
}
Future<String?> getOriginalUrl() async {
return iframe.src;
}
Future<String?> getSelectedText() async {
return _callMethod('getSelectedText');
}
Set<Sandbox> getSandbox() {
var sandbox = iframe.sandbox;
Set<Sandbox> values = Set();
@ -390,6 +486,14 @@ class InAppWebViewWebElement {
await _channel?.invokeMethod("onZoomScaleChanged", obj);
}
void onInjectedScriptLoaded(String id) async {
await _channel?.invokeMethod("onInjectedScriptLoaded", [id]);
}
void onInjectedScriptError(String id) async {
await _channel?.invokeMethod("onInjectedScriptError", [id]);
}
void dispose() {
_channel?.setMethodCallHandler(null);
_channel = null;

View File

@ -48,32 +48,32 @@ Future<dynamic> _dartNativeCommunication(String method, dynamic viewId,
WebPlatformManager.webViews[viewId] as InAppWebViewWebElement;
switch (method) {
case 'onLoadStart':
var url = args![0] as String;
String url = args![0];
webViewHtmlElement.onLoadStart(url);
break;
case 'onLoadStop':
var url = args![0] as String;
String url = args![0];
webViewHtmlElement.onLoadStop(url);
break;
case 'onUpdateVisitedHistory':
var url = args![0] as String;
String url = args![0];
webViewHtmlElement.onUpdateVisitedHistory(url);
break;
case 'onScrollChanged':
var x = (args![0] as double).toInt();
var y = (args[1] as double).toInt();
int x = (args![0] as double).toInt();
int y = (args[1] as double).toInt();
webViewHtmlElement.onScrollChanged(x, y);
break;
case 'onConsoleMessage':
var type = args![0] as String;
var message = args[1] as String?;
String type = args![0];
String? message = args[1];
webViewHtmlElement.onConsoleMessage(type, message);
break;
case 'onCreateWindow':
var windowId = args![0] as int;
var url = args[1] as String? ?? 'about:blank';
var target = args[2] as String?;
var windowFeatures = args[3] as String?;
int windowId = args![0];
String url = args[1] ?? 'about:blank';
String? target = args[2];
String? windowFeatures = args[3];
return await webViewHtmlElement.onCreateWindow(
windowId, url, target, windowFeatures);
case 'onWindowFocus':
@ -83,7 +83,7 @@ Future<dynamic> _dartNativeCommunication(String method, dynamic viewId,
webViewHtmlElement.onWindowBlur();
break;
case 'onPrint':
var url = args![0] as String?;
String? url = args![0];
webViewHtmlElement.onPrint(url);
break;
case 'onEnterFullscreen':
@ -93,14 +93,22 @@ Future<dynamic> _dartNativeCommunication(String method, dynamic viewId,
webViewHtmlElement.onExitFullscreen();
break;
case 'onTitleChanged':
var title = args![0] as String?;
String? title = args![0];
webViewHtmlElement.onTitleChanged(title);
break;
case 'onZoomScaleChanged':
var oldScale = args![0] as double;
var newScale = args[1] as double;
double oldScale = args![0];
double newScale = args[1];
webViewHtmlElement.onZoomScaleChanged(oldScale, newScale);
break;
case 'onInjectedScriptLoaded':
String id = args![0];
webViewHtmlElement.onInjectedScriptLoaded(id);
break;
case 'onInjectedScriptError':
String id = args![0];
webViewHtmlElement.onInjectedScriptError(id);
break;
}
}
}

View File

@ -10,8 +10,13 @@ function error() {
# on macOS local IP can be found using something like $(ipconfig getifaddr en0)
# on linux local IP can be found using something like $(ifconfig en0 | grep "inet " | grep -Fv 127.0.0.1 | awk '{print $2}') or $(ip route get 1 | awk '{print $NF;exit}')
export NODE_SERVER_IP=$1
PLATFORM=$2
FAILED=0
if [ $PLATFORM = "web" ]; then
$PROJECT_DIR/tool/chromedriver --port=4444 &
fi
dart $PROJECT_DIR/tool/env.dart
cd $PROJECT_DIR/nodejs_server_test_auth_basic_and_ssl
@ -21,7 +26,11 @@ flutter --version
flutter clean
cd $PROJECT_DIR/example
flutter clean
flutter driver --driver=test_driver/integration_test.dart --target=integration_test/webview_flutter_test.dart
if [ $PLATFORM = "web" ]; then
flutter driver --driver=test_driver/integration_test.dart --target=integration_test/webview_flutter_test.dart --device-id=chrome
else
flutter driver --driver=test_driver/integration_test.dart --target=integration_test/webview_flutter_test.dart
fi
if [ $? -eq 0 ]; then
echo "Integration tests passed successfully."

View File

@ -3,6 +3,6 @@
readonly SCRIPT_PATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )"
readonly PROJECT_DIR="$(dirname $SCRIPT_PATH)"
$SCRIPT_PATH/test.sh $1 2>&1 | tee $PROJECT_DIR/flutter_driver_tests.log
$SCRIPT_PATH/test.sh $1 $2 2>&1 | tee $PROJECT_DIR/flutter_driver_tests.log
kill $(jobs -p)