added new events

This commit is contained in:
Lorenzo Pichilli 2022-04-23 22:10:02 +02:00
parent 922fd0c142
commit 61a439893b
7 changed files with 269 additions and 23 deletions

View File

@ -22,7 +22,8 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
mediaPlaybackRequiresUserGesture: false,
useHybridComposition: true,
allowsInlineMediaPlayback: true,
iframeAllow: "camera; microphone"
iframeAllow: "camera; microphone",
iframeAllowFullscreen: true
);
PullToRefreshController? pullToRefreshController;
@ -46,7 +47,7 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
await webViewController?.clearFocus();
})
],
options: ContextMenuOptions(hideDefaultSystemContextMenuItems: false),
settings: ContextMenuSettings(hideDefaultSystemContextMenuItems: false),
onCreateContextMenu: (hitTestResult) async {
print("onCreateContextMenu");
print(hitTestResult.extra);
@ -184,6 +185,9 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
onConsoleMessage: (controller, consoleMessage) {
print(consoleMessage);
},
onZoomScaleChanged: (controller, oldScale, newScale) {
print("$oldScale $newScale");
},
),
!kIsWeb && progress < 1.0
? LinearProgressIndicator(value: progress)

View File

@ -2,11 +2,34 @@ window.flutter_inappwebview = {
viewId: null,
iframeId: null,
iframe: null,
windowAutoincrementId: 0,
windows: {},
isFullscreen: false,
documentTitle: null,
prepare: function () {
var iframe = document.getElementById(window.flutter_inappwebview.iframeId);
document.addEventListener('fullscreenchange', function(event) {
// document.fullscreenElement will point to the element that
// is in fullscreen mode if there is one. If there isn't one,
// the value of the property is null.
if (document.fullscreenElement && document.fullscreenElement.id == window.flutter_inappwebview.iframeId) {
window.flutter_inappwebview.isFullscreen = true;
window.flutter_inappwebview.nativeCommunication('onEnterFullscreen', window.flutter_inappwebview.viewId);
} else if (!document.fullscreenElement && window.flutter_inappwebview.isFullscreen) {
window.flutter_inappwebview.isFullscreen = false;
window.flutter_inappwebview.nativeCommunication('onExitFullscreen', window.flutter_inappwebview.viewId);
} else {
window.flutter_inappwebview.isFullscreen = false;
}
});
if (iframe != null) {
window.flutter_inappwebview.iframe = iframe;
iframe.addEventListener('load', function (event) {
window.flutter_inappwebview.windowAutoincrementId = 0;
window.flutter_inappwebview.windows = {};
try {
var oldLogs = {
'log': iframe.contentWindow.console.log,
@ -80,6 +103,41 @@ window.flutter_inappwebview = {
console.log(e);
}
try {
var originalOpen = iframe.contentWindow.open;
iframe.contentWindow.open = function (url, target, windowFeatures) {
var newWindow = originalOpen.call(iframe.contentWindow, ...arguments);
var windowId = window.flutter_inappwebview.windowAutoincrementId;
window.flutter_inappwebview.windowAutoincrementId++;
window.flutter_inappwebview.windows[windowId] = newWindow;
window.flutter_inappwebview.nativeCommunication('onCreateWindow', window.flutter_inappwebview.viewId, [windowId, url, target, windowFeatures]).then(function(){}, function(handledByClient) {
console.log(handledByClient);
if (handledByClient) {
newWindow.close();
}
});
return newWindow;
};
} catch (e) {
console.log(e);
}
try {
var originalPrint = iframe.contentWindow.print;
iframe.contentWindow.print = function () {
var iframeUrl = iframe.src;
try {
iframeUrl = iframe.contentWindow.location.href;
} catch (e) {
console.log(e);
}
window.flutter_inappwebview.nativeCommunication('onPrint', window.flutter_inappwebview.viewId, [iframeUrl]);
originalPrint.call(iframe.contentWindow);
};
} catch (e) {
console.log(e);
}
iframe.contentWindow.addEventListener('scroll', function (event) {
var x = 0;
var y = 0;
@ -91,6 +149,45 @@ window.flutter_inappwebview = {
}
window.flutter_inappwebview.nativeCommunication('onScrollChanged', window.flutter_inappwebview.viewId, [x, y]);
});
iframe.contentWindow.addEventListener('focus', function (event) {
window.flutter_inappwebview.nativeCommunication('onWindowFocus', window.flutter_inappwebview.viewId);
});
iframe.contentWindow.addEventListener('blur', function (event) {
window.flutter_inappwebview.nativeCommunication('onWindowBlur', window.flutter_inappwebview.viewId);
});
try {
var initialTitle = iframe.contentDocument.title;
window.flutter_inappwebview.documentTitle = initialTitle;
window.flutter_inappwebview.nativeCommunication('onTitleChanged', window.flutter_inappwebview.viewId, [initialTitle]);
new MutationObserver(function(mutations) {
var title = mutations[0].target.nodeValue;
if (title != window.flutter_inappwebview.documentTitle) {
window.flutter_inappwebview.documentTitle = title;
window.flutter_inappwebview.nativeCommunication('onTitleChanged', window.flutter_inappwebview.viewId, [title]);
}
}).observe(
iframe.contentDocument.querySelector('title'),
{ subtree: true, characterData: true, childList: true }
);
} catch (e) {
console.log(e);
}
try {
var oldPixelRatio = iframe.contentWindow.devicePixelRatio;
iframe.contentWindow.addEventListener('resize', function (e) {
var newPixelRatio = iframe.contentWindow.devicePixelRatio;
if(newPixelRatio !== oldPixelRatio){
window.flutter_inappwebview.nativeCommunication('onZoomScaleChanged', window.flutter_inappwebview.viewId, [oldPixelRatio, newPixelRatio]);
oldPixelRatio = newPixelRatio;
}
});
} catch (e) {
console.log(e);
}
});
}
},
@ -157,4 +254,4 @@ window.flutter_inappwebview = {
}
}
}
};
};

