updated web support
This commit is contained in:
parent
3bad02d6e4
commit
68f25d0d4d
|
@ -29,4 +29,6 @@
|
|||
build/
|
||||
.fvm/
|
||||
|
||||
flutter_driver_tests.log
|
||||
flutter_driver_tests.log
|
||||
tool/chromedriver
|
||||
tool/chromedriver.*
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;">
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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."
|
||||
|
|
|
@ -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)
|
Loading…
Reference in New Issue