added headless and cookie manager web support
This commit is contained in:
parent
d1a4ff1829
commit
bb33ec2362
@ -24,8 +24,6 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
|
|||||||
allowsInlineMediaPlayback: true,
|
allowsInlineMediaPlayback: true,
|
||||||
iframeAllow: "camera; microphone",
|
iframeAllow: "camera; microphone",
|
||||||
iframeAllowFullscreen: true,
|
iframeAllowFullscreen: true,
|
||||||
disableVerticalScroll: true,
|
|
||||||
disableHorizontalScroll: true,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
PullToRefreshController? pullToRefreshController;
|
PullToRefreshController? pullToRefreshController;
|
||||||
@ -123,7 +121,7 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
|
|||||||
initialUserScripts: UnmodifiableListView<UserScript>([]),
|
initialUserScripts: UnmodifiableListView<UserScript>([]),
|
||||||
initialSettings: settings,
|
initialSettings: settings,
|
||||||
pullToRefreshController: pullToRefreshController,
|
pullToRefreshController: pullToRefreshController,
|
||||||
onWebViewCreated: (controller) {
|
onWebViewCreated: (controller) async {
|
||||||
webViewController = controller;
|
webViewController = controller;
|
||||||
},
|
},
|
||||||
onLoadStart: (controller, url) async {
|
onLoadStart: (controller, url) async {
|
||||||
@ -162,17 +160,11 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
|
|||||||
return NavigationActionPolicy.ALLOW;
|
return NavigationActionPolicy.ALLOW;
|
||||||
},
|
},
|
||||||
onLoadStop: (controller, url) async {
|
onLoadStop: (controller, url) async {
|
||||||
print("onLoadStop");
|
|
||||||
pullToRefreshController?.endRefreshing();
|
pullToRefreshController?.endRefreshing();
|
||||||
setState(() {
|
setState(() {
|
||||||
this.url = url.toString();
|
this.url = url.toString();
|
||||||
urlController.text = this.url;
|
urlController.text = this.url;
|
||||||
});
|
});
|
||||||
await Future.delayed(Duration(seconds: 2));
|
|
||||||
await controller.setSettings(settings: settings.copy()
|
|
||||||
..disableVerticalScroll = false
|
|
||||||
..disableHorizontalScroll = false
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
onLoadError: (controller, url, code, message) {
|
onLoadError: (controller, url, code, message) {
|
||||||
pullToRefreshController?.endRefreshing();
|
pullToRefreshController?.endRefreshing();
|
||||||
|
@ -1,337 +1,365 @@
|
|||||||
window.flutter_inappwebview = {
|
window.flutter_inappwebview = {
|
||||||
viewId: null,
|
webViews: {},
|
||||||
iframeId: null,
|
createFlutterInAppWebView: function(viewId, iframeId) {
|
||||||
iframe: null,
|
var webView = {
|
||||||
windowAutoincrementId: 0,
|
viewId: viewId,
|
||||||
windows: {},
|
iframeId: iframeId,
|
||||||
isFullscreen: false,
|
iframe: null,
|
||||||
documentTitle: null,
|
windowAutoincrementId: 0,
|
||||||
functionMap: {},
|
windows: {},
|
||||||
settings: {},
|
isFullscreen: false,
|
||||||
prepare: function (settings) {
|
documentTitle: null,
|
||||||
window.flutter_inappwebview.settings = settings;
|
functionMap: {},
|
||||||
var iframe = document.getElementById(window.flutter_inappwebview.iframeId);
|
settings: {},
|
||||||
|
disableContextMenuHandler: function(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
prepare: function (settings) {
|
||||||
|
webView.settings = settings;
|
||||||
|
var iframe = document.getElementById(iframeId);
|
||||||
|
|
||||||
document.addEventListener('fullscreenchange', function(event) {
|
document.addEventListener('fullscreenchange', function(event) {
|
||||||
// document.fullscreenElement will point to the element that
|
// document.fullscreenElement will point to the element that
|
||||||
// is in fullscreen mode if there is one. If there isn't one,
|
// is in fullscreen mode if there is one. If there isn't one,
|
||||||
// the value of the property is null.
|
// the value of the property is null.
|
||||||
if (document.fullscreenElement && document.fullscreenElement.id == window.flutter_inappwebview.iframeId) {
|
if (document.fullscreenElement && document.fullscreenElement.id == iframeId) {
|
||||||
window.flutter_inappwebview.isFullscreen = true;
|
webView.isFullscreen = true;
|
||||||
window.flutter_inappwebview.nativeCommunication('onEnterFullscreen', window.flutter_inappwebview.viewId);
|
window.flutter_inappwebview.nativeCommunication('onEnterFullscreen', viewId);
|
||||||
} else if (!document.fullscreenElement && window.flutter_inappwebview.isFullscreen) {
|
} else if (!document.fullscreenElement && webView.isFullscreen) {
|
||||||
window.flutter_inappwebview.isFullscreen = false;
|
webView.isFullscreen = false;
|
||||||
window.flutter_inappwebview.nativeCommunication('onExitFullscreen', window.flutter_inappwebview.viewId);
|
window.flutter_inappwebview.nativeCommunication('onExitFullscreen', viewId);
|
||||||
} else {
|
} else {
|
||||||
window.flutter_inappwebview.isFullscreen = false;
|
webView.isFullscreen = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (iframe != null) {
|
if (iframe != null) {
|
||||||
window.flutter_inappwebview.iframe = iframe;
|
webView.iframe = iframe;
|
||||||
iframe.addEventListener('load', function (event) {
|
iframe.addEventListener('load', function (event) {
|
||||||
window.flutter_inappwebview.windowAutoincrementId = 0;
|
webView.windowAutoincrementId = 0;
|
||||||
window.flutter_inappwebview.windows = {};
|
webView.windows = {};
|
||||||
|
|
||||||
var url = iframe.src;
|
var url = iframe.src;
|
||||||
try {
|
try {
|
||||||
url = iframe.contentWindow.location.href;
|
url = iframe.contentWindow.location.href;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
}
|
}
|
||||||
window.flutter_inappwebview.nativeCommunication('onLoadStart', window.flutter_inappwebview.viewId, [url]);
|
window.flutter_inappwebview.nativeCommunication('onLoadStart', viewId, [url]);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var oldLogs = {
|
var oldLogs = {
|
||||||
'log': iframe.contentWindow.console.log,
|
'log': iframe.contentWindow.console.log,
|
||||||
'debug': iframe.contentWindow.console.debug,
|
'debug': iframe.contentWindow.console.debug,
|
||||||
'error': iframe.contentWindow.console.error,
|
'error': iframe.contentWindow.console.error,
|
||||||
'info': iframe.contentWindow.console.info,
|
'info': iframe.contentWindow.console.info,
|
||||||
'warn': iframe.contentWindow.console.warn
|
'warn': iframe.contentWindow.console.warn
|
||||||
};
|
};
|
||||||
for (var k in oldLogs) {
|
for (var k in oldLogs) {
|
||||||
(function(oldLog) {
|
(function(oldLog) {
|
||||||
iframe.contentWindow.console[oldLog] = function() {
|
iframe.contentWindow.console[oldLog] = function() {
|
||||||
var message = '';
|
var message = '';
|
||||||
for (var i in arguments) {
|
for (var i in arguments) {
|
||||||
if (message == '') {
|
if (message == '') {
|
||||||
message += arguments[i];
|
message += arguments[i];
|
||||||
} else {
|
} else {
|
||||||
message += ' ' + arguments[i];
|
message += ' ' + arguments[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
oldLogs[oldLog].call(iframe.contentWindow.console, ...arguments);
|
||||||
|
window.flutter_inappwebview.nativeCommunication('onConsoleMessage', viewId, [oldLog, message]);
|
||||||
}
|
}
|
||||||
|
})(k);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
oldLogs[oldLog].call(iframe.contentWindow.console, ...arguments);
|
window.flutter_inappwebview.nativeCommunication('onUpdateVisitedHistory', viewId, [iframeUrl]);
|
||||||
window.flutter_inappwebview.nativeCommunication('onConsoleMessage', window.flutter_inappwebview.viewId, [oldLog, message]);
|
};
|
||||||
|
|
||||||
|
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', viewId, [iframeUrl]);
|
||||||
|
};
|
||||||
|
|
||||||
|
var originalOpen = iframe.contentWindow.open;
|
||||||
|
iframe.contentWindow.open = function (url, target, windowFeatures) {
|
||||||
|
var newWindow = originalOpen.call(iframe.contentWindow, ...arguments);
|
||||||
|
var windowId = webView.windowAutoincrementId;
|
||||||
|
webView.windowAutoincrementId++;
|
||||||
|
webView.windows[windowId] = newWindow;
|
||||||
|
window.flutter_inappwebview.nativeCommunication('onCreateWindow', viewId, [windowId, url, target, windowFeatures]).then(function(){}, function(handledByClient) {
|
||||||
|
if (handledByClient) {
|
||||||
|
newWindow.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return newWindow;
|
||||||
|
};
|
||||||
|
|
||||||
|
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', viewId, [iframeUrl]);
|
||||||
|
originalPrint.call(iframe.contentWindow);
|
||||||
|
};
|
||||||
|
|
||||||
|
webView.functionMap = {
|
||||||
|
"window.open": iframe.contentWindow.open,
|
||||||
|
"window.print": iframe.contentWindow.print,
|
||||||
|
"window.history.pushState": iframe.contentWindow.history.pushState,
|
||||||
|
"window.history.replaceState": iframe.contentWindow.history.replaceState,
|
||||||
}
|
}
|
||||||
})(k);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
var initialTitle = iframe.contentDocument.title;
|
||||||
var originalPushState = iframe.contentWindow.history.pushState;
|
webView.documentTitle = initialTitle;
|
||||||
iframe.contentWindow.history.pushState = function (state, unused, url) {
|
window.flutter_inappwebview.nativeCommunication('onTitleChanged', viewId, [initialTitle]);
|
||||||
originalPushState.call(iframe.contentWindow.history, state, unused, url);
|
new MutationObserver(function(mutations) {
|
||||||
var iframeUrl = iframe.src;
|
var title = mutations[0].target.nodeValue;
|
||||||
try {
|
if (title != webView.documentTitle) {
|
||||||
iframeUrl = iframe.contentWindow.location.href;
|
webView.documentTitle = title;
|
||||||
|
window.flutter_inappwebview.nativeCommunication('onTitleChanged', viewId, [title]);
|
||||||
|
}
|
||||||
|
}).observe(
|
||||||
|
iframe.contentDocument.querySelector('title'),
|
||||||
|
{ subtree: true, characterData: true, childList: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
var oldPixelRatio = iframe.contentWindow.devicePixelRatio;
|
||||||
|
iframe.contentWindow.addEventListener('resize', function (e) {
|
||||||
|
var newPixelRatio = iframe.contentWindow.devicePixelRatio;
|
||||||
|
if(newPixelRatio !== oldPixelRatio){
|
||||||
|
window.flutter_inappwebview.nativeCommunication('onZoomScaleChanged', viewId, [oldPixelRatio, newPixelRatio]);
|
||||||
|
oldPixelRatio = newPixelRatio;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
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', viewId, [iframeUrl]);
|
||||||
|
});
|
||||||
|
|
||||||
|
iframe.contentWindow.addEventListener('scroll', function (event) {
|
||||||
|
var x = 0;
|
||||||
|
var y = 0;
|
||||||
|
try {
|
||||||
|
x = iframe.contentWindow.scrollX;
|
||||||
|
y = iframe.contentWindow.scrollY;
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
window.flutter_inappwebview.nativeCommunication('onScrollChanged', viewId, [x, y]);
|
||||||
|
});
|
||||||
|
|
||||||
|
iframe.contentWindow.addEventListener('focus', function (event) {
|
||||||
|
window.flutter_inappwebview.nativeCommunication('onWindowFocus', viewId);
|
||||||
|
});
|
||||||
|
|
||||||
|
iframe.contentWindow.addEventListener('blur', function (event) {
|
||||||
|
window.flutter_inappwebview.nativeCommunication('onWindowBlur', viewId);
|
||||||
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(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 {
|
try {
|
||||||
iframeUrl = iframe.contentWindow.location.href;
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
window.flutter_inappwebview.nativeCommunication('onUpdateVisitedHistory', window.flutter_inappwebview.viewId, [iframeUrl]);
|
|
||||||
};
|
|
||||||
|
|
||||||
var originalOpen = iframe.contentWindow.open;
|
if (!webView.settings.javaScriptCanOpenWindowsAutomatically) {
|
||||||
iframe.contentWindow.open = function (url, target, windowFeatures) {
|
iframe.contentWindow.open = function () {
|
||||||
var newWindow = originalOpen.call(iframe.contentWindow, ...arguments);
|
throw new Error('JavaScript cannot open windows automatically');
|
||||||
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) {
|
|
||||||
if (handledByClient) {
|
|
||||||
newWindow.close();
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
return newWindow;
|
|
||||||
};
|
|
||||||
|
|
||||||
var originalPrint = iframe.contentWindow.print;
|
if (!webView.settings.verticalScrollBarEnabled && !webView.settings.horizontalScrollBarEnabled) {
|
||||||
iframe.contentWindow.print = function () {
|
var style = iframe.contentDocument.createElement('style');
|
||||||
var iframeUrl = iframe.src;
|
style.id = "settings.verticalScrollBarEnabled-settings.horizontalScrollBarEnabled";
|
||||||
try {
|
style.innerHTML = "body::-webkit-scrollbar { width: 0px; height: 0px; }";
|
||||||
iframeUrl = iframe.contentWindow.location.href;
|
iframe.contentDocument.head.append(style);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (webView.settings.disableVerticalScroll) {
|
||||||
|
var style = iframe.contentDocument.createElement('style');
|
||||||
|
style.id = "settings.disableVerticalScroll";
|
||||||
|
style.innerHTML = "body { overflow-y: hidden; }";
|
||||||
|
iframe.contentDocument.head.append(style);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (webView.settings.disableHorizontalScroll) {
|
||||||
|
var style = iframe.contentDocument.createElement('style');
|
||||||
|
style.id = "settings.disableHorizontalScroll";
|
||||||
|
style.innerHTML = "body { overflow-x: hidden; }";
|
||||||
|
iframe.contentDocument.head.append(style);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (webView.settings.disableContextMenu) {
|
||||||
|
iframe.contentWindow.addEventListener('contextmenu', webView.disableContextMenuHandler);
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
}
|
}
|
||||||
window.flutter_inappwebview.nativeCommunication('onPrint', window.flutter_inappwebview.viewId, [iframeUrl]);
|
|
||||||
originalPrint.call(iframe.contentWindow);
|
|
||||||
};
|
|
||||||
|
|
||||||
window.flutter_inappwebview.functionMap = {
|
window.flutter_inappwebview.nativeCommunication('onLoadStop', viewId, [url]);
|
||||||
"window.open": iframe.contentWindow.open,
|
|
||||||
"window.print": iframe.contentWindow.print,
|
|
||||||
"window.history.pushState": iframe.contentWindow.history.pushState,
|
|
||||||
"window.history.replaceState": iframe.contentWindow.history.replaceState,
|
|
||||||
}
|
|
||||||
|
|
||||||
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 }
|
|
||||||
);
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
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]);
|
|
||||||
});
|
|
||||||
|
|
||||||
iframe.contentWindow.addEventListener('scroll', function (event) {
|
|
||||||
var x = 0;
|
|
||||||
var y = 0;
|
|
||||||
try {
|
|
||||||
x = iframe.contentWindow.scrollX;
|
|
||||||
y = iframe.contentWindow.scrollY;
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e);
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
setSettings: function (newSettings) {
|
||||||
|
var iframe = webView.iframe;
|
||||||
try {
|
try {
|
||||||
|
if (webView.settings.javaScriptCanOpenWindowsAutomatically != newSettings.javaScriptCanOpenWindowsAutomatically) {
|
||||||
if (!window.flutter_inappwebview.settings.javaScriptCanOpenWindowsAutomatically) {
|
if (!newSettings.javaScriptCanOpenWindowsAutomatically) {
|
||||||
iframe.contentWindow.open = function () {
|
iframe.contentWindow.open = function () {
|
||||||
throw new Error('JavaScript cannot open windows automatically');
|
throw new Error('JavaScript cannot open windows automatically');
|
||||||
};
|
};
|
||||||
|
} else {
|
||||||
|
iframe.contentWindow.open = webView.functionMap["window.open"];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!window.flutter_inappwebview.settings.verticalScrollBarEnabled && !window.flutter_inappwebview.settings.horizontalScrollBarEnabled) {
|
if (webView.settings.verticalScrollBarEnabled != newSettings.verticalScrollBarEnabled &&
|
||||||
var style = iframe.contentDocument.createElement('style');
|
webView.settings.horizontalScrollBarEnabled != newSettings.horizontalScrollBarEnabled) {
|
||||||
style.id = "settings.verticalScrollBarEnabled-settings.horizontalScrollBarEnabled";
|
if (!newSettings.verticalScrollBarEnabled && !newSettings.horizontalScrollBarEnabled) {
|
||||||
style.innerHTML = "body::-webkit-scrollbar { width: 0px; height: 0px; }";
|
var style = iframe.contentDocument.createElement('style');
|
||||||
iframe.contentDocument.head.append(style);
|
style.id = "settings.verticalScrollBarEnabled-settings.horizontalScrollBarEnabled";
|
||||||
|
style.innerHTML = "body::-webkit-scrollbar { width: 0px; height: 0px; }";
|
||||||
|
iframe.contentDocument.head.append(style);
|
||||||
|
} else {
|
||||||
|
var styleElement = iframe.contentDocument.getElementById("settings.verticalScrollBarEnabled-settings.horizontalScrollBarEnabled");
|
||||||
|
if (styleElement) { styleElement.remove() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (window.flutter_inappwebview.settings.disableVerticalScroll) {
|
if (webView.settings.disableVerticalScroll != newSettings.disableVerticalScroll) {
|
||||||
var style = iframe.contentDocument.createElement('style');
|
if (newSettings.disableVerticalScroll) {
|
||||||
style.id = "settings.disableVerticalScroll";
|
var style = iframe.contentDocument.createElement('style');
|
||||||
style.innerHTML = "body { overflow-y: hidden; }";
|
style.id = "settings.disableVerticalScroll";
|
||||||
iframe.contentDocument.head.append(style);
|
style.innerHTML = "body { overflow-y: hidden; }";
|
||||||
|
iframe.contentDocument.head.append(style);
|
||||||
|
} else {
|
||||||
|
var styleElement = iframe.contentDocument.getElementById("settings.disableVerticalScroll");
|
||||||
|
if (styleElement) { styleElement.remove() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (window.flutter_inappwebview.settings.disableHorizontalScroll) {
|
if (webView.settings.disableHorizontalScroll != newSettings.disableHorizontalScroll) {
|
||||||
var style = iframe.contentDocument.createElement('style');
|
if (newSettings.disableHorizontalScroll) {
|
||||||
style.id = "settings.disableHorizontalScroll";
|
var style = iframe.contentDocument.createElement('style');
|
||||||
style.innerHTML = "body { overflow-x: hidden; }";
|
style.id = "settings.disableHorizontalScroll";
|
||||||
iframe.contentDocument.head.append(style);
|
style.innerHTML = "body { overflow-x: hidden; }";
|
||||||
|
iframe.contentDocument.head.append(style);
|
||||||
|
} else {
|
||||||
|
var styleElement = iframe.contentDocument.getElementById("settings.disableHorizontalScroll");
|
||||||
|
if (styleElement) { styleElement.remove() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (webView.settings.disableContextMenu != newSettings.disableContextMenu) {
|
||||||
|
if (newSettings.disableContextMenu) {
|
||||||
|
iframe.contentWindow.addEventListener('contextmenu', webView.disableContextMenuHandler);
|
||||||
|
} else {
|
||||||
|
iframe.contentWindow.removeEventListener('contextmenu', webView.disableContextMenuHandler);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
window.flutter_inappwebview.nativeCommunication('onLoadStop', window.flutter_inappwebview.viewId, [url]);
|
webView.settings = newSettings;
|
||||||
});
|
},
|
||||||
}
|
reload: function () {
|
||||||
},
|
var iframe = webView.iframe;
|
||||||
setSettings: function (newSettings) {
|
if (iframe != null && iframe.contentWindow != null) {
|
||||||
var iframe = window.flutter_inappwebview.iframe;
|
try {
|
||||||
try {
|
iframe.contentWindow.location.reload();
|
||||||
if (window.flutter_inappwebview.settings.javaScriptCanOpenWindowsAutomatically != newSettings.javaScriptCanOpenWindowsAutomatically) {
|
} catch (e) {
|
||||||
if (!newSettings.javaScriptCanOpenWindowsAutomatically) {
|
console.log(e);
|
||||||
iframe.contentWindow.open = function () {
|
iframe.contentWindow.location.href = iframe.src;
|
||||||
throw new Error('JavaScript cannot open windows automatically');
|
}
|
||||||
};
|
}
|
||||||
} else {
|
},
|
||||||
iframe.contentWindow.open = window.flutter_inappwebview.functionMap["window.open"];
|
goBack: function () {
|
||||||
|
var iframe = webView.iframe;
|
||||||
|
if (iframe != null) {
|
||||||
|
try {
|
||||||
|
iframe.contentWindow.history.back();
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
goForward: function () {
|
||||||
|
var iframe = webView.iframe;
|
||||||
|
if (iframe != null) {
|
||||||
|
try {
|
||||||
|
iframe.contentWindow.history.forward();
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
goForwardOrForward: function (steps) {
|
||||||
|
var iframe = webView.iframe;
|
||||||
|
if (iframe != null) {
|
||||||
|
try {
|
||||||
|
iframe.contentWindow.history.go(steps);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
evaluateJavascript: function (source) {
|
||||||
|
var iframe = webView.iframe;
|
||||||
|
var result = null;
|
||||||
|
if (iframe != null) {
|
||||||
|
try {
|
||||||
|
result = JSON.stringify(iframe.contentWindow.eval(source));
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
stopLoading: function (steps) {
|
||||||
|
var iframe = webView.iframe;
|
||||||
|
if (iframe != null) {
|
||||||
|
try {
|
||||||
|
iframe.contentWindow.stop();
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (window.flutter_inappwebview.settings.verticalScrollBarEnabled != newSettings.verticalScrollBarEnabled &&
|
return webView;
|
||||||
window.flutter_inappwebview.settings.horizontalScrollBarEnabled != newSettings.horizontalScrollBarEnabled) {
|
|
||||||
if (!newSettings.verticalScrollBarEnabled && !newSettings.horizontalScrollBarEnabled) {
|
|
||||||
var style = iframe.contentDocument.createElement('style');
|
|
||||||
style.id = "settings.verticalScrollBarEnabled-settings.horizontalScrollBarEnabled";
|
|
||||||
style.innerHTML = "body::-webkit-scrollbar { width: 0px; height: 0px; }";
|
|
||||||
iframe.contentDocument.head.append(style);
|
|
||||||
} else {
|
|
||||||
var styleElement = iframe.contentDocument.getElementById("settings.verticalScrollBarEnabled-settings.horizontalScrollBarEnabled");
|
|
||||||
if (styleElement) { styleElement.remove() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (window.flutter_inappwebview.settings.disableVerticalScroll != newSettings.disableVerticalScroll) {
|
|
||||||
if (newSettings.disableVerticalScroll) {
|
|
||||||
var style = iframe.contentDocument.createElement('style');
|
|
||||||
style.id = "settings.disableVerticalScroll";
|
|
||||||
style.innerHTML = "body { overflow-y: hidden; }";
|
|
||||||
iframe.contentDocument.head.append(style);
|
|
||||||
} else {
|
|
||||||
var styleElement = iframe.contentDocument.getElementById("settings.disableVerticalScroll");
|
|
||||||
if (styleElement) { styleElement.remove() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (window.flutter_inappwebview.settings.disableHorizontalScroll != newSettings.disableHorizontalScroll) {
|
|
||||||
if (newSettings.disableHorizontalScroll) {
|
|
||||||
var style = iframe.contentDocument.createElement('style');
|
|
||||||
style.id = "settings.disableHorizontalScroll";
|
|
||||||
style.innerHTML = "body { overflow-x: hidden; }";
|
|
||||||
iframe.contentDocument.head.append(style);
|
|
||||||
} else {
|
|
||||||
var styleElement = iframe.contentDocument.getElementById("settings.disableHorizontalScroll");
|
|
||||||
if (styleElement) { styleElement.remove() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
window.flutter_inappwebview.settings = newSettings;
|
|
||||||
},
|
},
|
||||||
reload: function () {
|
getCookieExpirationDate: function(timestamp) {
|
||||||
var iframe = window.flutter_inappwebview.iframe;
|
return (new Date(timestamp)).toUTCString();
|
||||||
if (iframe != null && iframe.contentWindow != null) {
|
|
||||||
try {
|
|
||||||
iframe.contentWindow.location.reload();
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e);
|
|
||||||
iframe.contentWindow.location.href = iframe.src;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
goBack: function () {
|
|
||||||
var iframe = window.flutter_inappwebview.iframe;
|
|
||||||
if (iframe != null) {
|
|
||||||
try {
|
|
||||||
iframe.contentWindow.history.back();
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
goForward: function () {
|
|
||||||
var iframe = window.flutter_inappwebview.iframe;
|
|
||||||
if (iframe != null) {
|
|
||||||
try {
|
|
||||||
iframe.contentWindow.history.forward();
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
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;
|
|
||||||
if (iframe != null) {
|
|
||||||
try {
|
|
||||||
result = JSON.stringify(iframe.contentWindow.eval(source));
|
|
||||||
} catch (e) {}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
},
|
|
||||||
stopLoading: function (steps) {
|
|
||||||
var iframe = window.flutter_inappwebview.iframe;
|
|
||||||
if (iframe != null) {
|
|
||||||
try {
|
|
||||||
iframe.contentWindow.stop();
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
@ -36,6 +36,10 @@ class ChromeSafariBrowserNotOpenedException implements Exception {
|
|||||||
///**NOTE**: If you want to use the `ChromeSafariBrowser` class on Android 11+ you need to specify your app querying for
|
///**NOTE**: If you want to use the `ChromeSafariBrowser` class on Android 11+ you need to specify your app querying for
|
||||||
///`android.support.customtabs.action.CustomTabsService` in your `AndroidManifest.xml`
|
///`android.support.customtabs.action.CustomTabsService` in your `AndroidManifest.xml`
|
||||||
///(you can read more about it here: https://developers.google.com/web/android/custom-tabs/best-practices#applications_targeting_android_11_api_level_30_or_above).
|
///(you can read more about it here: https://developers.google.com/web/android/custom-tabs/best-practices#applications_targeting_android_11_api_level_30_or_above).
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Android native WebView
|
||||||
|
///- iOS
|
||||||
class ChromeSafariBrowser {
|
class ChromeSafariBrowser {
|
||||||
///View ID used internally.
|
///View ID used internally.
|
||||||
late final String id;
|
late final String id;
|
||||||
|
@ -6,6 +6,10 @@ import 'types.dart';
|
|||||||
///Class that represents the WebView context menu. It used by [WebView.contextMenu].
|
///Class that represents the WebView context menu. It used by [WebView.contextMenu].
|
||||||
///
|
///
|
||||||
///**NOTE**: To make it work properly on Android, JavaScript should be enabled!
|
///**NOTE**: To make it work properly on Android, JavaScript should be enabled!
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Android native WebView
|
||||||
|
///- iOS
|
||||||
class ContextMenu {
|
class ContextMenu {
|
||||||
///Event fired when the context menu for this WebView is being built.
|
///Event fired when the context menu for this WebView is being built.
|
||||||
///
|
///
|
||||||
|
@ -17,6 +17,15 @@ import 'types.dart';
|
|||||||
///**NOTE for iOS below 11.0 (LIMITED SUPPORT!)**: in this case, almost all of the methods ([CookieManager.deleteAllCookies] and [CookieManager.getAllCookies] are not supported!)
|
///**NOTE for iOS below 11.0 (LIMITED SUPPORT!)**: in this case, almost all of the methods ([CookieManager.deleteAllCookies] and [CookieManager.getAllCookies] are not supported!)
|
||||||
///has been implemented using JavaScript because there is no other way to work with them on iOS below 11.0.
|
///has been implemented using JavaScript because there is no other way to work with them on iOS below 11.0.
|
||||||
///See https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#restrict_access_to_cookies for JavaScript restrictions.
|
///See https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#restrict_access_to_cookies for JavaScript restrictions.
|
||||||
|
///
|
||||||
|
///**NOTE for Web (LIMITED SUPPORT!)**: in this case, almost all of the methods ([CookieManager.deleteAllCookies] and [CookieManager.getAllCookies] are not supported!)
|
||||||
|
///has been implemented using JavaScript, so all methods will have effect only if the iframe has the same origin.
|
||||||
|
///See https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#restrict_access_to_cookies for JavaScript restrictions.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Android native WebView
|
||||||
|
///- iOS
|
||||||
|
///- Web
|
||||||
class CookieManager {
|
class CookieManager {
|
||||||
static CookieManager? _instance;
|
static CookieManager? _instance;
|
||||||
static const MethodChannel _channel = const MethodChannel(
|
static const MethodChannel _channel = const MethodChannel(
|
||||||
@ -48,15 +57,20 @@ class CookieManager {
|
|||||||
///The default value of [path] is `"/"`.
|
///The default value of [path] is `"/"`.
|
||||||
///If [domain] is `null`, its default value will be the domain name of [url].
|
///If [domain] is `null`, its default value will be the domain name of [url].
|
||||||
///
|
///
|
||||||
///[iosBelow11WebViewController] could be used if you need to set a session-only cookie using JavaScript (so [isHttpOnly] cannot be set, see: https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#restrict_access_to_cookies)
|
///[webViewController] could be used if you need to set a session-only cookie using JavaScript (so [isHttpOnly] cannot be set, see: https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#restrict_access_to_cookies)
|
||||||
///on the current URL of the [WebView] managed by that controller when you need to target iOS below 11. In this case the [url] parameter is ignored.
|
///on the current URL of the [WebView] managed by that controller when you need to target iOS below 11 and Web platform. In this case the [url] parameter is ignored.
|
||||||
///
|
///
|
||||||
///**NOTE for iOS below 11.0**: If [iosBelow11WebViewController] is `null` or JavaScript is disabled for it, it will try to use a [HeadlessInAppWebView]
|
///**NOTE for iOS below 11.0**: If [webViewController] is `null` or JavaScript is disabled for it, it will try to use a [HeadlessInAppWebView]
|
||||||
|
///to set the cookie (session-only cookie won't work! In that case, you should set also [expiresDate] or [maxAge]).
|
||||||
|
///
|
||||||
|
///**NOTE for Web**: this method will have effect only if the iframe has the same origin.
|
||||||
|
///If [webViewController] is `null` or JavaScript is disabled for it, it will try to use a [HeadlessInAppWebView]
|
||||||
///to set the cookie (session-only cookie won't work! In that case, you should set also [expiresDate] or [maxAge]).
|
///to set the cookie (session-only cookie won't work! In that case, you should set also [expiresDate] or [maxAge]).
|
||||||
///
|
///
|
||||||
///**Supported Platforms/Implementations**:
|
///**Supported Platforms/Implementations**:
|
||||||
///- Android native WebView ([Official API - CookieManager.setCookie](https://developer.android.com/reference/android/webkit/CookieManager#setCookie(java.lang.String,%20java.lang.String,%20android.webkit.ValueCallback%3Cjava.lang.Boolean%3E)))
|
///- Android native WebView ([Official API - CookieManager.setCookie](https://developer.android.com/reference/android/webkit/CookieManager#setCookie(java.lang.String,%20java.lang.String,%20android.webkit.ValueCallback%3Cjava.lang.Boolean%3E)))
|
||||||
///- iOS ([Official API - WKHTTPCookieStore.setCookie](https://developer.apple.com/documentation/webkit/wkhttpcookiestore/2882007-setcookie))
|
///- iOS ([Official API - WKHTTPCookieStore.setCookie](https://developer.apple.com/documentation/webkit/wkhttpcookiestore/2882007-setcookie))
|
||||||
|
///- Web
|
||||||
Future<void> setCookie(
|
Future<void> setCookie(
|
||||||
{required Uri url,
|
{required Uri url,
|
||||||
required String name,
|
required String name,
|
||||||
@ -68,19 +82,26 @@ class CookieManager {
|
|||||||
bool? isSecure,
|
bool? isSecure,
|
||||||
bool? isHttpOnly,
|
bool? isHttpOnly,
|
||||||
HTTPCookieSameSitePolicy? sameSite,
|
HTTPCookieSameSitePolicy? sameSite,
|
||||||
InAppWebViewController? iosBelow11WebViewController}) async {
|
@Deprecated("Use webViewController instead") InAppWebViewController? iosBelow11WebViewController,
|
||||||
|
InAppWebViewController? webViewController}) async {
|
||||||
if (domain == null) domain = _getDomainName(url);
|
if (domain == null) domain = _getDomainName(url);
|
||||||
|
|
||||||
|
webViewController = webViewController ?? iosBelow11WebViewController;
|
||||||
|
|
||||||
assert(url.toString().isNotEmpty);
|
assert(url.toString().isNotEmpty);
|
||||||
assert(name.isNotEmpty);
|
assert(name.isNotEmpty);
|
||||||
assert(value.isNotEmpty);
|
assert(value.isNotEmpty);
|
||||||
assert(domain.isNotEmpty);
|
assert(domain.isNotEmpty);
|
||||||
assert(path.isNotEmpty);
|
assert(path.isNotEmpty);
|
||||||
|
|
||||||
if (defaultTargetPlatform == TargetPlatform.iOS) {
|
if (defaultTargetPlatform == TargetPlatform.iOS || kIsWeb) {
|
||||||
var platformUtil = PlatformUtil();
|
var shouldUseJavascript = kIsWeb;
|
||||||
var version = double.tryParse(await platformUtil.getSystemVersion());
|
if (defaultTargetPlatform == TargetPlatform.iOS && !kIsWeb) {
|
||||||
if (version != null && version < 11.0) {
|
var platformUtil = PlatformUtil.instance();
|
||||||
|
var version = double.tryParse(await platformUtil.getSystemVersion());
|
||||||
|
shouldUseJavascript = version != null && version < 11.0;
|
||||||
|
}
|
||||||
|
if (shouldUseJavascript) {
|
||||||
await _setCookieWithJavaScript(
|
await _setCookieWithJavaScript(
|
||||||
url: url,
|
url: url,
|
||||||
name: name,
|
name: name,
|
||||||
@ -91,7 +112,7 @@ class CookieManager {
|
|||||||
maxAge: maxAge,
|
maxAge: maxAge,
|
||||||
isSecure: isSecure,
|
isSecure: isSecure,
|
||||||
sameSite: sameSite,
|
sameSite: sameSite,
|
||||||
webViewController: iosBelow11WebViewController);
|
webViewController: webViewController);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -161,28 +182,40 @@ class CookieManager {
|
|||||||
|
|
||||||
///Gets all the cookies for the given [url].
|
///Gets all the cookies for the given [url].
|
||||||
///
|
///
|
||||||
///[iosBelow11WebViewController] is used for getting the cookies (also session-only cookies) using JavaScript (cookies with `isHttpOnly` enabled cannot be found, see: https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#restrict_access_to_cookies)
|
///[webViewController] is used for getting the cookies (also session-only cookies) using JavaScript (cookies with `isHttpOnly` enabled cannot be found, see: https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#restrict_access_to_cookies)
|
||||||
///from the current context of the [WebView] managed by that controller when you need to target iOS below 11. JavaScript must be enabled in order to work.
|
///from the current context of the [WebView] managed by that controller when you need to target iOS below 11 and Web platform. JavaScript must be enabled in order to work.
|
||||||
///In this case the [url] parameter is ignored.
|
///In this case the [url] parameter is ignored.
|
||||||
///
|
///
|
||||||
///**NOTE for iOS below 11.0**: All the cookies returned this way will have all the properties to `null` except for [Cookie.name] and [Cookie.value].
|
///**NOTE for iOS below 11.0**: All the cookies returned this way will have all the properties to `null` except for [Cookie.name] and [Cookie.value].
|
||||||
///If [iosBelow11WebViewController] is `null` or JavaScript is disabled for it, it will try to use a [HeadlessInAppWebView]
|
///If [webViewController] is `null` or JavaScript is disabled for it, it will try to use a [HeadlessInAppWebView]
|
||||||
|
///to get the cookies (session-only cookies and cookies with `isHttpOnly` enabled won't be found!).
|
||||||
|
///
|
||||||
|
///**NOTE for Web**: this method will have effect only if the iframe has the same origin.
|
||||||
|
///If [webViewController] is `null` or JavaScript is disabled for it, it will try to use a [HeadlessInAppWebView]
|
||||||
///to get the cookies (session-only cookies and cookies with `isHttpOnly` enabled won't be found!).
|
///to get the cookies (session-only cookies and cookies with `isHttpOnly` enabled won't be found!).
|
||||||
///
|
///
|
||||||
///**Supported Platforms/Implementations**:
|
///**Supported Platforms/Implementations**:
|
||||||
///- Android native WebView ([Official API - CookieManager.getCookie](https://developer.android.com/reference/android/webkit/CookieManager#getCookie(java.lang.String)))
|
///- Android native WebView ([Official API - CookieManager.getCookie](https://developer.android.com/reference/android/webkit/CookieManager#getCookie(java.lang.String)))
|
||||||
///- iOS ([Official API - WKHTTPCookieStore.getAllCookies](https://developer.apple.com/documentation/webkit/wkhttpcookiestore/2882005-getallcookies))
|
///- iOS ([Official API - WKHTTPCookieStore.getAllCookies](https://developer.apple.com/documentation/webkit/wkhttpcookiestore/2882005-getallcookies))
|
||||||
|
///- Web
|
||||||
Future<List<Cookie>> getCookies(
|
Future<List<Cookie>> getCookies(
|
||||||
{required Uri url,
|
{required Uri url,
|
||||||
InAppWebViewController? iosBelow11WebViewController}) async {
|
@Deprecated("Use webViewController instead") InAppWebViewController? iosBelow11WebViewController,
|
||||||
|
InAppWebViewController? webViewController}) async {
|
||||||
assert(url.toString().isNotEmpty);
|
assert(url.toString().isNotEmpty);
|
||||||
|
|
||||||
if (defaultTargetPlatform == TargetPlatform.iOS) {
|
webViewController = webViewController ?? iosBelow11WebViewController;
|
||||||
var platformUtil = PlatformUtil();
|
|
||||||
var version = double.tryParse(await platformUtil.getSystemVersion());
|
if (defaultTargetPlatform == TargetPlatform.iOS || kIsWeb) {
|
||||||
if (version != null && version < 11.0) {
|
var shouldUseJavascript = kIsWeb;
|
||||||
|
if (defaultTargetPlatform == TargetPlatform.iOS && !kIsWeb) {
|
||||||
|
var platformUtil = PlatformUtil.instance();
|
||||||
|
var version = double.tryParse(await platformUtil.getSystemVersion());
|
||||||
|
shouldUseJavascript = version != null && version < 11.0;
|
||||||
|
}
|
||||||
|
if (shouldUseJavascript) {
|
||||||
return await _getCookiesWithJavaScript(
|
return await _getCookiesWithJavaScript(
|
||||||
url: url, webViewController: iosBelow11WebViewController);
|
url: url, webViewController: webViewController);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,10 +258,12 @@ class CookieManager {
|
|||||||
.toList();
|
.toList();
|
||||||
documentCookies.forEach((documentCookie) {
|
documentCookies.forEach((documentCookie) {
|
||||||
List<String> cookie = documentCookie.split('=');
|
List<String> cookie = documentCookie.split('=');
|
||||||
cookies.add(Cookie(
|
if (cookie.length > 1) {
|
||||||
name: cookie[0],
|
cookies.add(Cookie(
|
||||||
value: cookie[1],
|
name: cookie[0],
|
||||||
));
|
value: cookie[1],
|
||||||
|
));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return cookies;
|
return cookies;
|
||||||
}
|
}
|
||||||
@ -251,10 +286,12 @@ class CookieManager {
|
|||||||
.toList();
|
.toList();
|
||||||
documentCookies.forEach((documentCookie) {
|
documentCookies.forEach((documentCookie) {
|
||||||
List<String> cookie = documentCookie.split('=');
|
List<String> cookie = documentCookie.split('=');
|
||||||
cookies.add(Cookie(
|
if (cookie.length > 1) {
|
||||||
name: cookie[0],
|
cookies.add(Cookie(
|
||||||
value: cookie[1],
|
name: cookie[0],
|
||||||
));
|
value: cookie[1],
|
||||||
|
));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
await headlessWebView.dispose();
|
await headlessWebView.dispose();
|
||||||
return cookies;
|
return cookies;
|
||||||
@ -262,30 +299,42 @@ class CookieManager {
|
|||||||
|
|
||||||
///Gets a cookie by its [name] for the given [url].
|
///Gets a cookie by its [name] for the given [url].
|
||||||
///
|
///
|
||||||
///[iosBelow11WebViewController] is used for getting the cookie (also session-only cookie) using JavaScript (cookie with `isHttpOnly` enabled cannot be found, see: https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#restrict_access_to_cookies)
|
///[webViewController] is used for getting the cookie (also session-only cookie) using JavaScript (cookie with `isHttpOnly` enabled cannot be found, see: https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#restrict_access_to_cookies)
|
||||||
///from the current context of the [WebView] managed by that controller when you need to target iOS below 11. JavaScript must be enabled in order to work.
|
///from the current context of the [WebView] managed by that controller when you need to target iOS below 11 and Web platform. JavaScript must be enabled in order to work.
|
||||||
///In this case the [url] parameter is ignored.
|
///In this case the [url] parameter is ignored.
|
||||||
///
|
///
|
||||||
///**NOTE for iOS below 11.0**: All the cookies returned this way will have all the properties to `null` except for [Cookie.name] and [Cookie.value].
|
///**NOTE for iOS below 11.0**: All the cookies returned this way will have all the properties to `null` except for [Cookie.name] and [Cookie.value].
|
||||||
///If [iosBelow11WebViewController] is `null` or JavaScript is disabled for it, it will try to use a [HeadlessInAppWebView]
|
///If [webViewController] is `null` or JavaScript is disabled for it, it will try to use a [HeadlessInAppWebView]
|
||||||
|
///to get the cookie (session-only cookie and cookie with `isHttpOnly` enabled won't be found!).
|
||||||
|
///
|
||||||
|
///**NOTE for Web**: this method will have effect only if the iframe has the same origin.
|
||||||
|
///If [webViewController] is `null` or JavaScript is disabled for it, it will try to use a [HeadlessInAppWebView]
|
||||||
///to get the cookie (session-only cookie and cookie with `isHttpOnly` enabled won't be found!).
|
///to get the cookie (session-only cookie and cookie with `isHttpOnly` enabled won't be found!).
|
||||||
///
|
///
|
||||||
///**Supported Platforms/Implementations**:
|
///**Supported Platforms/Implementations**:
|
||||||
///- Android native WebView
|
///- Android native WebView
|
||||||
///- iOS
|
///- iOS
|
||||||
|
///- Web
|
||||||
Future<Cookie?> getCookie(
|
Future<Cookie?> getCookie(
|
||||||
{required Uri url,
|
{required Uri url,
|
||||||
required String name,
|
required String name,
|
||||||
InAppWebViewController? iosBelow11WebViewController}) async {
|
@Deprecated("Use webViewController instead") InAppWebViewController? iosBelow11WebViewController,
|
||||||
|
InAppWebViewController? webViewController}) async {
|
||||||
assert(url.toString().isNotEmpty);
|
assert(url.toString().isNotEmpty);
|
||||||
assert(name.isNotEmpty);
|
assert(name.isNotEmpty);
|
||||||
|
|
||||||
if (defaultTargetPlatform == TargetPlatform.iOS) {
|
webViewController = webViewController ?? iosBelow11WebViewController;
|
||||||
var platformUtil = PlatformUtil();
|
|
||||||
var version = double.tryParse(await platformUtil.getSystemVersion());
|
if (defaultTargetPlatform == TargetPlatform.iOS || kIsWeb) {
|
||||||
if (version != null && version < 11.0) {
|
var shouldUseJavascript = kIsWeb;
|
||||||
|
if (defaultTargetPlatform == TargetPlatform.iOS && !kIsWeb) {
|
||||||
|
var platformUtil = PlatformUtil.instance();
|
||||||
|
var version = double.tryParse(await platformUtil.getSystemVersion());
|
||||||
|
shouldUseJavascript = version != null && version < 11.0;
|
||||||
|
}
|
||||||
|
if (shouldUseJavascript) {
|
||||||
List<Cookie> cookies = await _getCookiesWithJavaScript(
|
List<Cookie> cookies = await _getCookiesWithJavaScript(
|
||||||
url: url, webViewController: iosBelow11WebViewController);
|
url: url, webViewController: webViewController);
|
||||||
return cookies
|
return cookies
|
||||||
.cast<Cookie?>()
|
.cast<Cookie?>()
|
||||||
.firstWhere((cookie) => cookie!.name == name, orElse: () => null);
|
.firstWhere((cookie) => cookie!.name == name, orElse: () => null);
|
||||||
@ -319,31 +368,43 @@ class CookieManager {
|
|||||||
///The default value of [path] is `"/"`.
|
///The default value of [path] is `"/"`.
|
||||||
///If [domain] is empty, its default value will be the domain name of [url].
|
///If [domain] is empty, its default value will be the domain name of [url].
|
||||||
///
|
///
|
||||||
///[iosBelow11WebViewController] is used for deleting the cookie (also session-only cookie) using JavaScript (cookie with `isHttpOnly` enabled cannot be deleted, see: https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#restrict_access_to_cookies)
|
///[webViewController] is used for deleting the cookie (also session-only cookie) using JavaScript (cookie with `isHttpOnly` enabled cannot be deleted, see: https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#restrict_access_to_cookies)
|
||||||
///from the current context of the [WebView] managed by that controller when you need to target iOS below 11. JavaScript must be enabled in order to work.
|
///from the current context of the [WebView] managed by that controller when you need to target iOS below 11 and Web platform. JavaScript must be enabled in order to work.
|
||||||
///In this case the [url] parameter is ignored.
|
///In this case the [url] parameter is ignored.
|
||||||
///
|
///
|
||||||
///**NOTE for iOS below 11.0**: If [iosBelow11WebViewController] is `null` or JavaScript is disabled for it, it will try to use a [HeadlessInAppWebView]
|
///**NOTE for iOS below 11.0**: If [webViewController] is `null` or JavaScript is disabled for it, it will try to use a [HeadlessInAppWebView]
|
||||||
|
///to delete the cookie (session-only cookie and cookie with `isHttpOnly` enabled won't be deleted!).
|
||||||
|
///
|
||||||
|
///**NOTE for Web**: this method will have effect only if the iframe has the same origin.
|
||||||
|
///If [webViewController] is `null` or JavaScript is disabled for it, it will try to use a [HeadlessInAppWebView]
|
||||||
///to delete the cookie (session-only cookie and cookie with `isHttpOnly` enabled won't be deleted!).
|
///to delete the cookie (session-only cookie and cookie with `isHttpOnly` enabled won't be deleted!).
|
||||||
///
|
///
|
||||||
///**Supported Platforms/Implementations**:
|
///**Supported Platforms/Implementations**:
|
||||||
///- Android native WebView
|
///- Android native WebView
|
||||||
///- iOS ([Official API - WKHTTPCookieStore.delete](https://developer.apple.com/documentation/webkit/wkhttpcookiestore/2882009-delete)
|
///- iOS ([Official API - WKHTTPCookieStore.delete](https://developer.apple.com/documentation/webkit/wkhttpcookiestore/2882009-delete)
|
||||||
|
///- Web
|
||||||
Future<void> deleteCookie(
|
Future<void> deleteCookie(
|
||||||
{required Uri url,
|
{required Uri url,
|
||||||
required String name,
|
required String name,
|
||||||
String domain = "",
|
String domain = "",
|
||||||
String path = "/",
|
String path = "/",
|
||||||
InAppWebViewController? iosBelow11WebViewController}) async {
|
@Deprecated("Use webViewController instead") InAppWebViewController? iosBelow11WebViewController,
|
||||||
|
InAppWebViewController? webViewController}) async {
|
||||||
if (domain.isEmpty) domain = _getDomainName(url);
|
if (domain.isEmpty) domain = _getDomainName(url);
|
||||||
|
|
||||||
assert(url.toString().isNotEmpty);
|
assert(url.toString().isNotEmpty);
|
||||||
assert(name.isNotEmpty);
|
assert(name.isNotEmpty);
|
||||||
|
|
||||||
if (defaultTargetPlatform == TargetPlatform.iOS) {
|
webViewController = webViewController ?? iosBelow11WebViewController;
|
||||||
var platformUtil = PlatformUtil();
|
|
||||||
var version = double.tryParse(await platformUtil.getSystemVersion());
|
if (defaultTargetPlatform == TargetPlatform.iOS || kIsWeb) {
|
||||||
if (version != null && version < 11.0) {
|
var shouldUseJavascript = kIsWeb;
|
||||||
|
if (defaultTargetPlatform == TargetPlatform.iOS && !kIsWeb) {
|
||||||
|
var platformUtil = PlatformUtil.instance();
|
||||||
|
var version = double.tryParse(await platformUtil.getSystemVersion());
|
||||||
|
shouldUseJavascript = version != null && version < 11.0;
|
||||||
|
}
|
||||||
|
if (shouldUseJavascript) {
|
||||||
await _setCookieWithJavaScript(
|
await _setCookieWithJavaScript(
|
||||||
url: url,
|
url: url,
|
||||||
name: name,
|
name: name,
|
||||||
@ -351,7 +412,7 @@ class CookieManager {
|
|||||||
path: path,
|
path: path,
|
||||||
domain: domain,
|
domain: domain,
|
||||||
maxAge: -1,
|
maxAge: -1,
|
||||||
webViewController: iosBelow11WebViewController);
|
webViewController: webViewController);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -369,31 +430,43 @@ class CookieManager {
|
|||||||
///The default value of [path] is `"/"`.
|
///The default value of [path] is `"/"`.
|
||||||
///If [domain] is empty, its default value will be the domain name of [url].
|
///If [domain] is empty, its default value will be the domain name of [url].
|
||||||
///
|
///
|
||||||
///[iosBelow11WebViewController] is used for deleting the cookies (also session-only cookies) using JavaScript (cookies with `isHttpOnly` enabled cannot be deleted, see: https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#restrict_access_to_cookies)
|
///[webViewController] is used for deleting the cookies (also session-only cookies) using JavaScript (cookies with `isHttpOnly` enabled cannot be deleted, see: https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#restrict_access_to_cookies)
|
||||||
///from the current context of the [WebView] managed by that controller when you need to target iOS below 11. JavaScript must be enabled in order to work.
|
///from the current context of the [WebView] managed by that controller when you need to target iOS below 11 and Web platform. JavaScript must be enabled in order to work.
|
||||||
///In this case the [url] parameter is ignored.
|
///In this case the [url] parameter is ignored.
|
||||||
///
|
///
|
||||||
///**NOTE for iOS below 11.0**: If [iosBelow11WebViewController] is `null` or JavaScript is disabled for it, it will try to use a [HeadlessInAppWebView]
|
///**NOTE for iOS below 11.0**: If [webViewController] is `null` or JavaScript is disabled for it, it will try to use a [HeadlessInAppWebView]
|
||||||
|
///to delete the cookies (session-only cookies and cookies with `isHttpOnly` enabled won't be deleted!).
|
||||||
|
///
|
||||||
|
///**NOTE for Web**: this method will have effect only if the iframe has the same origin.
|
||||||
|
///If [webViewController] is `null` or JavaScript is disabled for it, it will try to use a [HeadlessInAppWebView]
|
||||||
///to delete the cookies (session-only cookies and cookies with `isHttpOnly` enabled won't be deleted!).
|
///to delete the cookies (session-only cookies and cookies with `isHttpOnly` enabled won't be deleted!).
|
||||||
///
|
///
|
||||||
///**Supported Platforms/Implementations**:
|
///**Supported Platforms/Implementations**:
|
||||||
///- Android native WebView
|
///- Android native WebView
|
||||||
///- iOS
|
///- iOS
|
||||||
|
///- Web
|
||||||
Future<void> deleteCookies(
|
Future<void> deleteCookies(
|
||||||
{required Uri url,
|
{required Uri url,
|
||||||
String domain = "",
|
String domain = "",
|
||||||
String path = "/",
|
String path = "/",
|
||||||
InAppWebViewController? iosBelow11WebViewController}) async {
|
@Deprecated("Use webViewController instead") InAppWebViewController? iosBelow11WebViewController,
|
||||||
|
InAppWebViewController? webViewController}) async {
|
||||||
if (domain.isEmpty) domain = _getDomainName(url);
|
if (domain.isEmpty) domain = _getDomainName(url);
|
||||||
|
|
||||||
assert(url.toString().isNotEmpty);
|
assert(url.toString().isNotEmpty);
|
||||||
|
|
||||||
if (defaultTargetPlatform == TargetPlatform.iOS) {
|
webViewController = webViewController ?? iosBelow11WebViewController;
|
||||||
var platformUtil = PlatformUtil();
|
|
||||||
var version = double.tryParse(await platformUtil.getSystemVersion());
|
if (defaultTargetPlatform == TargetPlatform.iOS || kIsWeb) {
|
||||||
if (version != null && version < 11.0) {
|
var shouldUseJavascript = kIsWeb;
|
||||||
|
if (defaultTargetPlatform == TargetPlatform.iOS && !kIsWeb) {
|
||||||
|
var platformUtil = PlatformUtil.instance();
|
||||||
|
var version = double.tryParse(await platformUtil.getSystemVersion());
|
||||||
|
shouldUseJavascript = version != null && version < 11.0;
|
||||||
|
}
|
||||||
|
if (shouldUseJavascript) {
|
||||||
List<Cookie> cookies = await _getCookiesWithJavaScript(
|
List<Cookie> cookies = await _getCookiesWithJavaScript(
|
||||||
url: url, webViewController: iosBelow11WebViewController);
|
url: url, webViewController: webViewController);
|
||||||
for (var i = 0; i < cookies.length; i++) {
|
for (var i = 0; i < cookies.length; i++) {
|
||||||
await _setCookieWithJavaScript(
|
await _setCookieWithJavaScript(
|
||||||
url: url,
|
url: url,
|
||||||
@ -402,7 +475,7 @@ class CookieManager {
|
|||||||
path: path,
|
path: path,
|
||||||
domain: domain,
|
domain: domain,
|
||||||
maxAge: -1,
|
maxAge: -1,
|
||||||
webViewController: iosBelow11WebViewController);
|
webViewController: webViewController);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -462,13 +535,15 @@ class CookieManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<String> _getCookieExpirationDate(int expiresDate) async {
|
Future<String> _getCookieExpirationDate(int expiresDate) async {
|
||||||
var platformUtil = PlatformUtil();
|
var platformUtil = PlatformUtil.instance();
|
||||||
var dateTime = DateTime.fromMillisecondsSinceEpoch(expiresDate).toUtc();
|
var dateTime = DateTime.fromMillisecondsSinceEpoch(expiresDate).toUtc();
|
||||||
return await platformUtil.formatDate(
|
return !kIsWeb ?
|
||||||
date: dateTime,
|
await platformUtil.formatDate(
|
||||||
format: 'EEE, dd MMM yyyy hh:mm:ss z',
|
date: dateTime,
|
||||||
locale: 'en_US',
|
format: 'EEE, dd MMM yyyy hh:mm:ss z',
|
||||||
timezone: 'GMT');
|
locale: 'en_US',
|
||||||
|
timezone: 'GMT') :
|
||||||
|
await platformUtil.getWebCookieExpirationDate(date: dateTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,10 @@ import 'package:flutter/services.dart';
|
|||||||
///On Android, this class has a custom implementation using `android.database.sqlite.SQLiteDatabase` because
|
///On Android, this class has a custom implementation using `android.database.sqlite.SQLiteDatabase` because
|
||||||
///[WebViewDatabase](https://developer.android.com/reference/android/webkit/WebViewDatabase)
|
///[WebViewDatabase](https://developer.android.com/reference/android/webkit/WebViewDatabase)
|
||||||
///doesn't offer the same functionalities as iOS `URLCredentialStorage`.
|
///doesn't offer the same functionalities as iOS `URLCredentialStorage`.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Android native WebView
|
||||||
|
///- iOS
|
||||||
class HttpAuthCredentialDatabase {
|
class HttpAuthCredentialDatabase {
|
||||||
static HttpAuthCredentialDatabase? _instance;
|
static HttpAuthCredentialDatabase? _instance;
|
||||||
static const MethodChannel _channel = const MethodChannel(
|
static const MethodChannel _channel = const MethodChannel(
|
||||||
|
@ -40,6 +40,10 @@ class InAppBrowserNotOpenedException implements Exception {
|
|||||||
|
|
||||||
///This class uses the native WebView of the platform.
|
///This class uses the native WebView of the platform.
|
||||||
///The [webViewController] field can be used to access the [InAppWebViewController] API.
|
///The [webViewController] field can be used to access the [InAppWebViewController] API.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Android native WebView
|
||||||
|
///- iOS
|
||||||
class InAppBrowser {
|
class InAppBrowser {
|
||||||
///View ID used internally.
|
///View ID used internally.
|
||||||
late final String id;
|
late final String id;
|
||||||
|
@ -7,6 +7,10 @@ import 'package:flutter/services.dart' show rootBundle;
|
|||||||
import 'mime_type_resolver.dart';
|
import 'mime_type_resolver.dart';
|
||||||
|
|
||||||
///This class allows you to create a simple server on `http://localhost:[port]/` in order to be able to load your assets file on a server. The default [port] value is `8080`.
|
///This class allows you to create a simple server on `http://localhost:[port]/` in order to be able to load your assets file on a server. The default [port] value is `8080`.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Android native WebView
|
||||||
|
///- iOS
|
||||||
class InAppLocalhostServer {
|
class InAppLocalhostServer {
|
||||||
bool _started = false;
|
bool _started = false;
|
||||||
HttpServer? _server;
|
HttpServer? _server;
|
||||||
|
@ -18,6 +18,11 @@ import '../util.dart';
|
|||||||
///It can be used to run a WebView in background without attaching an `InAppWebView` to the widget tree.
|
///It can be used to run a WebView in background without attaching an `InAppWebView` to the widget tree.
|
||||||
///
|
///
|
||||||
///Remember to dispose it when you don't need it anymore.
|
///Remember to dispose it when you don't need it anymore.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Android native WebView
|
||||||
|
///- iOS
|
||||||
|
///- Web
|
||||||
class HeadlessInAppWebView implements WebView {
|
class HeadlessInAppWebView implements WebView {
|
||||||
///View ID.
|
///View ID.
|
||||||
late final String id;
|
late final String id;
|
||||||
|
@ -20,6 +20,11 @@ import 'in_app_webview_settings.dart';
|
|||||||
import '../pull_to_refresh/main.dart';
|
import '../pull_to_refresh/main.dart';
|
||||||
|
|
||||||
///Flutter Widget for adding an **inline native WebView** integrated in the flutter widget tree.
|
///Flutter Widget for adding an **inline native WebView** integrated in the flutter widget tree.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Android native WebView
|
||||||
|
///- iOS
|
||||||
|
///- Web
|
||||||
class InAppWebView extends StatefulWidget implements WebView {
|
class InAppWebView extends StatefulWidget implements WebView {
|
||||||
/// `gestureRecognizers` specifies which gestures should be consumed by the WebView.
|
/// `gestureRecognizers` specifies which gestures should be consumed by the WebView.
|
||||||
/// It is possible for other gesture recognizers to be competing with the web view on pointer
|
/// It is possible for other gesture recognizers to be competing with the web view on pointer
|
||||||
|
@ -228,9 +228,12 @@ class InAppWebViewSettings
|
|||||||
|
|
||||||
///Set to `true` to disable context menu. The default value is `false`.
|
///Set to `true` to disable context menu. The default value is `false`.
|
||||||
///
|
///
|
||||||
|
///**NOTE for Web**: this setting will have effect only if the iframe has the same origin.
|
||||||
|
///
|
||||||
///**Supported Platforms/Implementations**:
|
///**Supported Platforms/Implementations**:
|
||||||
///- Android native WebView
|
///- Android native WebView
|
||||||
///- iOS
|
///- iOS
|
||||||
|
///- Web
|
||||||
bool disableContextMenu;
|
bool disableContextMenu;
|
||||||
|
|
||||||
///Set to `false` if the WebView should not support zooming using its on-screen zoom controls and gestures. The default value is `true`.
|
///Set to `false` if the WebView should not support zooming using its on-screen zoom controls and gestures. The default value is `true`.
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
|
///Platform native utilities
|
||||||
class PlatformUtil {
|
class PlatformUtil {
|
||||||
static PlatformUtil? _instance;
|
static PlatformUtil? _instance;
|
||||||
static const MethodChannel _channel = const MethodChannel(
|
static const MethodChannel _channel = const MethodChannel(
|
||||||
'com.pichillilorenzo/flutter_inappwebview_platformutil');
|
'com.pichillilorenzo/flutter_inappwebview_platformutil');
|
||||||
|
|
||||||
|
///Get [PlatformUtil] instance.
|
||||||
static PlatformUtil instance() {
|
static PlatformUtil instance() {
|
||||||
return (_instance != null) ? _instance! : _init();
|
return (_instance != null) ? _instance! : _init();
|
||||||
}
|
}
|
||||||
@ -18,6 +20,8 @@ class PlatformUtil {
|
|||||||
static Future<dynamic> _handleMethod(MethodCall call) async {}
|
static Future<dynamic> _handleMethod(MethodCall call) async {}
|
||||||
|
|
||||||
String? _cachedSystemVersion;
|
String? _cachedSystemVersion;
|
||||||
|
|
||||||
|
///Get current platform system version.
|
||||||
Future<String> getSystemVersion() async {
|
Future<String> getSystemVersion() async {
|
||||||
if (_cachedSystemVersion != null) {
|
if (_cachedSystemVersion != null) {
|
||||||
return _cachedSystemVersion!;
|
return _cachedSystemVersion!;
|
||||||
@ -28,6 +32,7 @@ class PlatformUtil {
|
|||||||
return _cachedSystemVersion!;
|
return _cachedSystemVersion!;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///Format date.
|
||||||
Future<String> formatDate(
|
Future<String> formatDate(
|
||||||
{required DateTime date,
|
{required DateTime date,
|
||||||
required String format,
|
required String format,
|
||||||
@ -40,4 +45,12 @@ class PlatformUtil {
|
|||||||
args.putIfAbsent('timezone', () => timezone);
|
args.putIfAbsent('timezone', () => timezone);
|
||||||
return await _channel.invokeMethod('formatDate', args);
|
return await _channel.invokeMethod('formatDate', args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///Get cookie expiration date used by Web platform.
|
||||||
|
Future<String> getWebCookieExpirationDate(
|
||||||
|
{required DateTime date}) async {
|
||||||
|
Map<String, dynamic> args = <String, dynamic>{};
|
||||||
|
args.putIfAbsent('date', () => date.millisecondsSinceEpoch);
|
||||||
|
return await _channel.invokeMethod('getWebCookieExpirationDate', args);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,10 @@ import 'pull_to_refresh_settings.dart';
|
|||||||
///(for example [WebView.onWebViewCreated] or [InAppBrowser.onBrowserCreated]).
|
///(for example [WebView.onWebViewCreated] or [InAppBrowser.onBrowserCreated]).
|
||||||
///
|
///
|
||||||
///**NOTE for Android**: to be able to use the "pull-to-refresh" feature, [InAppWebViewSettings.useHybridComposition] must be `true`.
|
///**NOTE for Android**: to be able to use the "pull-to-refresh" feature, [InAppWebViewSettings.useHybridComposition] must be `true`.
|
||||||
|
///
|
||||||
|
///**Supported Platforms/Implementations**:
|
||||||
|
///- Android native WebView
|
||||||
|
///- iOS
|
||||||
class PullToRefreshController {
|
class PullToRefreshController {
|
||||||
@Deprecated("Use settings instead")
|
@Deprecated("Use settings instead")
|
||||||
// ignore: deprecated_member_use_from_same_package
|
// ignore: deprecated_member_use_from_same_package
|
||||||
|
@ -184,6 +184,20 @@ class InAppWebViewInitialData {
|
|||||||
this.androidHistoryUrl = this.historyUrl;
|
this.androidHistoryUrl = this.historyUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static InAppWebViewInitialData? fromMap(Map<String, dynamic>? map) {
|
||||||
|
if (map == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return InAppWebViewInitialData(
|
||||||
|
data: map["data"],
|
||||||
|
mimeType: map["mimeType"],
|
||||||
|
encoding: map["encoding"],
|
||||||
|
baseUrl: map["baseUrl"],
|
||||||
|
// ignore: deprecated_member_use_from_same_package
|
||||||
|
androidHistoryUrl: map["androidHistoryUrl"],
|
||||||
|
historyUrl: map["historyUrl"]);
|
||||||
|
}
|
||||||
|
|
||||||
Map<String, String> toMap() {
|
Map<String, String> toMap() {
|
||||||
return {
|
return {
|
||||||
"data": data,
|
"data": data,
|
||||||
|
67
lib/src/web/headless_in_app_web_view_web_element.dart
Normal file
67
lib/src/web/headless_in_app_web_view_web_element.dart
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
|
import 'in_app_web_view_web_element.dart';
|
||||||
|
import '../util.dart';
|
||||||
|
|
||||||
|
class HeadlessInAppWebViewWebElement {
|
||||||
|
String id;
|
||||||
|
late BinaryMessenger _messenger;
|
||||||
|
InAppWebViewWebElement? webView;
|
||||||
|
late MethodChannel? _channel;
|
||||||
|
|
||||||
|
HeadlessInAppWebViewWebElement({required this.id, required BinaryMessenger messenger,
|
||||||
|
required this.webView}) {
|
||||||
|
this._messenger = messenger;
|
||||||
|
|
||||||
|
_channel = MethodChannel(
|
||||||
|
'com.pichillilorenzo/flutter_headless_inappwebview_${this.id}',
|
||||||
|
const StandardMethodCodec(),
|
||||||
|
_messenger,
|
||||||
|
);
|
||||||
|
|
||||||
|
this._channel?.setMethodCallHandler(handleMethodCall);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<dynamic> handleMethodCall(MethodCall call) async {
|
||||||
|
switch (call.method) {
|
||||||
|
case "dispose":
|
||||||
|
dispose();
|
||||||
|
break;
|
||||||
|
case "setSize":
|
||||||
|
Size size = MapSize.fromMap(call.arguments['size'])!;
|
||||||
|
setSize(size);
|
||||||
|
break;
|
||||||
|
case "getSize":
|
||||||
|
return getSize().toMap();
|
||||||
|
default:
|
||||||
|
throw PlatformException(
|
||||||
|
code: 'Unimplemented',
|
||||||
|
details: 'flutter_inappwebview for web doesn\'t implement \'${call.method}\'',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void onWebViewCreated() async {
|
||||||
|
await _channel?.invokeMethod("onWebViewCreated");
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSize(Size size) {
|
||||||
|
webView?.iframe.style.width = size.width.toString() + "px";
|
||||||
|
webView?.iframe.style.height = size.height.toString() + "px";
|
||||||
|
}
|
||||||
|
|
||||||
|
Size getSize() {
|
||||||
|
var width = webView?.iframe.getBoundingClientRect().width.toDouble() ?? 0.0;
|
||||||
|
var height = webView?.iframe.getBoundingClientRect().height.toDouble() ?? 0.0;
|
||||||
|
return Size(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dispose() {
|
||||||
|
_channel?.setMethodCallHandler(null);
|
||||||
|
_channel = null;
|
||||||
|
webView?.dispose();
|
||||||
|
webView = null;
|
||||||
|
}
|
||||||
|
}
|
62
lib/src/web/headless_inappwebview_manager.dart
Normal file
62
lib/src/web/headless_inappwebview_manager.dart
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
import 'dart:html';
|
||||||
|
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'web_platform_manager.dart';
|
||||||
|
import '../in_app_webview/in_app_webview_settings.dart';
|
||||||
|
import 'in_app_web_view_web_element.dart';
|
||||||
|
import 'headless_in_app_web_view_web_element.dart';
|
||||||
|
|
||||||
|
import '../types.dart';
|
||||||
|
|
||||||
|
class HeadlessInAppWebViewManager {
|
||||||
|
static late MethodChannel _sharedChannel;
|
||||||
|
|
||||||
|
late BinaryMessenger _messenger;
|
||||||
|
|
||||||
|
HeadlessInAppWebViewManager({required BinaryMessenger messenger}) {
|
||||||
|
this._messenger = messenger;
|
||||||
|
HeadlessInAppWebViewManager._sharedChannel = MethodChannel(
|
||||||
|
'com.pichillilorenzo/flutter_headless_inappwebview',
|
||||||
|
const StandardMethodCodec(),
|
||||||
|
_messenger,
|
||||||
|
);
|
||||||
|
HeadlessInAppWebViewManager._sharedChannel.setMethodCallHandler(handleMethod);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<dynamic> handleMethod(MethodCall call) async {
|
||||||
|
switch (call.method) {
|
||||||
|
case "run":
|
||||||
|
String id = call.arguments["id"];
|
||||||
|
Map<String, dynamic> params = call.arguments["params"].cast<String, dynamic>();
|
||||||
|
run(id, params);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw UnimplementedError("Unimplemented ${call.method} method");
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
void run(String id, Map<String, dynamic> params) {
|
||||||
|
var webView = InAppWebViewWebElement(viewId: id, messenger: _messenger);
|
||||||
|
var headlessWebView = HeadlessInAppWebViewWebElement(
|
||||||
|
id: id,
|
||||||
|
messenger: _messenger,
|
||||||
|
webView: webView
|
||||||
|
);
|
||||||
|
WebPlatformManager.webViews.putIfAbsent(id, () => webView);
|
||||||
|
webView.iframe.style.display = 'none';
|
||||||
|
Map<String, dynamic> initialSettings = params["initialSettings"].cast<String, dynamic>();
|
||||||
|
if (initialSettings.isEmpty) {
|
||||||
|
webView.initialSettings = InAppWebViewSettings();
|
||||||
|
} else {
|
||||||
|
webView.initialSettings = InAppWebViewSettings.fromMap(initialSettings);
|
||||||
|
}
|
||||||
|
webView.initialUrlRequest = URLRequest.fromMap(params["initialUrlRequest"]?.cast<String, dynamic>());
|
||||||
|
webView.initialFile = params["initialFile"];
|
||||||
|
webView.initialData = InAppWebViewInitialData.fromMap(params["initialData"]?.cast<String, dynamic>());
|
||||||
|
document.body?.append(webView.iframe);
|
||||||
|
webView.prepare();
|
||||||
|
headlessWebView.onWebViewCreated();
|
||||||
|
webView.makeInitialLoad();
|
||||||
|
}
|
||||||
|
}
|
@ -3,14 +3,15 @@ import 'package:flutter/services.dart';
|
|||||||
import 'dart:html';
|
import 'dart:html';
|
||||||
import 'dart:js' as js;
|
import 'dart:js' as js;
|
||||||
|
|
||||||
|
import 'web_platform_manager.dart';
|
||||||
import '../in_app_webview/in_app_webview_settings.dart';
|
import '../in_app_webview/in_app_webview_settings.dart';
|
||||||
import '../types.dart';
|
import '../types.dart';
|
||||||
|
|
||||||
class InAppWebViewWebElement {
|
class InAppWebViewWebElement {
|
||||||
late int _viewId;
|
late dynamic _viewId;
|
||||||
late BinaryMessenger _messenger;
|
late BinaryMessenger _messenger;
|
||||||
late IFrameElement iframe;
|
late IFrameElement iframe;
|
||||||
late MethodChannel _channel;
|
late MethodChannel? _channel;
|
||||||
InAppWebViewSettings? initialSettings;
|
InAppWebViewSettings? initialSettings;
|
||||||
URLRequest? initialUrlRequest;
|
URLRequest? initialUrlRequest;
|
||||||
InAppWebViewInitialData? initialData;
|
InAppWebViewInitialData? initialData;
|
||||||
@ -20,7 +21,7 @@ class InAppWebViewWebElement {
|
|||||||
late js.JsObject bridgeJsObject;
|
late js.JsObject bridgeJsObject;
|
||||||
bool isLoading = false;
|
bool isLoading = false;
|
||||||
|
|
||||||
InAppWebViewWebElement({required int viewId, required BinaryMessenger messenger}) {
|
InAppWebViewWebElement({required dynamic viewId, required BinaryMessenger messenger}) {
|
||||||
this._viewId = viewId;
|
this._viewId = viewId;
|
||||||
this._messenger = messenger;
|
this._messenger = messenger;
|
||||||
iframe = IFrameElement()
|
iframe = IFrameElement()
|
||||||
@ -35,11 +36,10 @@ class InAppWebViewWebElement {
|
|||||||
_messenger,
|
_messenger,
|
||||||
);
|
);
|
||||||
|
|
||||||
this._channel.setMethodCallHandler(handleMethodCall);
|
this._channel?.setMethodCallHandler(handleMethodCall);
|
||||||
|
|
||||||
bridgeJsObject = js.JsObject.fromBrowserObject(js.context['flutter_inappwebview']);
|
bridgeJsObject = js.JsObject.fromBrowserObject(js.context[WebPlatformManager.BRIDGE_JS_OBJECT_NAME]);
|
||||||
bridgeJsObject['viewId'] = _viewId;
|
bridgeJsObject['webViews'][_viewId] = bridgeJsObject.callMethod("createFlutterInAppWebView", [_viewId, iframe.id]);
|
||||||
bridgeJsObject['iframeId'] = iframe.id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handles method calls over the MethodChannel of this plugin.
|
/// Handles method calls over the MethodChannel of this plugin.
|
||||||
@ -87,6 +87,9 @@ class InAppWebViewWebElement {
|
|||||||
InAppWebViewSettings newSettings = InAppWebViewSettings.fromMap(call.arguments["settings"].cast<String, dynamic>());
|
InAppWebViewSettings newSettings = InAppWebViewSettings.fromMap(call.arguments["settings"].cast<String, dynamic>());
|
||||||
setSettings(newSettings);
|
setSettings(newSettings);
|
||||||
break;
|
break;
|
||||||
|
case "dispose":
|
||||||
|
dispose();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw PlatformException(
|
throw PlatformException(
|
||||||
code: 'Unimplemented',
|
code: 'Unimplemented',
|
||||||
@ -118,7 +121,16 @@ class InAppWebViewWebElement {
|
|||||||
iframe.setAttribute("sandbox", sandbox.map((e) => e.toValue()).join(" "));
|
iframe.setAttribute("sandbox", sandbox.map((e) => e.toValue()).join(" "));
|
||||||
}
|
}
|
||||||
|
|
||||||
bridgeJsObject.callMethod("prepare", [js.JsObject.jsify(settings.toMap())]);
|
_callMethod("prepare", [js.JsObject.jsify(settings.toMap())]);
|
||||||
|
}
|
||||||
|
|
||||||
|
dynamic _callMethod(Object method, [List? args]) {
|
||||||
|
var webViews = bridgeJsObject['webViews'] as js.JsObject;
|
||||||
|
if (webViews.hasProperty(_viewId)) {
|
||||||
|
var webview = bridgeJsObject['webViews'][_viewId] as js.JsObject;
|
||||||
|
return webview.callMethod(method, args);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
void makeInitialLoad() async {
|
void makeInitialLoad() async {
|
||||||
@ -168,27 +180,27 @@ class InAppWebViewWebElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> reload() async {
|
Future<void> reload() async {
|
||||||
bridgeJsObject.callMethod("reload");
|
_callMethod("reload");
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> goBack() async {
|
Future<void> goBack() async {
|
||||||
bridgeJsObject.callMethod("goBack");
|
_callMethod("goBack");
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> goForward() async {
|
Future<void> goForward() async {
|
||||||
bridgeJsObject.callMethod("goForward");
|
_callMethod("goForward");
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> goBackOrForward({required int steps}) async {
|
Future<void> goBackOrForward({required int steps}) async {
|
||||||
bridgeJsObject.callMethod("goBackOrForward", [steps]);
|
_callMethod("goBackOrForward", [steps]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<dynamic> evaluateJavascript({required String source}) async {
|
Future<dynamic> evaluateJavascript({required String source}) async {
|
||||||
return bridgeJsObject.callMethod("evaluateJavascript", [source]);
|
return _callMethod("evaluateJavascript", [source]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> stopLoading() async {
|
Future<void> stopLoading() async {
|
||||||
bridgeJsObject.callMethod("stopLoading");
|
_callMethod("stopLoading");
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<Sandbox> getSandbox() {
|
Set<Sandbox> getSandbox() {
|
||||||
@ -243,7 +255,7 @@ class InAppWebViewWebElement {
|
|||||||
iframe.setAttribute("sandbox", sandbox.map((e) => e.toValue()).join(" "));
|
iframe.setAttribute("sandbox", sandbox.map((e) => e.toValue()).join(" "));
|
||||||
}
|
}
|
||||||
|
|
||||||
bridgeJsObject.callMethod("setSettings", [js.JsObject.jsify(newSettings.toMap())]);
|
_callMethod("setSettings", [js.JsObject.jsify(newSettings.toMap())]);
|
||||||
|
|
||||||
settings = newSettings;
|
settings = newSettings;
|
||||||
}
|
}
|
||||||
@ -254,7 +266,7 @@ class InAppWebViewWebElement {
|
|||||||
var obj = {
|
var obj = {
|
||||||
"url": url
|
"url": url
|
||||||
};
|
};
|
||||||
await _channel.invokeMethod("onLoadStart", obj);
|
await _channel?.invokeMethod("onLoadStart", obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onLoadStop(String url) async {
|
void onLoadStop(String url) async {
|
||||||
@ -263,14 +275,14 @@ class InAppWebViewWebElement {
|
|||||||
var obj = {
|
var obj = {
|
||||||
"url": url
|
"url": url
|
||||||
};
|
};
|
||||||
await _channel.invokeMethod("onLoadStop", obj);
|
await _channel?.invokeMethod("onLoadStop", obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onUpdateVisitedHistory(String url) async {
|
void onUpdateVisitedHistory(String url) async {
|
||||||
var obj = {
|
var obj = {
|
||||||
"url": url
|
"url": url
|
||||||
};
|
};
|
||||||
await _channel.invokeMethod("onUpdateVisitedHistory", obj);
|
await _channel?.invokeMethod("onUpdateVisitedHistory", obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onScrollChanged(int x, int y) async {
|
void onScrollChanged(int x, int y) async {
|
||||||
@ -278,7 +290,7 @@ class InAppWebViewWebElement {
|
|||||||
"x": x,
|
"x": x,
|
||||||
"y": y
|
"y": y
|
||||||
};
|
};
|
||||||
await _channel.invokeMethod("onScrollChanged", obj);
|
await _channel?.invokeMethod("onScrollChanged", obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onConsoleMessage(String type, String? message) async {
|
void onConsoleMessage(String type, String? message) async {
|
||||||
@ -302,7 +314,7 @@ class InAppWebViewWebElement {
|
|||||||
"messageLevel": messageLevel,
|
"messageLevel": messageLevel,
|
||||||
"message": message
|
"message": message
|
||||||
};
|
};
|
||||||
await _channel.invokeMethod("onConsoleMessage", obj);
|
await _channel?.invokeMethod("onConsoleMessage", obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool?> onCreateWindow(int windowId, String url, String? target, String? windowFeatures) async {
|
Future<bool?> onCreateWindow(int windowId, String url, String? target, String? windowFeatures) async {
|
||||||
@ -330,15 +342,15 @@ class InAppWebViewWebElement {
|
|||||||
},
|
},
|
||||||
"windowFeatures": windowFeaturesMap
|
"windowFeatures": windowFeaturesMap
|
||||||
};
|
};
|
||||||
return await _channel.invokeMethod("onCreateWindow", obj);
|
return await _channel?.invokeMethod("onCreateWindow", obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onWindowFocus() async {
|
void onWindowFocus() async {
|
||||||
await _channel.invokeMethod("onWindowFocus");
|
await _channel?.invokeMethod("onWindowFocus");
|
||||||
}
|
}
|
||||||
|
|
||||||
void onWindowBlur() async {
|
void onWindowBlur() async {
|
||||||
await _channel.invokeMethod("onWindowBlur");
|
await _channel?.invokeMethod("onWindowBlur");
|
||||||
}
|
}
|
||||||
|
|
||||||
void onPrint(String? url) async {
|
void onPrint(String? url) async {
|
||||||
@ -346,15 +358,15 @@ class InAppWebViewWebElement {
|
|||||||
"url": url
|
"url": url
|
||||||
};
|
};
|
||||||
|
|
||||||
await _channel.invokeMethod("onPrint", obj);
|
await _channel?.invokeMethod("onPrint", obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onEnterFullscreen() async {
|
void onEnterFullscreen() async {
|
||||||
await _channel.invokeMethod("onEnterFullscreen");
|
await _channel?.invokeMethod("onEnterFullscreen");
|
||||||
}
|
}
|
||||||
|
|
||||||
void onExitFullscreen() async {
|
void onExitFullscreen() async {
|
||||||
await _channel.invokeMethod("onExitFullscreen");
|
await _channel?.invokeMethod("onExitFullscreen");
|
||||||
}
|
}
|
||||||
|
|
||||||
void onTitleChanged(String? title) async {
|
void onTitleChanged(String? title) async {
|
||||||
@ -362,7 +374,7 @@ class InAppWebViewWebElement {
|
|||||||
"title": title
|
"title": title
|
||||||
};
|
};
|
||||||
|
|
||||||
await _channel.invokeMethod("onTitleChanged", obj);
|
await _channel?.invokeMethod("onTitleChanged", obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onZoomScaleChanged(double oldScale, double newScale) async {
|
void onZoomScaleChanged(double oldScale, double newScale) async {
|
||||||
@ -371,6 +383,20 @@ class InAppWebViewWebElement {
|
|||||||
"newScale": newScale
|
"newScale": newScale
|
||||||
};
|
};
|
||||||
|
|
||||||
await _channel.invokeMethod("onZoomScaleChanged", obj);
|
await _channel?.invokeMethod("onZoomScaleChanged", obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dispose() {
|
||||||
|
_channel?.setMethodCallHandler(null);
|
||||||
|
_channel = null;
|
||||||
|
iframe.remove();
|
||||||
|
if (WebPlatformManager.webViews.containsKey(_viewId)) {
|
||||||
|
WebPlatformManager.webViews.remove(_viewId);
|
||||||
|
}
|
||||||
|
bridgeJsObject = js.JsObject.fromBrowserObject(js.context[WebPlatformManager.BRIDGE_JS_OBJECT_NAME]);
|
||||||
|
var webViews = bridgeJsObject['webViews'] as js.JsObject;
|
||||||
|
if (webViews.hasProperty(_viewId)) {
|
||||||
|
webViews.deleteProperty(_viewId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
46
lib/src/web/platform_util.dart
Normal file
46
lib/src/web/platform_util.dart
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
|
import 'dart:js' as js;
|
||||||
|
|
||||||
|
import 'web_platform_manager.dart';
|
||||||
|
|
||||||
|
class PlatformUtil {
|
||||||
|
late BinaryMessenger _messenger;
|
||||||
|
late MethodChannel? _channel;
|
||||||
|
|
||||||
|
PlatformUtil({required BinaryMessenger messenger}) {
|
||||||
|
this._messenger = messenger;
|
||||||
|
|
||||||
|
_channel = MethodChannel(
|
||||||
|
'com.pichillilorenzo/flutter_inappwebview_platformutil',
|
||||||
|
const StandardMethodCodec(),
|
||||||
|
_messenger,
|
||||||
|
);
|
||||||
|
|
||||||
|
this._channel?.setMethodCallHandler(handleMethodCall);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<dynamic> handleMethodCall(MethodCall call) async {
|
||||||
|
switch (call.method) {
|
||||||
|
case "getWebCookieExpirationDate":
|
||||||
|
int timestamp = call.arguments['date'];
|
||||||
|
return getWebCookieExpirationDate(timestamp);
|
||||||
|
default:
|
||||||
|
throw PlatformException(
|
||||||
|
code: 'Unimplemented',
|
||||||
|
details: 'flutter_inappwebview for web doesn\'t implement \'${call.method}\'',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String getWebCookieExpirationDate(int timestamp) {
|
||||||
|
var bridgeJsObject = js.JsObject.fromBrowserObject(js.context[WebPlatformManager.BRIDGE_JS_OBJECT_NAME]);
|
||||||
|
return bridgeJsObject.callMethod("getCookieExpirationDate", [timestamp]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dispose() {
|
||||||
|
_channel?.setMethodCallHandler(null);
|
||||||
|
_channel = null;
|
||||||
|
}
|
||||||
|
}
|
@ -1,11 +1,11 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:flutter/services.dart';
|
import 'headless_inappwebview_manager.dart';
|
||||||
import 'web_platform_manager.dart';
|
import 'web_platform_manager.dart';
|
||||||
import 'package:flutter_web_plugins/flutter_web_plugins.dart';
|
import 'package:flutter_web_plugins/flutter_web_plugins.dart';
|
||||||
import 'shims/dart_ui.dart' as ui;
|
import 'shims/dart_ui.dart' as ui;
|
||||||
|
|
||||||
import 'in_app_web_view_web_element.dart';
|
import 'in_app_web_view_web_element.dart';
|
||||||
|
import 'platform_util.dart';
|
||||||
import 'package:js/js.dart';
|
import 'package:js/js.dart';
|
||||||
|
|
||||||
/// Builds an iframe based WebView.
|
/// Builds an iframe based WebView.
|
||||||
@ -26,30 +26,21 @@ class FlutterInAppWebViewWebPlatform {
|
|||||||
|
|
||||||
static void registerWith(Registrar registrar) {
|
static void registerWith(Registrar registrar) {
|
||||||
final pluginInstance = FlutterInAppWebViewWebPlatform(registrar);
|
final pluginInstance = FlutterInAppWebViewWebPlatform(registrar);
|
||||||
|
final platformUtil = PlatformUtil(messenger: registrar);
|
||||||
|
final headlessManager = HeadlessInAppWebViewManager(messenger: registrar);
|
||||||
_nativeCommunication = allowInterop(_dartNativeCommunication);
|
_nativeCommunication = allowInterop(_dartNativeCommunication);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handles method calls over the MethodChannel of this plugin.
|
|
||||||
Future<dynamic> handleMethodCall(MethodCall call) async {
|
|
||||||
switch (call.method) {
|
|
||||||
default:
|
|
||||||
throw PlatformException(
|
|
||||||
code: 'Unimplemented',
|
|
||||||
details: 'flutter_inappwebview for web doesn\'t implement \'${call.method}\'',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allows assigning a function to be callable from `window.flutter_inappwebview.nativeCommunication()`
|
/// Allows assigning a function to be callable from `window.flutter_inappwebview.nativeCommunication()`
|
||||||
@JS('flutter_inappwebview.nativeCommunication')
|
@JS('flutter_inappwebview.nativeCommunication')
|
||||||
external set _nativeCommunication(Future<dynamic> Function(String method, int viewId, [List? args]) f);
|
external set _nativeCommunication(Future<dynamic> Function(String method, dynamic viewId, [List? args]) f);
|
||||||
|
|
||||||
/// Allows calling the assigned function from Dart as well.
|
/// Allows calling the assigned function from Dart as well.
|
||||||
@JS()
|
@JS()
|
||||||
external Future<dynamic> nativeCommunication(String method, int viewId, [List? args]);
|
external Future<dynamic> nativeCommunication(String method, dynamic viewId, [List? args]);
|
||||||
|
|
||||||
Future<dynamic> _dartNativeCommunication(String method, int viewId, [List? args]) async {
|
Future<dynamic> _dartNativeCommunication(String method, dynamic viewId, [List? args]) async {
|
||||||
if (WebPlatformManager.webViews.containsKey(viewId)) {
|
if (WebPlatformManager.webViews.containsKey(viewId)) {
|
||||||
var webViewHtmlElement = WebPlatformManager.webViews[viewId] as InAppWebViewWebElement;
|
var webViewHtmlElement = WebPlatformManager.webViews[viewId] as InAppWebViewWebElement;
|
||||||
switch (method) {
|
switch (method) {
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
abstract class WebPlatformManager {
|
abstract class WebPlatformManager {
|
||||||
static final Map<int, dynamic> webViews = {};
|
static final String BRIDGE_JS_OBJECT_NAME = "flutter_inappwebview";
|
||||||
|
static final Map<dynamic, dynamic> webViews = {};
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user