View File

@ -19,7 +19,10 @@
*
*/
@JS()
library flutter_inappwebview;
import 'package:js/js.dart';
export 'src/main.dart';
export 'src/web/main.dart';

View File

@ -994,6 +994,27 @@ class InAppWebViewController
_inAppBrowser!.onOverScrolled(x, y, clampedX, clampedY);
}
break;
case "onWindowFocus":
if (_webview != null && _webview!.onWindowFocus != null)
_webview!.onWindowFocus!(this);
else if (_inAppBrowser != null) _inAppBrowser!.onWindowFocus();
break;
case "onWindowBlur":
if (_webview != null && _webview!.onWindowBlur != null)
_webview!.onWindowBlur!(this);
else if (_inAppBrowser != null) _inAppBrowser!.onWindowBlur();
break;
case "onPrint":
if ((_webview != null && _webview!.onPrint != null) ||
_inAppBrowser != null) {
String? url = call.arguments["url"];
Uri? uri = url != null ? Uri.parse(url) : null;
if (_webview != null && _webview!.onPrint != null)
_webview!.onPrint!(this, uri);
else
_inAppBrowser!.onPrint(uri);
}
break;
case "onCallJsHandler":
String handlerName = call.arguments["handlerName"];
// decode args to json

View File

@ -188,9 +188,13 @@ abstract class WebView {
///Also, note that calling [InAppWebViewController.setSettings] method using the controller of the new created WebView,
///it will update also the WebView options of the caller WebView.
///
///**NOTE for Web**: this event will be called only if the iframe has the same origin.
///Also, there is no way to block the opening the window in a synchronous way, so returning `true` will just close it quickly.
///
///**Supported Platforms/Implementations**:
///- Android native WebView ([Official API - WebChromeClient.onCreateWindow](https://developer.android.com/reference/android/webkit/WebChromeClient#onCreateWindow(android.webkit.WebView,%20boolean,%20boolean,%20android.os.Message)))
///- iOS ([Official API - WKUIDelegate.webView](https://developer.apple.com/documentation/webkit/wkuidelegate/1536907-webview))
///- Web
final Future<bool?> Function(InAppWebViewController controller,
CreateWindowAction createWindowAction)? onCreateWindow;
@ -205,17 +209,23 @@ abstract class WebView {
///Event fired when the JavaScript `window` object of the WebView has received focus.
///This is the result of the `focus` JavaScript event applied to the `window` object.
///
///**NOTE for Web**: this event will be called only if the iframe has the same origin.
///
///**Supported Platforms/Implementations**:
///- Android native WebView
///- iOS
///- Web ([Official API - Window.onfocus](https://developer.mozilla.org/en-US/docs/Web/API/Window/focus_event))
final void Function(InAppWebViewController controller)? onWindowFocus;
///Event fired when the JavaScript `window` object of the WebView has lost focus.
///This is the result of the `blur` JavaScript event applied to the `window` object.
///
///**NOTE for Web**: this event will be called only if the iframe has the same origin.
///
///**Supported Platforms/Implementations**:
///- Android native WebView
///- iOS
///- Web ([Official API - Window.onblur](https://developer.mozilla.org/en-US/docs/Web/API/Window/blur_event))
final void Function(InAppWebViewController controller)? onWindowBlur;
///Event fired when javascript calls the `alert()` method to display an alert dialog.
@ -400,9 +410,12 @@ abstract class WebView {
///
///[url] represents the url on which is called.
///
///**NOTE for Web**: this event will be called only if the iframe has the same origin.
///
///**Supported Platforms/Implementations**:
///- Android native WebView
///- iOS
///- Web
final void Function(InAppWebViewController controller, Uri? url)? onPrint;
///Event fired when an HTML element of the webview has been clicked and held.
@ -420,6 +433,7 @@ abstract class WebView {
///**Supported Platforms/Implementations**:
///- Android native WebView ([Official API - WebChromeClient.onShowCustomView](https://developer.android.com/reference/android/webkit/WebChromeClient#onShowCustomView(android.view.View,%20android.webkit.WebChromeClient.CustomViewCallback)))
///- iOS ([Official API - UIWindow.didBecomeVisibleNotification](https://developer.apple.com/documentation/uikit/uiwindow/1621621-didbecomevisiblenotification))
///- Web ([Official API - Document.onfullscreenchange](https://developer.mozilla.org/en-US/docs/Web/API/Document/fullscreenchange_event))
final void Function(InAppWebViewController controller)? onEnterFullscreen;
///Event fired when the current page has exited full screen mode.
@ -431,6 +445,7 @@ abstract class WebView {
///**Supported Platforms/Implementations**:
///- Android native WebView ([Official API - WebChromeClient.onHideCustomView](https://developer.android.com/reference/android/webkit/WebChromeClient#onHideCustomView()))
///- iOS ([Official API - UIWindow.didBecomeHiddenNotification](https://developer.apple.com/documentation/uikit/uiwindow/1621617-didbecomehiddennotification))
///- Web ([Official API - Document.onfullscreenchange](https://developer.mozilla.org/en-US/docs/Web/API/Document/fullscreenchange_event))
final void Function(InAppWebViewController controller)? onExitFullscreen;
///Called when the web view begins to receive web content.
@ -450,9 +465,12 @@ abstract class WebView {
///
///[title] represents the string containing the new title of the document.
///
///**NOTE for Web**: this event will be called only if the iframe has the same origin.
///
///**Supported Platforms/Implementations**:
///- Android native WebView ([Official API - WebChromeClient.onReceivedTitle](https://developer.android.com/reference/android/webkit/WebChromeClient#onReceivedTitle(android.webkit.WebView,%20java.lang.String)))
///- iOS
///- Web
final void Function(InAppWebViewController controller, String? title)?
onTitleChanged;
@ -478,9 +496,12 @@ abstract class WebView {
///
///[newScale] The new zoom scale factor.
///
///**NOTE for Web**: this event will be called only if the iframe has the same origin.
///
///**Supported Platforms/Implementations**:
///- Android native WebView ([Official API - WebViewClient.onScaleChanged](https://developer.android.com/reference/android/webkit/WebViewClient#onScaleChanged(android.webkit.WebView,%20float,%20float)))
///- iOS ([Official API - UIScrollViewDelegate.scrollViewDidZoom](https://developer.apple.com/documentation/uikit/uiscrollviewdelegate/1619409-scrollviewdidzoom))
///- Web
final void Function(
InAppWebViewController controller, double oldScale, double newScale)?
onZoomScaleChanged;

View File

@ -201,40 +201,40 @@ class InAppWebViewWebElement {
settings = newSettings;
}
onLoadStart(String url) async {
void onLoadStart(String url) async {
isLoading = true;
var obj = {
"url": url
};
_channel.invokeMethod("onLoadStart", obj);
await _channel.invokeMethod("onLoadStart", obj);
}
onLoadStop(String url) async {
void onLoadStop(String url) async {
isLoading = false;
var obj = {
"url": url
};
_channel.invokeMethod("onLoadStop", obj);
await _channel.invokeMethod("onLoadStop", obj);
}
onUpdateVisitedHistory(String url) async {
void onUpdateVisitedHistory(String url) async {
var obj = {
"url": url
};
_channel.invokeMethod("onUpdateVisitedHistory", obj);
await _channel.invokeMethod("onUpdateVisitedHistory", obj);
}
onScrollChanged(int x, int y) async {
void onScrollChanged(int x, int y) async {
var obj = {
"x": x,
"y": y
};
_channel.invokeMethod("onScrollChanged", obj);
await _channel.invokeMethod("onScrollChanged", obj);
}
onConsoleMessage(String type, String? message) async {
void onConsoleMessage(String type, String? message) async {
int messageLevel = 1;
switch (type) {
case 'debug':
@ -255,6 +255,75 @@ class InAppWebViewWebElement {
"messageLevel": messageLevel,
"message": message
};
_channel.invokeMethod("onConsoleMessage", obj);
await _channel.invokeMethod("onConsoleMessage", obj);
}
Future<bool?> onCreateWindow(int windowId, String url, String? target, String? windowFeatures) async {
Map<String, dynamic> windowFeaturesMap = {};
List<String> features = windowFeatures?.split(",") ?? [];
for (var feature in features) {
var keyValue = feature.trim().split("=");
if (keyValue.length == 2) {
var key = keyValue[0].trim();
var value = keyValue[1].trim();
if (['height', 'width', 'x', 'y'].contains(key)) {
windowFeaturesMap[key] = double.parse(value);
} else {
windowFeaturesMap[key] = value;
}
}
}
var obj = {
"windowId": windowId,
"isForMainFrame": true,
"request": {
"url": url,
"method": "GET"
},
"windowFeatures": windowFeaturesMap
};
return await _channel.invokeMethod("onCreateWindow", obj);
}
void onWindowFocus() async {
await _channel.invokeMethod("onWindowFocus");
}
void onWindowBlur() async {
await _channel.invokeMethod("onWindowBlur");
}
void onPrint(String? url) async {
var obj = {
"url": url
};
await _channel.invokeMethod("onPrint", obj);
}
void onEnterFullscreen() async {
await _channel.invokeMethod("onEnterFullscreen");
}
void onExitFullscreen() async {
await _channel.invokeMethod("onExitFullscreen");
}
void onTitleChanged(String? title) async {
var obj = {
"title": title
};
await _channel.invokeMethod("onTitleChanged", obj);
}
void onZoomScaleChanged(double oldScale, double newScale) async {
var obj = {
"oldScale": oldScale,
"newScale": newScale
};
await _channel.invokeMethod("onZoomScaleChanged", obj);
}
}

View File

@ -43,38 +43,69 @@ class FlutterInAppWebViewWebPlatform {
/// Allows assigning a function to be callable from `window.flutter_inappwebview.nativeCommunication()`
@JS('flutter_inappwebview.nativeCommunication')
external set _nativeCommunication(void Function(String method, int viewId, [List? args]) f);
external set _nativeCommunication(Future<dynamic> Function(String method, int viewId, [List? args]) f);
/// Allows calling the assigned function from Dart as well.
@JS()
external void nativeCommunication();
external Future<dynamic> nativeCommunication(String method, int viewId, [List? args]);
void _dartNativeCommunication(String method, int viewId, [List? args]) {
Future<dynamic> _dartNativeCommunication(String method, int viewId, [List? args]) async {
if (WebPlatformManager.webViews.containsKey(viewId)) {
var webViewHtmlElement = WebPlatformManager.webViews[viewId] as InAppWebViewWebElement;
switch (method) {
case 'onLoadStart':
String url = args![0] as String;
var url = args![0] as String;
webViewHtmlElement.onLoadStart(url);
break;
case 'onLoadStop':
String url = args![0] as String;
var url = args![0] as String;
webViewHtmlElement.onLoadStop(url);
break;
case 'onUpdateVisitedHistory':
String url = args![0] as String;
var url = args![0] as String;
webViewHtmlElement.onUpdateVisitedHistory(url);
break;
case 'onScrollChanged':
int x = args![0] as int;
int y = args[1] as int;
var x = (args![0] as double).toInt();
var y = (args[1] as double).toInt();
webViewHtmlElement.onScrollChanged(x, y);
break;
case 'onConsoleMessage':
String type = args![0] as String;
String? message = args[1] as String?;
var type = args![0] as String;
var message = args[1] as String?;
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?;
return await webViewHtmlElement.onCreateWindow(windowId, url, target, windowFeatures);
case 'onWindowFocus':
webViewHtmlElement.onWindowFocus();
break;
case 'onWindowBlur':
webViewHtmlElement.onWindowBlur();
break;
case 'onPrint':
var url = args![0] as String?;
webViewHtmlElement.onPrint(url);
break;
case 'onEnterFullscreen':
webViewHtmlElement.onEnterFullscreen();
break;
case 'onExitFullscreen':
webViewHtmlElement.onExitFullscreen();
break;
case 'onTitleChanged':
var title = args![0] as String?;
webViewHtmlElement.onTitleChanged(title);
break;
case 'onZoomScaleChanged':
var oldScale = args![0] as double;
var newScale = args[1] as double;
webViewHtmlElement.onZoomScaleChanged(oldScale, newScale);
break;
}
}
}