bug fixes, fix #450, updated integration tests

This commit is contained in:
Lorenzo Pichilli 2021-02-22 23:38:30 +01:00
parent 0b0bce66aa
commit f886f2f1e5
24 changed files with 4250 additions and 2431 deletions

View File

@ -1,4 +1,4 @@
## 5.0.0-nullsafety.0 ## 5.0.0
- Added support for Dart null-safety feature - Added support for Dart null-safety feature
- Added Android Hybrid Composition support "Use PlatformViewLink widget for Android WebView" [#462](https://github.com/pichillilorenzo/flutter_inappwebview/pull/462) (thanks to [plateaukao](https://github.com/plateaukao) and [tneotia](https://github.com/tneotia)) - Added Android Hybrid Composition support "Use PlatformViewLink widget for Android WebView" [#462](https://github.com/pichillilorenzo/flutter_inappwebview/pull/462) (thanks to [plateaukao](https://github.com/plateaukao) and [tneotia](https://github.com/tneotia))
@ -32,6 +32,7 @@
- Merge "Add ChromeSafariBrowser support for Android 11" [#538](https://github.com/pichillilorenzo/flutter_inappwebview/pull/538) (thanks to [DRSchlaubi](https://github.com/DRSchlaubi)) - Merge "Add ChromeSafariBrowser support for Android 11" [#538](https://github.com/pichillilorenzo/flutter_inappwebview/pull/538) (thanks to [DRSchlaubi](https://github.com/DRSchlaubi))
- Merge "fix(iOS): missing implementation of method zoomBy" [#670](https://github.com/pichillilorenzo/flutter_inappwebview/pull/670) (thanks to [pcqpcq](https://github.com/pcqpcq)) - Merge "fix(iOS): missing implementation of method zoomBy" [#670](https://github.com/pichillilorenzo/flutter_inappwebview/pull/670) (thanks to [pcqpcq](https://github.com/pcqpcq))
- Merge "[mod] Fix all issues relate to long click in Android version 7.0 (#657, #527)" [#671](https://github.com/pichillilorenzo/flutter_inappwebview/pull/671) (thanks to [MrNinja](https://github.com/MrNinja)) - Merge "[mod] Fix all issues relate to long click in Android version 7.0 (#657, #527)" [#671](https://github.com/pichillilorenzo/flutter_inappwebview/pull/671) (thanks to [MrNinja](https://github.com/MrNinja))
- Merge "Fix ViewGroup.removeView NullPointerException (#450)" [#683](https://github.com/pichillilorenzo/flutter_inappwebview/pull/683) (thanks to [toda-bps](https://github.com/toda-bps))
- Fixed missing properties initialization when using InAppWebViewController.fromInAppBrowser - Fixed missing properties initialization when using InAppWebViewController.fromInAppBrowser
- Fixed "Issue in Flutter web: 'Unsupported operation: Platform._operatingSystem'" [#507](https://github.com/pichillilorenzo/flutter_inappwebview/issues/507) - Fixed "Issue in Flutter web: 'Unsupported operation: Platform._operatingSystem'" [#507](https://github.com/pichillilorenzo/flutter_inappwebview/issues/507)
- Fixed "window.flutter_inappwebview.callHandler is not a function" [#218](https://github.com/pichillilorenzo/flutter_inappwebview/issues/218) - Fixed "window.flutter_inappwebview.callHandler is not a function" [#218](https://github.com/pichillilorenzo/flutter_inappwebview/issues/218)

View File

@ -73,7 +73,7 @@ public class InAppWebViewMethodHandler implements MethodChannel.MethodCallHandle
break; break;
case "loadFile": case "loadFile":
if (webView != null) { if (webView != null) {
String assetFilePath = (String) call.argument("url"); String assetFilePath = (String) call.argument("assetFilePath");
try { try {
webView.loadFile(assetFilePath); webView.loadFile(assetFilePath);
} catch (IOException e) { } catch (IOException e) {
@ -458,7 +458,7 @@ public class InAppWebViewMethodHandler implements MethodChannel.MethodCallHandle
Integer index = (Integer) call.argument("index"); Integer index = (Integer) call.argument("index");
Map<String, Object> userScriptMap = (Map<String, Object>) call.argument("userScript"); Map<String, Object> userScriptMap = (Map<String, Object>) call.argument("userScript");
UserScript userScript = UserScript.fromMap(userScriptMap); UserScript userScript = UserScript.fromMap(userScriptMap);
result.success(webView.userContentController.removePluginScriptAt(index, userScript.getInjectionTime())); result.success(webView.userContentController.removeUserOnlyScriptAt(index, userScript.getInjectionTime()));
} else { } else {
result.success(false); result.success(false);
} }

View File

@ -460,7 +460,9 @@ public class InAppBrowserActivity extends AppCompatActivity implements InAppBrow
Shared.activityPluginBinding.removeActivityResultListener(webView.inAppWebViewChromeClient); Shared.activityPluginBinding.removeActivityResultListener(webView.inAppWebViewChromeClient);
} }
ViewGroup vg = (ViewGroup) (webView.getParent()); ViewGroup vg = (ViewGroup) (webView.getParent());
vg.removeView(webView); if (vg != null) {
vg.removeView(webView);
}
webView.setWebChromeClient(new WebChromeClient()); webView.setWebChromeClient(new WebChromeClient());
webView.setWebViewClient(new WebViewClient() { webView.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView view, String url) { public void onPageFinished(WebView view, String url) {

View File

@ -81,8 +81,8 @@ public class InAppBrowserOptions implements Options<InAppBrowserActivity> {
@Override @Override
public Map<String, Object> getRealOptions(InAppBrowserActivity inAppBrowserActivity) { public Map<String, Object> getRealOptions(InAppBrowserActivity inAppBrowserActivity) {
Map<String, Object> realOptions = toMap(); Map<String, Object> realOptions = toMap();
realOptions.put("hideToolbarTop", inAppBrowserActivity.actionBar.isShowing()); realOptions.put("hideToolbarTop", !inAppBrowserActivity.actionBar.isShowing());
realOptions.put("hideUrlBar", inAppBrowserActivity.menu.findItem(R.id.menu_search).isVisible()); realOptions.put("hideUrlBar", !inAppBrowserActivity.menu.findItem(R.id.menu_search).isVisible());
realOptions.put("hideProgressBar", inAppBrowserActivity.progressBar.getMax() == 0); realOptions.put("hideProgressBar", inAppBrowserActivity.progressBar.getMax() == 0);
return realOptions; return realOptions;
} }

View File

@ -1037,7 +1037,7 @@ final public class InAppWebView extends InputAwareWebView {
} }
public void injectCSSCode(String source) { public void injectCSSCode(String source) {
String jsWrapper = "(function(d) { var style = d.createElement('style'); style.innerHTML = %s; d.body.appendChild(style); })(document);"; String jsWrapper = "(function(d) { var style = d.createElement('style'); style.innerHTML = %s; d.head.appendChild(style); })(document);";
injectDeferredObject(source, null, jsWrapper, null); injectDeferredObject(source, null, jsWrapper, null);
} }

View File

@ -672,10 +672,16 @@ public class InAppWebViewChromeClient extends WebChromeClient implements PluginR
public void onProgressChanged(WebView view, int progress) { public void onProgressChanged(WebView view, int progress) {
super.onProgressChanged(view, progress); super.onProgressChanged(view, progress);
InAppWebView webView = (InAppWebView) view;
if (inAppBrowserDelegate != null) { if (inAppBrowserDelegate != null) {
inAppBrowserDelegate.didChangeProgress(progress); inAppBrowserDelegate.didChangeProgress(progress);
} }
if (webView.inAppWebViewClient != null) {
webView.inAppWebViewClient.loadCustomJavaScriptOnPageStarted(view);
}
Map<String, Object> obj = new HashMap<>(); Map<String, Object> obj = new HashMap<>();
obj.put("progress", progress); obj.put("progress", progress);
channel.invokeMethod("onProgressChanged", obj); channel.invokeMethod("onProgressChanged", obj);

View File

@ -1,6 +1,7 @@
package com.pichillilorenzo.flutter_inappwebview.types; package com.pichillilorenzo.flutter_inappwebview.types;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
@ -216,11 +217,6 @@ public class UserContentController {
return this.pluginScripts.get(pluginScript.getInjectionTime()).remove(pluginScript); return this.pluginScripts.get(pluginScript.getInjectionTime()).remove(pluginScript);
} }
public boolean removePluginScriptAt(int index, UserScriptInjectionTime injectionTime) {
PluginScript pluginScript = new ArrayList<>(this.pluginScripts.get(injectionTime)).get(index);
return this.removePluginScript(pluginScript);
}
public void removeAllPluginScripts() { public void removeAllPluginScripts() {
this.pluginScripts.get(UserScriptInjectionTime.AT_DOCUMENT_START).clear(); this.pluginScripts.get(UserScriptInjectionTime.AT_DOCUMENT_START).clear();
this.pluginScripts.get(UserScriptInjectionTime.AT_DOCUMENT_END).clear(); this.pluginScripts.get(UserScriptInjectionTime.AT_DOCUMENT_END).clear();
@ -356,9 +352,5 @@ public class UserContentController {
private static final String DOCUMENT_READY_WRAPPER_JS_SOURCE = "if (document.readyState === 'interactive' || document.readyState === 'complete') { " + private static final String DOCUMENT_READY_WRAPPER_JS_SOURCE = "if (document.readyState === 'interactive' || document.readyState === 'complete') { " +
" " + PluginScriptsUtil.VAR_PLACEHOLDER_VALUE + " " + PluginScriptsUtil.VAR_PLACEHOLDER_VALUE +
"} else {" +
" document.addEventListener('DOMContentLoaded', function() {" +
" " + PluginScriptsUtil.VAR_PLACEHOLDER_VALUE +
" });" +
"}"; "}";
} }

View File

@ -1 +1 @@
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"device_info","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/device_info-2.0.0-nullsafety.2/","dependencies":[]},{"name":"flutter_downloader","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":["device_info"]},{"name":"integration_test","path":"/Users/lorenzopichilli/flutter/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"android":[{"name":"device_info","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/device_info-2.0.0-nullsafety.2/","dependencies":[]},{"name":"flutter_downloader","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":["device_info"]},{"name":"integration_test","path":"/Users/lorenzopichilli/flutter/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"macos":[{"name":"path_provider_macos","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-0.0.5-nullsafety/","dependencies":[]},{"name":"url_launcher_macos","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-0.1.0-nullsafety.2/","dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-0.2.0-nullsafety/","dependencies":[]},{"name":"url_launcher_linux","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-0.1.0-nullsafety.3/","dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-0.1.0-nullsafety.3/","dependencies":[]},{"name":"url_launcher_windows","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-0.1.0-nullsafety.2/","dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"device_info","dependencies":[]},{"name":"flutter_downloader","dependencies":[]},{"name":"flutter_inappwebview","dependencies":["device_info"]},{"name":"integration_test","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos","path_provider_linux","path_provider_windows"]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_linux","url_launcher_macos","url_launcher_windows"]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]}],"date_created":"2021-02-22 12:12:06.265826","version":"1.27.0-5.0.pre.90"} {"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"device_info","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/device_info-2.0.0-nullsafety.2/","dependencies":[]},{"name":"flutter_downloader","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":["device_info"]},{"name":"integration_test","path":"/Users/lorenzopichilli/flutter/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"android":[{"name":"device_info","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/device_info-2.0.0-nullsafety.2/","dependencies":[]},{"name":"flutter_downloader","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_downloader-1.5.2/","dependencies":[]},{"name":"flutter_inappwebview","path":"/Users/lorenzopichilli/Desktop/flutter_inappwebview/","dependencies":["device_info"]},{"name":"integration_test","path":"/Users/lorenzopichilli/flutter/packages/integration_test/","dependencies":[]},{"name":"path_provider","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-2.0.0-nullsafety/","dependencies":[]},{"name":"permission_handler","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/permission_handler-5.1.0+2/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.6/","dependencies":[]}],"macos":[{"name":"path_provider_macos","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_macos-0.0.5-nullsafety/","dependencies":[]},{"name":"url_launcher_macos","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_macos-0.1.0-nullsafety.2/","dependencies":[]}],"linux":[{"name":"path_provider_linux","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_linux-0.2.0-nullsafety/","dependencies":[]},{"name":"url_launcher_linux","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_linux-0.1.0-nullsafety.3/","dependencies":[]}],"windows":[{"name":"path_provider_windows","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider_windows-0.1.0-nullsafety.3/","dependencies":[]},{"name":"url_launcher_windows","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher_windows-0.1.0-nullsafety.2/","dependencies":[]}],"web":[]},"dependencyGraph":[{"name":"device_info","dependencies":[]},{"name":"flutter_downloader","dependencies":[]},{"name":"flutter_inappwebview","dependencies":["device_info"]},{"name":"integration_test","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos","path_provider_linux","path_provider_windows"]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_macos","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"permission_handler","dependencies":[]},{"name":"url_launcher","dependencies":["url_launcher_linux","url_launcher_macos","url_launcher_windows"]},{"name":"url_launcher_linux","dependencies":[]},{"name":"url_launcher_macos","dependencies":[]},{"name":"url_launcher_windows","dependencies":[]}],"date_created":"2021-02-22 23:35:30.325662","version":"1.27.0-5.0.pre.90"}

File diff suppressed because it is too large Load Diff

View File

@ -28,6 +28,8 @@
<true/> <true/>
<key>NSAppTransportSecurity</key> <key>NSAppTransportSecurity</key>
<dict> <dict>
<key>NSAllowsArbitraryLoadsInWebContent</key>
<true/>
<key>NSAllowsArbitraryLoads</key> <key>NSAllowsArbitraryLoads</key>
<true/> <true/>
<key>NSAllowsLocalNetworking</key> <key>NSAllowsLocalNetworking</key>

View File

@ -102,7 +102,7 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
key: webViewKey, key: webViewKey,
// contextMenu: contextMenu, // contextMenu: contextMenu,
initialUrlRequest: URLRequest( initialUrlRequest: URLRequest(
url: Uri.parse("https://github.com") url: Uri.parse("https://flutter.dev")
), ),
// initialFile: "assets/index.html", // initialFile: "assets/index.html",
initialUserScripts: UnmodifiableListView<UserScript>([ initialUserScripts: UnmodifiableListView<UserScript>([
@ -140,9 +140,6 @@ class _InAppWebViewExampleScreenState extends State<InAppWebViewExampleScreen> {
return NavigationActionPolicy.ALLOW; return NavigationActionPolicy.ALLOW;
}, },
onLoadResource: (controller, resource) {
// print(resource);
},
onLoadStop: (controller, url) async { onLoadStop: (controller, url) async {
print("onLoadStop $url"); print("onLoadStop $url");
setState(() { setState(() {

View File

@ -71,6 +71,7 @@ flutter:
- test_assets/in_app_webview_on_console_message_test.html - test_assets/in_app_webview_on_console_message_test.html
- test_assets/in_app_webview_on_create_window_test.html - test_assets/in_app_webview_on_create_window_test.html
- test_assets/in_app_webview_on_js_dialog_test.html - test_assets/in_app_webview_on_js_dialog_test.html
- test_assets/js/
- test_assets/css/ - test_assets/css/
- test_assets/images/ - test_assets/images/
- test_assets/favicon.ico - test_assets/favicon.ico

View File

@ -0,0 +1,3 @@
body {
background-color: rgb(0, 0, 255);
}

File diff suppressed because one or more lines are too long

View File

@ -426,7 +426,7 @@ public class InAppBrowserWebViewController: UIViewController, InAppBrowserDelega
searchBar.isHidden = newOptions.hideUrlBar searchBar.isHidden = newOptions.hideUrlBar
} }
if newOptionsMap["toolbarTop"] != nil, browserOptions?.hideToolbarTop != newOptions.hideToolbarTop { if newOptionsMap["hideToolbarTop"] != nil, browserOptions?.hideToolbarTop != newOptions.hideToolbarTop {
navigationController?.navigationBar.isHidden = newOptions.hideToolbarTop navigationController?.navigationBar.isHidden = newOptions.hideToolbarTop
} }

View File

@ -1323,7 +1323,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
} }
public func injectCSSCode(source: String) { public func injectCSSCode(source: String) {
let jsWrapper = "(function(d) { var style = d.createElement('style'); style.innerHTML = %@; d.body.appendChild(style); })(document);" let jsWrapper = "(function(d) { var style = d.createElement('style'); style.innerHTML = %@; d.head.appendChild(style); })(document);"
injectDeferredObject(source: source, withWrapper: jsWrapper, completionHandler: nil) injectDeferredObject(source: source, withWrapper: jsWrapper, completionHandler: nil)
} }
@ -1356,7 +1356,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
cssLinkAttributes += " link.title = '\(titleAttr.replacingOccurrences(of: "\'", with: "\\'"))'; " cssLinkAttributes += " link.title = '\(titleAttr.replacingOccurrences(of: "\'", with: "\\'"))'; "
} }
} }
let jsWrapper = "(function(d) { var link = d.createElement('link'); link.rel='\(alternateStylesheet)stylesheet', link.type='text/css'; \(cssLinkAttributes) link.href = %@; d.body.appendChild(link); })(document);" let jsWrapper = "(function(d) { var link = d.createElement('link'); link.rel='\(alternateStylesheet)stylesheet', link.type='text/css'; \(cssLinkAttributes) link.href = %@; d.head.appendChild(link); })(document);"
injectDeferredObject(source: urlFile, withWrapper: jsWrapper, completionHandler: nil) injectDeferredObject(source: urlFile, withWrapper: jsWrapper, completionHandler: nil)
} }

View File

@ -260,8 +260,8 @@ class InAppWebViewMethodHandler: FlutterMethodCallDelegate {
break break
case "pauseTimers": case "pauseTimers":
webView?.pauseTimers() webView?.pauseTimers()
result(true) result(true)
break break
case "resumeTimers": case "resumeTimers":
webView?.resumeTimers() webView?.resumeTimers()
result(true) result(true)
@ -383,16 +383,19 @@ class InAppWebViewMethodHandler: FlutterMethodCallDelegate {
result(webView?.getCertificate()?.toMap()) result(webView?.getCertificate()?.toMap())
break break
case "addUserScript": case "addUserScript":
let userScriptMap = arguments!["userScript"] as! [String: Any?] if let webView = webView {
let userScript = UserScript.fromMap(map: userScriptMap, windowId: webView?.windowId)! let userScriptMap = arguments!["userScript"] as! [String: Any?]
webView?.configuration.userContentController.addUserOnlyScript(userScript) let userScript = UserScript.fromMap(map: userScriptMap, windowId: webView.windowId)!
webView.configuration.userContentController.addUserOnlyScript(userScript)
webView.configuration.userContentController.sync(scriptMessageHandler: webView)
}
result(true) result(true)
break break
case "removeUserScript": case "removeUserScript":
let index = arguments!["index"] as! Int let index = arguments!["index"] as! Int
let userScriptMap = arguments!["userScript"] as! [String: Any?] let userScriptMap = arguments!["userScript"] as! [String: Any?]
let userScript = UserScript.fromMap(map: userScriptMap, windowId: webView?.windowId)! let userScript = UserScript.fromMap(map: userScriptMap, windowId: webView?.windowId)!
webView?.configuration.userContentController.removeUserOnlyScript(at: index, userOnlyScript: userScript) webView?.configuration.userContentController.removeUserOnlyScript(at: index, injectionTime: userScript.injectionTime)
result(true) result(true)
break break
case "removeUserScriptsByGroupName": case "removeUserScriptsByGroupName":
@ -463,12 +466,12 @@ class InAppWebViewMethodHandler: FlutterMethodCallDelegate {
break break
case "isSecureContext": case "isSecureContext":
if let webView = webView { if let webView = webView {
result(webView.isSecureContext(completionHandler: { (isSecureContext) in webView.isSecureContext(completionHandler: { (isSecureContext) in
result(isSecureContext) result(isSecureContext)
})) })
} }
else { else {
result(nil) result(false)
} }
break break
default: default:

View File

@ -178,9 +178,10 @@ extension WKUserContentController {
removeUserScript(scriptToRemove: userOnlyScript) removeUserScript(scriptToRemove: userOnlyScript)
} }
public func removeUserOnlyScript(at index: Int, userOnlyScript: UserScript) { public func removeUserOnlyScript(at index: Int, injectionTime: WKUserScriptInjectionTime) {
userOnlyScripts[userOnlyScript.injectionTime]!.removeObject(at: index) let scriptToRemove = userOnlyScripts[injectionTime]![index]
removeUserScript(scriptToRemove: userOnlyScript) userOnlyScripts[injectionTime]!.removeObject(at: index)
removeUserScript(scriptToRemove: scriptToRemove)
} }
public func removeAllUserOnlyScripts() { public func removeAllUserOnlyScripts() {

View File

@ -6,6 +6,30 @@ import 'package:flutter/services.dart';
import '../_uuid_generator.dart'; import '../_uuid_generator.dart';
import 'chrome_safari_browser_options.dart'; import 'chrome_safari_browser_options.dart';
class ChromeSafariBrowserAlreadyOpenedException implements Exception {
final dynamic message;
ChromeSafariBrowserAlreadyOpenedException([this.message]);
String toString() {
Object? message = this.message;
if (message == null) return "ChromeSafariBrowserAlreadyOpenedException";
return "ChromeSafariBrowserAlreadyOpenedException: $message";
}
}
class ChromeSafariBrowserNotOpenedException implements Exception {
final dynamic message;
ChromeSafariBrowserNotOpenedException([this.message]);
String toString() {
Object? message = this.message;
if (message == null) return "ChromeSafariBrowserNotOpenedException";
return "ChromeSafariBrowserNotOpenedException: $message";
}
}
///This class uses native [Chrome Custom Tabs](https://developer.android.com/reference/android/support/customtabs/package-summary) on Android ///This class uses native [Chrome Custom Tabs](https://developer.android.com/reference/android/support/customtabs/package-summary) on Android
///and [SFSafariViewController](https://developer.apple.com/documentation/safariservices/sfsafariviewcontroller) on iOS. ///and [SFSafariViewController](https://developer.apple.com/documentation/safariservices/sfsafariviewcontroller) on iOS.
/// ///
@ -120,7 +144,7 @@ class ChromeSafariBrowser {
void throwIsAlreadyOpened({String message = ''}) { void throwIsAlreadyOpened({String message = ''}) {
if (this.isOpened()) { if (this.isOpened()) {
throw Exception([ throw ChromeSafariBrowserAlreadyOpenedException([
'Error: ${(message.isEmpty) ? '' : message + ' '}The browser is already opened.' 'Error: ${(message.isEmpty) ? '' : message + ' '}The browser is already opened.'
]); ]);
} }
@ -128,7 +152,7 @@ class ChromeSafariBrowser {
void throwIsNotOpened({String message = ''}) { void throwIsNotOpened({String message = ''}) {
if (!this.isOpened()) { if (!this.isOpened()) {
throw Exception([ throw ChromeSafariBrowserNotOpenedException([
'Error: ${(message.isEmpty) ? '' : message + ' '}The browser is not opened.' 'Error: ${(message.isEmpty) ? '' : message + ' '}The browser is not opened.'
]); ]);
} }

View File

@ -13,6 +13,30 @@ import '../in_app_webview/in_app_webview_options.dart';
import 'in_app_browser_options.dart'; import 'in_app_browser_options.dart';
class InAppBrowserAlreadyOpenedException implements Exception {
final dynamic message;
InAppBrowserAlreadyOpenedException([this.message]);
String toString() {
Object? message = this.message;
if (message == null) return "InAppBrowserAlreadyOpenedException";
return "InAppBrowserAlreadyOpenedException: $message";
}
}
class InAppBrowserNotOpenedException implements Exception {
final dynamic message;
InAppBrowserNotOpenedException([this.message]);
String toString() {
Object? message = this.message;
if (message == null) return "InAppBrowserNotOpenedException";
return "InAppBrowserNotOpenedException: $message";
}
}
///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.
class InAppBrowser { class InAppBrowser {
@ -76,7 +100,7 @@ class InAppBrowser {
Map<String, dynamic> args = <String, dynamic>{}; Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('uuid', () => uuid); args.putIfAbsent('uuid', () => uuid);
args.putIfAbsent('urlRequest', () => urlRequest.toMap()); args.putIfAbsent('urlRequest', () => urlRequest.toMap());
args.putIfAbsent('options', () => options?.toMap() ?? {}); args.putIfAbsent('options', () => options?.toMap() ?? InAppBrowserClassOptions().toMap());
args.putIfAbsent('contextMenu', () => contextMenu?.toMap() ?? {}); args.putIfAbsent('contextMenu', () => contextMenu?.toMap() ?? {});
args.putIfAbsent('windowId', () => windowId); args.putIfAbsent('windowId', () => windowId);
args.putIfAbsent('initialUserScripts', () => initialUserScripts?.map((e) => e.toMap()).toList() ?? []); args.putIfAbsent('initialUserScripts', () => initialUserScripts?.map((e) => e.toMap()).toList() ?? []);
@ -127,7 +151,7 @@ class InAppBrowser {
Map<String, dynamic> args = <String, dynamic>{}; Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('uuid', () => uuid); args.putIfAbsent('uuid', () => uuid);
args.putIfAbsent('assetFilePath', () => assetFilePath); args.putIfAbsent('assetFilePath', () => assetFilePath);
args.putIfAbsent('options', () => options?.toMap() ?? {}); args.putIfAbsent('options', () => options?.toMap() ?? InAppBrowserClassOptions().toMap());
args.putIfAbsent('contextMenu', () => contextMenu?.toMap() ?? {}); args.putIfAbsent('contextMenu', () => contextMenu?.toMap() ?? {});
args.putIfAbsent('windowId', () => windowId); args.putIfAbsent('windowId', () => windowId);
args.putIfAbsent('initialUserScripts', () => initialUserScripts?.map((e) => e.toMap()).toList() ?? []); args.putIfAbsent('initialUserScripts', () => initialUserScripts?.map((e) => e.toMap()).toList() ?? []);
@ -154,12 +178,12 @@ class InAppBrowser {
Map<String, dynamic> args = <String, dynamic>{}; Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('uuid', () => uuid); args.putIfAbsent('uuid', () => uuid);
args.putIfAbsent('options', () => options?.toMap() ?? {}); args.putIfAbsent('options', () => options?.toMap() ?? InAppBrowserClassOptions().toMap());
args.putIfAbsent('data', () => data); args.putIfAbsent('data', () => data);
args.putIfAbsent('mimeType', () => mimeType); args.putIfAbsent('mimeType', () => mimeType);
args.putIfAbsent('encoding', () => encoding); args.putIfAbsent('encoding', () => encoding);
args.putIfAbsent('baseUrl', () => baseUrl ?? Uri.parse("about:blank")); args.putIfAbsent('baseUrl', () => baseUrl?.toString() ?? "about:blank");
args.putIfAbsent('historyUrl', () => androidHistoryUrl ?? Uri.parse("about:blank")); args.putIfAbsent('historyUrl', () => androidHistoryUrl?.toString() ?? "about:blank");
args.putIfAbsent('contextMenu', () => contextMenu?.toMap() ?? {}); args.putIfAbsent('contextMenu', () => contextMenu?.toMap() ?? {});
args.putIfAbsent('windowId', () => windowId); args.putIfAbsent('windowId', () => windowId);
args.putIfAbsent('initialUserScripts', () => initialUserScripts?.map((e) => e.toMap()).toList() ?? []); args.putIfAbsent('initialUserScripts', () => initialUserScripts?.map((e) => e.toMap()).toList() ?? []);
@ -768,7 +792,7 @@ class InAppBrowser {
void throwIfAlreadyOpened({String message = ''}) { void throwIfAlreadyOpened({String message = ''}) {
if (this.isOpened()) { if (this.isOpened()) {
throw Exception([ throw InAppBrowserAlreadyOpenedException([
'Error: ${(message.isEmpty) ? '' : message + ' '}The browser is already opened.' 'Error: ${(message.isEmpty) ? '' : message + ' '}The browser is already opened.'
]); ]);
} }
@ -776,7 +800,7 @@ class InAppBrowser {
void throwIfNotOpened({String message = ''}) { void throwIfNotOpened({String message = ''}) {
if (!this.isOpened()) { if (!this.isOpened()) {
throw Exception([ throw InAppBrowserNotOpenedException([
'Error: ${(message.isEmpty) ? '' : message + ' '}The browser is not opened.' 'Error: ${(message.isEmpty) ? '' : message + ' '}The browser is not opened.'
]); ]);
} }

View File

@ -39,40 +39,40 @@ class BrowserOptions {
///Class that represents the options that can be used for an [InAppBrowser] WebView. ///Class that represents the options that can be used for an [InAppBrowser] WebView.
class InAppBrowserClassOptions { class InAppBrowserClassOptions {
///Cross-platform options. ///Cross-platform options.
InAppBrowserOptions? crossPlatform; late InAppBrowserOptions crossPlatform;
///Android-specific options. ///Android-specific options.
AndroidInAppBrowserOptions? android; late AndroidInAppBrowserOptions android;
///iOS-specific options. ///iOS-specific options.
IOSInAppBrowserOptions? ios; late IOSInAppBrowserOptions ios;
///WebView options. ///WebView options.
InAppWebViewGroupOptions? inAppWebViewGroupOptions; late InAppWebViewGroupOptions inAppWebViewGroupOptions;
InAppBrowserClassOptions( InAppBrowserClassOptions(
{this.crossPlatform, {InAppBrowserOptions? crossPlatform,
this.android, AndroidInAppBrowserOptions? android,
this.ios, IOSInAppBrowserOptions? ios,
this.inAppWebViewGroupOptions}) { InAppWebViewGroupOptions? inAppWebViewGroupOptions}) {
this.crossPlatform = this.crossPlatform ?? InAppBrowserOptions(); this.crossPlatform = crossPlatform ?? InAppBrowserOptions();
this.android = this.android ?? AndroidInAppBrowserOptions(); this.android = android ?? AndroidInAppBrowserOptions();
this.ios = this.ios ?? IOSInAppBrowserOptions(); this.ios = ios ?? IOSInAppBrowserOptions();
this.inAppWebViewGroupOptions = this.inAppWebViewGroupOptions =
this.inAppWebViewGroupOptions ?? InAppWebViewGroupOptions(); inAppWebViewGroupOptions ?? InAppWebViewGroupOptions();
} }
Map<String, dynamic> toMap() { Map<String, dynamic> toMap() {
Map<String, dynamic> options = {}; Map<String, dynamic> options = {};
options.addAll(this.crossPlatform?.toMap() ?? {}); options.addAll(this.crossPlatform.toMap());
options.addAll(this.inAppWebViewGroupOptions?.crossPlatform.toMap() ?? {}); options.addAll(this.inAppWebViewGroupOptions.crossPlatform.toMap());
if (defaultTargetPlatform == TargetPlatform.android) { if (defaultTargetPlatform == TargetPlatform.android) {
options.addAll(this.android?.toMap() ?? {}); options.addAll(this.android.toMap());
options.addAll(this.inAppWebViewGroupOptions?.android.toMap() ?? {}); options.addAll(this.inAppWebViewGroupOptions.android.toMap());
} else if (defaultTargetPlatform == TargetPlatform.iOS) { } else if (defaultTargetPlatform == TargetPlatform.iOS) {
options.addAll(this.ios?.toMap() ?? {}); options.addAll(this.ios.toMap());
options.addAll(this.inAppWebViewGroupOptions?.ios.toMap() ?? {}); options.addAll(this.inAppWebViewGroupOptions.ios.toMap());
} }
return options; return options;
@ -95,16 +95,16 @@ class InAppBrowserClassOptions {
InAppBrowserOptions.fromMap(options); InAppBrowserOptions.fromMap(options);
inAppBrowserClassOptions.inAppWebViewGroupOptions = inAppBrowserClassOptions.inAppWebViewGroupOptions =
InAppWebViewGroupOptions(); InAppWebViewGroupOptions();
inAppBrowserClassOptions.inAppWebViewGroupOptions!.crossPlatform = inAppBrowserClassOptions.inAppWebViewGroupOptions.crossPlatform =
InAppWebViewOptions.fromMap(options); InAppWebViewOptions.fromMap(options);
if (defaultTargetPlatform == TargetPlatform.android) { if (defaultTargetPlatform == TargetPlatform.android) {
inAppBrowserClassOptions.android = inAppBrowserClassOptions.android =
AndroidInAppBrowserOptions.fromMap(options); AndroidInAppBrowserOptions.fromMap(options);
inAppBrowserClassOptions.inAppWebViewGroupOptions!.android = inAppBrowserClassOptions.inAppWebViewGroupOptions.android =
AndroidInAppWebViewOptions.fromMap(options); AndroidInAppWebViewOptions.fromMap(options);
} else if (defaultTargetPlatform == TargetPlatform.iOS) { } else if (defaultTargetPlatform == TargetPlatform.iOS) {
inAppBrowserClassOptions.ios = IOSInAppBrowserOptions.fromMap(options); inAppBrowserClassOptions.ios = IOSInAppBrowserOptions.fromMap(options);
inAppBrowserClassOptions.inAppWebViewGroupOptions!.ios = inAppBrowserClassOptions.inAppWebViewGroupOptions.ios =
IOSInAppWebViewOptions.fromMap(options); IOSInAppWebViewOptions.fromMap(options);
} }

View File

@ -77,7 +77,7 @@ class InAppWebViewController {
MethodChannel('com.pichillilorenzo/flutter_inappwebview_$id'); MethodChannel('com.pichillilorenzo/flutter_inappwebview_$id');
this._channel.setMethodCallHandler(handleMethod); this._channel.setMethodCallHandler(handleMethod);
this._webview = webview; this._webview = webview;
this._userScripts = List<UserScript>.from(webview.initialUserScripts ?? []); this._userScripts = List<UserScript>.from(webview.initialUserScripts ?? <UserScript>[]);
this._init(); this._init();
} }
@ -86,7 +86,7 @@ class InAppWebViewController {
this._inAppBrowserUuid = uuid; this._inAppBrowserUuid = uuid;
this._channel = channel; this._channel = channel;
this._inAppBrowser = inAppBrowser; this._inAppBrowser = inAppBrowser;
this._userScripts = List<UserScript>.from(initialUserScripts ?? []); this._userScripts = List<UserScript>.from(initialUserScripts ?? <UserScript>[]);
this._init(); this._init();
} }
@ -982,6 +982,8 @@ class InAppWebViewController {
///Specify the same value as the URL parameter to prevent WebView from reading any other content. ///Specify the same value as the URL parameter to prevent WebView from reading any other content.
///Specify a directory to give WebView permission to read additional files in the specified directory. ///Specify a directory to give WebView permission to read additional files in the specified directory.
/// ///
///**NOTE for Android**: when loading an URL Request using "POST" method, headers are ignored.
///
///**Official Android API**: https://developer.android.com/reference/android/webkit/WebView#loadUrl(java.lang.String) ///**Official Android API**: https://developer.android.com/reference/android/webkit/WebView#loadUrl(java.lang.String)
/// ///
///**Official iOS API**: ///**Official iOS API**:
@ -1037,8 +1039,8 @@ class InAppWebViewController {
args.putIfAbsent('data', () => data); args.putIfAbsent('data', () => data);
args.putIfAbsent('mimeType', () => mimeType); args.putIfAbsent('mimeType', () => mimeType);
args.putIfAbsent('encoding', () => encoding); args.putIfAbsent('encoding', () => encoding);
args.putIfAbsent('baseUrl', () => baseUrl ?? Uri.parse("about:blank")); args.putIfAbsent('baseUrl', () => baseUrl?.toString() ?? "about:blank");
args.putIfAbsent('historyUrl', () => androidHistoryUrl ?? Uri.parse("about:blank")); args.putIfAbsent('historyUrl', () => androidHistoryUrl?.toString() ?? "about:blank");
await _channel.invokeMethod('loadData', args); await _channel.invokeMethod('loadData', args);
} }
@ -1376,31 +1378,8 @@ class InAppWebViewController {
///**Official iOS API**: https://developer.apple.com/documentation/webkit/wkwebview/1414977-backforwardlist ///**Official iOS API**: https://developer.apple.com/documentation/webkit/wkwebview/1414977-backforwardlist
Future<WebHistory?> getCopyBackForwardList() async { Future<WebHistory?> getCopyBackForwardList() async {
Map<String, dynamic> args = <String, dynamic>{}; Map<String, dynamic> args = <String, dynamic>{};
Map<dynamic, dynamic>? result = Map<String, dynamic>? result = (await _channel.invokeMethod('getCopyBackForwardList', args))?.cast<String, dynamic>();
await _channel.invokeMethod('getCopyBackForwardList', args); return WebHistory.fromMap(result);
if (result == null) {
return null;
}
result = result.cast<String, dynamic>();
List<dynamic> historyListMap = result["history"];
historyListMap = historyListMap.cast<LinkedHashMap<dynamic, dynamic>>();
int currentIndex = result["currentIndex"];
List<WebHistoryItem> historyList = [] as List<WebHistoryItem>;
for (var i = 0; i < historyListMap.length; i++) {
LinkedHashMap<dynamic, dynamic> historyItem = historyListMap[i];
historyList.add(WebHistoryItem(
originalUrl: historyItem["originalUrl"] != null ? Uri.parse(historyItem["originalUrl"]) : null,
title: historyItem["title"],
url: historyItem["url"] != null ? Uri.parse(historyItem["url"]) : null,
index: i,
offset: i - currentIndex));
}
return WebHistory(list: historyList, currentIndex: currentIndex);
} }
///Clears all the webview's cache. ///Clears all the webview's cache.

View File

@ -618,6 +618,8 @@ abstract class WebView {
iosShouldAllowDeprecatedTLS; iosShouldAllowDeprecatedTLS;
///Initial url request that will be loaded. ///Initial url request that will be loaded.
///
///**NOTE for Android**: when loading an URL Request using "POST" method, headers are ignored.
final URLRequest? initialUrlRequest; final URLRequest? initialUrlRequest;
///Initial asset file that will be loaded. See [InAppWebViewController.loadFile] for explanation. ///Initial asset file that will be loaded. See [InAppWebViewController.loadFile] for explanation.

View File

@ -1,3 +1,4 @@
import 'dart:collection';
import 'dart:io'; import 'dart:io';
import 'dart:typed_data'; import 'dart:typed_data';
import 'dart:convert'; import 'dart:convert';
@ -144,17 +145,19 @@ class InAppWebViewInitialData {
///The URL to use as the page's base URL. The default value is `about:blank`. ///The URL to use as the page's base URL. The default value is `about:blank`.
late Uri baseUrl; late Uri baseUrl;
///The URL to use as the history entry. The default value is `about:blank`. If non-null, this must be a valid URL. This parameter is used only on Android. ///The URL to use as the history entry. The default value is `about:blank`. If non-null, this must be a valid URL.
late Uri historyUrl; ///
///This parameter is used only on Android.
late Uri androidHistoryUrl;
InAppWebViewInitialData( InAppWebViewInitialData(
{required this.data, {required this.data,
this.mimeType = "text/html", this.mimeType = "text/html",
this.encoding = "utf8", this.encoding = "utf8",
Uri? baseUrl, Uri? baseUrl,
Uri? historyUrl}) { Uri? androidHistoryUrl}) {
this.baseUrl = baseUrl == null ? Uri.parse("about:blank") : baseUrl; this.baseUrl = baseUrl == null ? Uri.parse("about:blank") : baseUrl;
this.historyUrl = historyUrl == null ? Uri.parse("about:blank") : historyUrl; this.androidHistoryUrl = androidHistoryUrl == null ? Uri.parse("about:blank") : androidHistoryUrl;
} }
Map<String, String> toMap() { Map<String, String> toMap() {
@ -163,7 +166,7 @@ class InAppWebViewInitialData {
"mimeType": mimeType, "mimeType": mimeType,
"encoding": encoding, "encoding": encoding,
"baseUrl": baseUrl.toString(), "baseUrl": baseUrl.toString(),
"historyUrl": historyUrl.toString() "historyUrl": androidHistoryUrl.toString()
}; };
} }
@ -397,6 +400,30 @@ class WebHistory {
WebHistory({this.list, this.currentIndex}); WebHistory({this.list, this.currentIndex});
static WebHistory? fromMap(Map<String, dynamic>? map) {
if (map == null) {
return null;
}
List<LinkedHashMap<dynamic, dynamic>>? historyListMap = map["history"]?.cast<LinkedHashMap<dynamic, dynamic>>();
int currentIndex = map["currentIndex"];
List<WebHistoryItem> historyList = <WebHistoryItem>[];
if (historyListMap != null) {
for (var i = 0; i < historyListMap.length; i++) {
var historyItem = historyListMap[i];
historyList.add(WebHistoryItem(
originalUrl: historyItem["originalUrl"] != null ? Uri.parse(historyItem["originalUrl"]) : null,
title: historyItem["title"],
url: historyItem["url"] != null ? Uri.parse(historyItem["url"]) : null,
index: i,
offset: i - currentIndex));
}
}
return WebHistory(list: historyList, currentIndex: currentIndex);
}
Map<String, dynamic> toMap() { Map<String, dynamic> toMap() {
return {"list": list, "currentIndex": currentIndex}; return {"list": list, "currentIndex": currentIndex};
} }