updated web support
This commit is contained in:
parent
24317b22ec
commit
1161380eab
|
@ -119,10 +119,10 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
|
|||
InAppWebView(
|
||||
key: webViewKey,
|
||||
// contextMenu: contextMenu,
|
||||
initialUrlRequest:
|
||||
URLRequest(url: Uri.parse("https://www.pubnub.com/developers/demos/webrtc/launch/")),
|
||||
// initialUrlRequest:
|
||||
// URLRequest(url: Uri.parse(Uri.base.toString().replaceFirst("/#/", "/") + 'page.html')),
|
||||
// URLRequest(url: Uri.parse("https://www.pubnub.com/developers/demos/webrtc/launch/")),
|
||||
initialUrlRequest:
|
||||
URLRequest(url: Uri.parse(Uri.base.toString().replaceFirst("/#/", "/") + 'page.html')),
|
||||
// initialFile: "assets/index.html",
|
||||
initialUserScripts: UnmodifiableListView<UserScript>([]),
|
||||
initialSettings: settings,
|
||||
|
@ -221,6 +221,12 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
|
|||
webViewController?.reload();
|
||||
},
|
||||
),
|
||||
ElevatedButton(
|
||||
child: Icon(Icons.cancel),
|
||||
onPressed: () {
|
||||
webViewController?.stopLoading();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
])));
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<base href="$FLUTTER_BASE_HREF">
|
||||
|
||||
<meta charset="UTF-8">
|
||||
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
|
||||
<meta name="description" content="Demonstrates how to use the flutter_inappwebview plugin.">
|
||||
|
||||
<!-- iOS meta tags & icons -->
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<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">
|
||||
|
||||
<!-- Favicon -->
|
||||
<link rel="icon" type="image/png" href="favicon.png"/>
|
||||
|
||||
<title>flutter_inappwebview_example</title>
|
||||
<link rel="manifest" href="manifest.json">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Heavy Page</h1>
|
||||
<a href="/page.html">Go to page 1</a>
|
||||
<br>
|
||||
<p id="infotext">Loading image...</p>
|
||||
<img src="https://picsum.photos/5000" alt="Loading failed" onerror="this.src = ''; window.infotext != null ? infotext.remove() : null" onload="window.infotext != null ? infotext.remove() : null">
|
||||
</body>
|
||||
</html>
|
|
@ -1,7 +1,6 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<base href="$FLUTTER_BASE_HREF">
|
||||
|
||||
<meta charset="UTF-8">
|
||||
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
|
||||
|
@ -22,5 +21,9 @@
|
|||
<body>
|
||||
<h1>Simple Page 2</h1>
|
||||
<a href="/page.html">Go to page 1</a>
|
||||
<br>
|
||||
<a href="/heavy-page.html">Go to heavy-page</a>
|
||||
<br>
|
||||
<button onclick="window.history.pushState({}, '', '#test-state-change')">Test state change</button>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -22,5 +22,7 @@
|
|||
<body>
|
||||
<h1>Simple Page 1</h1>
|
||||
<a href="/page-2.html">Go to page 2</a>
|
||||
<br>
|
||||
<a href="/heavy-page.html">Go to heavy-page</a>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -13,7 +13,44 @@ window.flutter_inappwebview = {
|
|||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
window.flutter_inappwebview.nativeCommunication('iframeLoaded', window.flutter_inappwebview.viewId, [url]);
|
||||
window.flutter_inappwebview.nativeCommunication('onLoadStart', window.flutter_inappwebview.viewId, [url]);
|
||||
window.flutter_inappwebview.nativeCommunication('onLoadStop', window.flutter_inappwebview.viewId, [url]);
|
||||
|
||||
iframe.contentWindow.addEventListener('popstate', function (event) {
|
||||
var iframeUrl = iframe.src;
|
||||
try {
|
||||
iframeUrl = iframe.contentWindow.location.href;
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
window.flutter_inappwebview.nativeCommunication('onUpdateVisitedHistory', window.flutter_inappwebview.viewId, [iframeUrl]);
|
||||
});
|
||||
try {
|
||||
var originalPushState = iframe.contentWindow.history.pushState;
|
||||
iframe.contentWindow.history.pushState = function (state, unused, url) {
|
||||
originalPushState.call(iframe.contentWindow.history, state, unused, url);
|
||||
var iframeUrl = iframe.src;
|
||||
try {
|
||||
iframeUrl = iframe.contentWindow.location.href;
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
window.flutter_inappwebview.nativeCommunication('onUpdateVisitedHistory', window.flutter_inappwebview.viewId, [iframeUrl]);
|
||||
};
|
||||
var originalReplaceState = iframe.contentWindow.history.replaceState;
|
||||
iframe.contentWindow.history.replaceState = function (state, unused, url) {
|
||||
originalReplaceState.call(iframe.contentWindow.history, state, unused, url);
|
||||
var iframeUrl = iframe.src;
|
||||
try {
|
||||
iframeUrl = iframe.contentWindow.location.href;
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
window.flutter_inappwebview.nativeCommunication('onUpdateVisitedHistory', window.flutter_inappwebview.viewId, [iframeUrl]);
|
||||
};
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
@ -48,6 +85,16 @@ window.flutter_inappwebview = {
|
|||
}
|
||||
}
|
||||
},
|
||||
goForwardOrForward: function (steps) {
|
||||
var iframe = window.flutter_inappwebview.iframe;
|
||||
if (iframe != null) {
|
||||
try {
|
||||
iframe.contentWindow.history.go(steps);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
},
|
||||
evaluateJavascript: function (source) {
|
||||
var iframe = window.flutter_inappwebview.iframe;
|
||||
var result = null;
|
||||
|
@ -59,5 +106,15 @@ window.flutter_inappwebview = {
|
|||
}
|
||||
}
|
||||
return result;
|
||||
},
|
||||
stopLoading: function (steps) {
|
||||
var iframe = window.flutter_inappwebview.iframe;
|
||||
if (iframe != null) {
|
||||
try {
|
||||
iframe.contentWindow.stop();
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1586,6 +1586,7 @@ class InAppWebViewController
|
|||
///**Supported Platforms/Implementations**:
|
||||
///- Android native WebView ([Official API - WebView.goBackOrForward](https://developer.android.com/reference/android/webkit/WebView#goBackOrForward(int)))
|
||||
///- iOS ([Official API - WKWebView.go](https://developer.apple.com/documentation/webkit/wkwebview/1414991-go))
|
||||
///- Web ([Official API - History.go](https://developer.mozilla.org/en-US/docs/Web/API/History/go))
|
||||
Future<void> goBackOrForward({required int steps}) async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
args.putIfAbsent('steps', () => steps);
|
||||
|
@ -1608,6 +1609,7 @@ class InAppWebViewController
|
|||
///**Supported Platforms/Implementations**:
|
||||
///- Android native WebView
|
||||
///- iOS
|
||||
///- Web
|
||||
Future<void> goTo({required WebHistoryItem historyItem}) async {
|
||||
var steps = historyItem.offset;
|
||||
if (steps != null) {
|
||||
|
@ -1620,6 +1622,7 @@ class InAppWebViewController
|
|||
///**Supported Platforms/Implementations**:
|
||||
///- Android native WebView
|
||||
///- iOS
|
||||
///- Web
|
||||
Future<bool> isLoading() async {
|
||||
Map<String, dynamic> args = <String, dynamic>{};
|
||||
return await _channel.invokeMethod('isLoading', args);
|
||||
|
|
|
@ -25,6 +25,9 @@ abstract class WebView {
|
|||
|
||||
///Event fired when the [WebView] starts to load an [url].
|
||||
///
|
||||
///**NOTE**: on Web it will be dispatched at the same time of [onLoadStop] event
|
||||
///because there isn't any way to capture the real load start event from an iframe.
|
||||
///
|
||||
///**Supported Platforms/Implementations**:
|
||||
///- Android native WebView ([Official API - WebViewClient.onPageStarted](https://developer.android.com/reference/android/webkit/WebViewClient#onPageStarted(android.webkit.WebView,%20java.lang.String,%20android.graphics.Bitmap)))
|
||||
///- iOS ([Official API - WKNavigationDelegate.webView](https://developer.apple.com/documentation/webkit/wknavigationdelegate/1455621-webview))
|
||||
|
@ -380,6 +383,7 @@ abstract class WebView {
|
|||
///**Supported Platforms/Implementations**:
|
||||
///- Android native WebView ([Official API - WebViewClient.doUpdateVisitedHistory](https://developer.android.com/reference/android/webkit/WebViewClient#doUpdateVisitedHistory(android.webkit.WebView,%20java.lang.String,%20boolean)))
|
||||
///- iOS
|
||||
///- Web
|
||||
final void Function(
|
||||
InAppWebViewController controller, Uri? url, bool? isReload)?
|
||||
onUpdateVisitedHistory;
|
||||
|
|
|
@ -18,7 +18,7 @@ class InAppWebViewWebElement {
|
|||
|
||||
late InAppWebViewSettings settings;
|
||||
late js.JsObject bridgeJsObject;
|
||||
WebHistory webHistory = WebHistory(list: [], currentIndex: -1);
|
||||
bool isLoading = false;
|
||||
|
||||
InAppWebViewWebElement({required int viewId, required BinaryMessenger messenger}) {
|
||||
this._viewId = viewId;
|
||||
|
@ -49,29 +49,44 @@ class InAppWebViewWebElement {
|
|||
return iframe.id;
|
||||
case "loadUrl":
|
||||
URLRequest urlRequest = URLRequest.fromMap(call.arguments["urlRequest"].cast<String, dynamic>())!;
|
||||
await _loadUrl(urlRequest: urlRequest);
|
||||
await loadUrl(urlRequest: urlRequest);
|
||||
break;
|
||||
case "loadData":
|
||||
String data = call.arguments["data"];
|
||||
String mimeType = call.arguments["mimeType"];
|
||||
await _loadData(data: data, mimeType: mimeType);
|
||||
await loadData(data: data, mimeType: mimeType);
|
||||
break;
|
||||
case "loadFile":
|
||||
String assetFilePath = call.arguments["assetFilePath"];
|
||||
await _loadFile(assetFilePath: assetFilePath);
|
||||
await loadFile(assetFilePath: assetFilePath);
|
||||
break;
|
||||
case "reload":
|
||||
await _reload();
|
||||
await reload();
|
||||
break;
|
||||
case "goBack":
|
||||
await _goBack();
|
||||
await goBack();
|
||||
break;
|
||||
case "goForward":
|
||||
await _goForward();
|
||||
await goForward();
|
||||
break;
|
||||
case "goBackOrForward":
|
||||
int steps = call.arguments["steps"];
|
||||
await goBackOrForward(steps: steps);
|
||||
break;
|
||||
case "isLoading":
|
||||
return isLoading;
|
||||
case "evaluateJavascript":
|
||||
String source = call.arguments["source"];
|
||||
return await _evaluateJavascript(source: source);
|
||||
return await evaluateJavascript(source: source);
|
||||
case "stopLoading":
|
||||
await stopLoading();
|
||||
break;
|
||||
case "getSettings":
|
||||
return await settings.toMap();
|
||||
case "setSettings":
|
||||
InAppWebViewSettings newSettings = InAppWebViewSettings.fromMap(call.arguments["settings"].cast<String, dynamic>());
|
||||
setSettings(newSettings);
|
||||
break;
|
||||
default:
|
||||
throw PlatformException(
|
||||
code: 'Unimplemented',
|
||||
|
@ -98,11 +113,11 @@ class InAppWebViewWebElement {
|
|||
|
||||
void makeInitialLoad() async {
|
||||
if (initialUrlRequest != null) {
|
||||
_loadUrl(urlRequest: initialUrlRequest!);
|
||||
loadUrl(urlRequest: initialUrlRequest!);
|
||||
} else if (initialData != null) {
|
||||
_loadData(data: initialData!.data, mimeType: initialData!.mimeType);
|
||||
loadData(data: initialData!.data, mimeType: initialData!.mimeType);
|
||||
} else if (initialFile != null) {
|
||||
_loadFile(assetFilePath: initialFile!);
|
||||
loadFile(assetFilePath: initialFile!);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -125,55 +140,97 @@ class InAppWebViewWebElement {
|
|||
return 'data:$contentType,' + Uri.encodeFull(httpRequest.responseText ?? '');
|
||||
}
|
||||
|
||||
Future<void> _loadUrl({required URLRequest urlRequest}) async {
|
||||
Future<void> loadUrl({required URLRequest urlRequest}) async {
|
||||
if ((urlRequest.method == null || urlRequest.method == "GET") &&
|
||||
(urlRequest.headers == null || urlRequest.headers!.isEmpty)) {
|
||||
iframe.src = urlRequest.url.toString();
|
||||
} else {
|
||||
iframe.src = _convertHttpResponseToData(await _makeRequest(urlRequest));
|
||||
}
|
||||
var obj = {
|
||||
"url": iframe.src
|
||||
};
|
||||
_channel.invokeMethod("onLoadStart", obj);
|
||||
}
|
||||
|
||||
Future<void> _loadData({required String data, String mimeType = "text/html"}) async {
|
||||
Future<void> loadData({required String data, String mimeType = "text/html"}) async {
|
||||
iframe.src = 'data:$mimeType,' + Uri.encodeFull(data);
|
||||
var obj = {
|
||||
"url": iframe.src
|
||||
};
|
||||
_channel.invokeMethod("onLoadStart", obj);
|
||||
}
|
||||
|
||||
Future<void> _loadFile({required String assetFilePath}) async {
|
||||
Future<void> loadFile({required String assetFilePath}) async {
|
||||
iframe.src = assetFilePath;
|
||||
var obj = {
|
||||
"url": iframe.src
|
||||
};
|
||||
_channel.invokeMethod("onLoadStart", obj);
|
||||
}
|
||||
|
||||
Future<void> _reload() async {
|
||||
Future<void> reload() async {
|
||||
bridgeJsObject.callMethod("reload");
|
||||
}
|
||||
|
||||
Future<void> _goBack() async {
|
||||
Future<void> goBack() async {
|
||||
bridgeJsObject.callMethod("goBack");
|
||||
}
|
||||
|
||||
Future<void> _goForward() async {
|
||||
Future<void> goForward() async {
|
||||
bridgeJsObject.callMethod("goForward");
|
||||
}
|
||||
|
||||
Future<dynamic> _evaluateJavascript({required String source}) async {
|
||||
Future<void> goBackOrForward({required int steps}) async {
|
||||
bridgeJsObject.callMethod("goBackOrForward", [steps]);
|
||||
}
|
||||
|
||||
Future<dynamic> evaluateJavascript({required String source}) async {
|
||||
return bridgeJsObject.callMethod("evaluateJavascript", [source]);
|
||||
}
|
||||
|
||||
onIFrameLoaded(String url) async {
|
||||
Future<void> stopLoading() async {
|
||||
bridgeJsObject.callMethod("stopLoading");
|
||||
}
|
||||
|
||||
Future<void> setSettings(InAppWebViewSettings newSettings) async {
|
||||
if (settings.iframeAllow != newSettings.iframeAllow) {
|
||||
iframe.allow = newSettings.iframeAllow;
|
||||
}
|
||||
if (settings.iframeAllowFullscreen != newSettings.iframeAllowFullscreen) {
|
||||
iframe.allowFullscreen = newSettings.iframeAllowFullscreen;
|
||||
}
|
||||
if (settings.iframeSandox != newSettings.iframeSandox) {
|
||||
iframe.setAttribute("sandbox", newSettings.iframeSandox ?? "");
|
||||
}
|
||||
if (settings.iframeWidth != newSettings.iframeWidth) {
|
||||
iframe.style.width = newSettings.iframeWidth;
|
||||
}
|
||||
if (settings.iframeHeight != newSettings.iframeHeight) {
|
||||
iframe.style.height = newSettings.iframeHeight;
|
||||
}
|
||||
if (settings.iframeReferrerPolicy != newSettings.iframeReferrerPolicy) {
|
||||
iframe.referrerPolicy = newSettings.iframeReferrerPolicy;
|
||||
}
|
||||
if (settings.iframeName != newSettings.iframeName) {
|
||||
iframe.name = newSettings.iframeName;
|
||||
}
|
||||
if (settings.iframeCsp != newSettings.iframeCsp) {
|
||||
iframe.csp = newSettings.iframeCsp;
|
||||
}
|
||||
settings = newSettings;
|
||||
}
|
||||
|
||||
onLoadStart(String url) async {
|
||||
isLoading = true;
|
||||
|
||||
var obj = {
|
||||
"url": url
|
||||
};
|
||||
_channel.invokeMethod("onLoadStart", obj);
|
||||
}
|
||||
|
||||
onLoadStop(String url) async {
|
||||
isLoading = false;
|
||||
|
||||
var obj = {
|
||||
"url": url
|
||||
};
|
||||
_channel.invokeMethod("onLoadStop", obj);
|
||||
}
|
||||
|
||||
onUpdateVisitedHistory(String url) async {
|
||||
var obj = {
|
||||
"url": url
|
||||
};
|
||||
_channel.invokeMethod("onUpdateVisitedHistory", obj);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,9 +53,17 @@ void _dartNativeCommunication(String method, int viewId, [List? args]) {
|
|||
if (WebPlatformManager.webViews.containsKey(viewId)) {
|
||||
var webViewHtmlElement = WebPlatformManager.webViews[viewId] as InAppWebViewWebElement;
|
||||
switch (method) {
|
||||
case 'iframeLoaded':
|
||||
case 'onLoadStart':
|
||||
String url = args![0] as String;
|
||||
webViewHtmlElement.onIFrameLoaded(url);
|
||||
webViewHtmlElement.onLoadStart(url);
|
||||
break;
|
||||
case 'onLoadStop':
|
||||
String url = args![0] as String;
|
||||
webViewHtmlElement.onLoadStop(url);
|
||||
break;
|
||||
case 'onUpdateVisitedHistory':
|
||||
String url = args![0] as String;
|
||||
webViewHtmlElement.onUpdateVisitedHistory(url);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue