From 90e5d0a736505a726306171db1d928994cd96b6d Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Wed, 10 Feb 2021 21:22:52 +0100 Subject: [PATCH] added applePayAPIEnabled iOS-specific WebView options, fix #605 --- .idea/libraries/Dart_Packages.xml | 772 ------------------ .idea/libraries/Flutter_Plugins.xml | 5 +- .travis.yml | 3 +- CHANGELOG.md | 2 +- README.md | 1 + example/.flutter-plugins-dependencies | 2 +- .../ios/Flutter/flutter_export_environment.sh | 4 +- example/lib/in_app_webiew_example.screen.dart | 2 +- flutter_inappwebview.iml | 1 - .../InAppBrowserManager.swift | 0 .../InAppBrowserOptions.swift | 0 .../InAppBrowserWebViewController.swift | 0 .../CustomeSchemeHandler.swift | 0 .../FlutterWebViewController.swift | 0 .../FlutterWebViewFactory.swift | 0 .../{ => InAppWebView}/InAppWebView.swift | 82 +- .../InAppWebViewOptions.swift | 9 + .../ChromeSafariBrowserManager.swift | 0 .../SafariBrowserOptions.swift | 0 .../SafariViewController.swift | 0 lib/src/in_app_webview_controller.dart | 2 +- lib/src/webview.dart | 2 +- lib/src/webview_options.dart | 59 +- 23 files changed, 157 insertions(+), 789 deletions(-) delete mode 100644 .idea/libraries/Dart_Packages.xml rename ios/Classes/{ => InAppBrowser}/InAppBrowserManager.swift (100%) rename ios/Classes/{ => InAppBrowser}/InAppBrowserOptions.swift (100%) rename ios/Classes/{ => InAppBrowser}/InAppBrowserWebViewController.swift (100%) rename ios/Classes/{ => InAppWebView}/CustomeSchemeHandler.swift (100%) rename ios/Classes/{ => InAppWebView}/FlutterWebViewController.swift (100%) rename ios/Classes/{ => InAppWebView}/FlutterWebViewFactory.swift (100%) rename ios/Classes/{ => InAppWebView}/InAppWebView.swift (96%) rename ios/Classes/{ => InAppWebView}/InAppWebViewOptions.swift (95%) rename ios/Classes/{ => SafariViewController}/ChromeSafariBrowserManager.swift (100%) rename ios/Classes/{ => SafariViewController}/SafariBrowserOptions.swift (100%) rename ios/Classes/{ => SafariViewController}/SafariViewController.swift (100%) diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml deleted file mode 100644 index 787c9c8a..00000000 --- a/.idea/libraries/Dart_Packages.xml +++ /dev/null @@ -1,772 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml index 31799730..c241dc8c 100755 --- a/.idea/libraries/Flutter_Plugins.xml +++ b/.idea/libraries/Flutter_Plugins.xml @@ -1,6 +1,9 @@ - + + + + diff --git a/.travis.yml b/.travis.yml index 8b124ada..61e03174 100644 --- a/.travis.yml +++ b/.travis.yml @@ -58,7 +58,8 @@ jobs: - 'android-sdk-license-.+' - 'google-gdk-license-.+' before_install: - - sdkmanager tools + - yes | sdkmanager --licenses + - sdkmanager tools > /dev/null - sdkmanager "system-images;android-30;google_apis;x86" > /dev/null - echo no | avdmanager --verbose create avd --force -n test -k "system-images;android-30;google_apis;x86" - emulator -avd test -verbose -no-window -no-audio & diff --git a/CHANGELOG.md b/CHANGELOG.md index b4802b26..d3b915c4 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ - Added `initialUserScripts` WebView option - Added `addUserScript`, `addUserScripts`, `removeUserScript`, `removeUserScripts`, `removeAllUserScripts`, `callAsyncJavaScript` WebView methods - Added `contentWorld` argument to `evaluateJavascript` WebView method -- Added `isDirectionalLockEnabled`, `mediaType`, `pageZoom`, `limitsNavigationsToAppBoundDomains`, `useOnNavigationResponse` iOS-specific WebView options +- Added `isDirectionalLockEnabled`, `mediaType`, `pageZoom`, `limitsNavigationsToAppBoundDomains`, `useOnNavigationResponse`, `applePayAPIEnabled` iOS-specific WebView options - Added `handlesURLScheme`, `createPdf`, `createWebArchiveData` iOS-specific WebView methods - Added `iosOnNavigationResponse` and `iosShouldAllowDeprecatedTLS` iOS-specific WebView events - Added `iosAnimated` optional argument to `zoomBy` WebView method diff --git a/README.md b/README.md index 7eb05be7..e2fa5084 100755 --- a/README.md +++ b/README.md @@ -643,6 +643,7 @@ Instead, on the `onLoadStop` WebView event, you can use `callHandler` directly: * `allowsPictureInPictureMediaPlayback`: Set to `true` to allow HTML5 videos play picture-in-picture. The default value is `true`. * `alwaysBounceHorizontal`: A Boolean value that determines whether bouncing always occurs when horizontal scrolling reaches the end of the content view. The default value is `false`. * `alwaysBounceVertical`: A Boolean value that determines whether bouncing always occurs when vertical scrolling reaches the end of the content. The default value is `false`. +* `applePayAPIEnabled`: A * `automaticallyAdjustsScrollIndicatorInsets`: Configures whether the scroll indicator insets are automatically adjusted by the system. The default value is `false`. * `contentInsetAdjustmentBehavior`: Configures how safe area insets are added to the adjusted content inset. The default value is `IOSUIScrollViewContentInsetAdjustmentBehavior.NEVER`. * `dataDetectorTypes`: Specifying a dataDetectoryTypes value adds interactivity to web content that matches the value. diff --git a/example/.flutter-plugins-dependencies b/example/.flutter-plugins-dependencies index 4c22ebd3..b1ccb4e1 100644 --- a/example/.flutter-plugins-dependencies +++ b/example/.flutter-plugins-dependencies @@ -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-1.6.27/","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-1.6.27/","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.4+8/","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.0.1+2/","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.0.4+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-10 17:06:20.294420","version":"1.26.0-18.0.pre.257"} \ No newline at end of file +{"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-1.6.27/","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-1.6.27/","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.4+8/","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.0.1+2/","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.0.4+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-10 18:12:10.702361","version":"1.26.0-18.0.pre.257"} \ No newline at end of file diff --git a/example/ios/Flutter/flutter_export_environment.sh b/example/ios/Flutter/flutter_export_environment.sh index b59a9d8e..ff2151af 100755 --- a/example/ios/Flutter/flutter_export_environment.sh +++ b/example/ios/Flutter/flutter_export_environment.sh @@ -2,12 +2,12 @@ # This is a generated file; do not edit or check into version control. export "FLUTTER_ROOT=/Users/lorenzopichilli/flutter" export "FLUTTER_APPLICATION_PATH=/Users/lorenzopichilli/Desktop/flutter_inappwebview/example" -export "FLUTTER_TARGET=integration_test/webview_flutter_test.dart" +export "FLUTTER_TARGET=/Users/lorenzopichilli/Desktop/flutter_inappwebview/example/lib/main.dart" export "FLUTTER_BUILD_DIR=build" export "SYMROOT=${SOURCE_ROOT}/../build/ios" export "FLUTTER_BUILD_NAME=1.0.0" export "FLUTTER_BUILD_NUMBER=1" -export "DART_DEFINES=RkxVVFRFUl9XRUJfQVVUT19ERVRFQ1Q9dHJ1ZQ==" +export "DART_DEFINES=Zmx1dHRlci5pbnNwZWN0b3Iuc3RydWN0dXJlZEVycm9ycz10cnVl,RkxVVFRFUl9XRUJfQVVUT19ERVRFQ1Q9dHJ1ZQ==" export "DART_OBFUSCATION=false" export "TRACK_WIDGET_CREATION=true" export "TREE_SHAKE_ICONS=false" diff --git a/example/lib/in_app_webiew_example.screen.dart b/example/lib/in_app_webiew_example.screen.dart index 8033a280..d549bee6 100755 --- a/example/lib/in_app_webiew_example.screen.dart +++ b/example/lib/in_app_webiew_example.screen.dart @@ -95,13 +95,13 @@ class _InAppWebViewExampleScreenState extends State { crossPlatform: InAppWebViewOptions( useShouldOverrideUrlLoading: false, mediaPlaybackRequiresUserGesture: false, - clearCache: true ), android: AndroidInAppWebViewOptions( useHybridComposition: true, ), ios: IOSInAppWebViewOptions( allowsInlineMediaPlayback: true, + applePayAPIEnabled: false, // limitsNavigationsToAppBoundDomains: true // adds Service Worker API on iOS 14.0+ ) ), diff --git a/flutter_inappwebview.iml b/flutter_inappwebview.iml index 4cb39159..0adae5aa 100755 --- a/flutter_inappwebview.iml +++ b/flutter_inappwebview.iml @@ -80,6 +80,5 @@ - \ No newline at end of file diff --git a/ios/Classes/InAppBrowserManager.swift b/ios/Classes/InAppBrowser/InAppBrowserManager.swift similarity index 100% rename from ios/Classes/InAppBrowserManager.swift rename to ios/Classes/InAppBrowser/InAppBrowserManager.swift diff --git a/ios/Classes/InAppBrowserOptions.swift b/ios/Classes/InAppBrowser/InAppBrowserOptions.swift similarity index 100% rename from ios/Classes/InAppBrowserOptions.swift rename to ios/Classes/InAppBrowser/InAppBrowserOptions.swift diff --git a/ios/Classes/InAppBrowserWebViewController.swift b/ios/Classes/InAppBrowser/InAppBrowserWebViewController.swift similarity index 100% rename from ios/Classes/InAppBrowserWebViewController.swift rename to ios/Classes/InAppBrowser/InAppBrowserWebViewController.swift diff --git a/ios/Classes/CustomeSchemeHandler.swift b/ios/Classes/InAppWebView/CustomeSchemeHandler.swift similarity index 100% rename from ios/Classes/CustomeSchemeHandler.swift rename to ios/Classes/InAppWebView/CustomeSchemeHandler.swift diff --git a/ios/Classes/FlutterWebViewController.swift b/ios/Classes/InAppWebView/FlutterWebViewController.swift similarity index 100% rename from ios/Classes/FlutterWebViewController.swift rename to ios/Classes/InAppWebView/FlutterWebViewController.swift diff --git a/ios/Classes/FlutterWebViewFactory.swift b/ios/Classes/InAppWebView/FlutterWebViewFactory.swift similarity index 100% rename from ios/Classes/FlutterWebViewFactory.swift rename to ios/Classes/InAppWebView/FlutterWebViewFactory.swift diff --git a/ios/Classes/InAppWebView.swift b/ios/Classes/InAppWebView/InAppWebView.swift similarity index 96% rename from ios/Classes/InAppWebView.swift rename to ios/Classes/InAppWebView/InAppWebView.swift index ae9e5cb8..6f280f7f 100755 --- a/ios/Classes/InAppWebView.swift +++ b/ios/Classes/InAppWebView/InAppWebView.swift @@ -995,8 +995,10 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi self.evaluateJavaScript("window.\(JAVASCRIPT_BRIDGE_NAME)._findElementsAtPoint(\(touchLocation.x),\(touchLocation.y))", completionHandler: {(value, error) in if error != nil { print("Long press gesture recognizer error: \(error?.localizedDescription ?? "")") - } else { + } else if let value = value { self.onLongPressHitTestResult(hitTestResult: value as! [String: Any?]) + } else { + self.onLongPressHitTestResult(hitTestResult: [:]) } }) } @@ -1218,6 +1220,10 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi } public func prepareAndAddUserScripts() -> Void { + if let applePayAPIEnabled = options?.applePayAPIEnabled, applePayAPIEnabled { + return + } + addWindowIdUserScript() if windowId != nil { // the new created window webview has the same WKWebViewConfiguration variable reference @@ -1355,6 +1361,9 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi } func addPluginUserScripts() -> Void { + if let applePayAPIEnabled = options?.applePayAPIEnabled, applePayAPIEnabled { + return + } addSharedPluginUserScriptsInContentWorlds() let findElementsAtPointJSScript = WKUserScript(source: findElementsAtPointJS, injectionTime: .atDocumentStart, forMainFrameOnly: false) @@ -1402,6 +1411,10 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi } public func addUserScript(wkUserScript: WKUserScript) -> Void { + if let applePayAPIEnabled = options?.applePayAPIEnabled, applePayAPIEnabled { + return + } + userScripts.append(wkUserScript) configuration.userContentController.addUserScript(wkUserScript) } @@ -1442,6 +1455,11 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi // there isn't a way to remove a specific user script using WKUserContentController, // so we remove all the user scripts and, then, we add them again without the one that has been removed configuration.userContentController.removeAllUserScripts() + + if let applePayAPIEnabled = options?.applePayAPIEnabled, applePayAPIEnabled { + return + } + addWindowIdUserScript() addPluginUserScripts() addAllUserScripts() @@ -1450,6 +1468,11 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi public func removeAllUserScripts() -> Void { userScripts.removeAll() configuration.userContentController.removeAllUserScripts() + + if let applePayAPIEnabled = options?.applePayAPIEnabled, applePayAPIEnabled { + return + } + // add all the necessary base WKUserScripts of this plugin again addWindowIdUserScript() addPluginUserScripts() @@ -1639,10 +1662,12 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi self.evaluateJavaScript("window.\(JAVASCRIPT_BRIDGE_NAME)._findElementsAtPoint(\(lastLongPressTouhLocation.x),\(lastLongPressTouhLocation.y))", completionHandler: {(value, error) in if error != nil { print("Long press gesture recognizer error: \(error?.localizedDescription ?? "")") - } else { + } else if let value = value { let hitTestResult = value as! [String: Any?] arguments["hitTestResult"] = hitTestResult self.channel?.invokeMethod("onCreateContextMenu", arguments: arguments) + } else { + self.channel?.invokeMethod("onCreateContextMenu", arguments: arguments) } }) } else { @@ -1867,6 +1892,21 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi func setOptions(newOptions: InAppWebViewOptions, newOptionsMap: [String: Any]) { + // MUST be the first! In this way, all the options that uses evaluateJavaScript can be applied/blocked! + if #available(iOS 13.0, *) { + if newOptionsMap["applePayAPIEnabled"] != nil && options?.applePayAPIEnabled != newOptions.applePayAPIEnabled { + if let options = options { + options.applePayAPIEnabled = newOptions.applePayAPIEnabled + } + if !newOptions.applePayAPIEnabled { + // re-add WKUserScripts for the next page load + prepareAndAddUserScripts() + } else { + configuration.userContentController.removeAllUserScripts() + } + } + } + if newOptionsMap["transparentBackground"] != nil && options?.transparentBackground != newOptions.transparentBackground { if newOptions.transparentBackground { isOpaque = false @@ -1950,7 +1990,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi if #available(iOS 14.0, *) { for contentWorldName in userScriptsContentWorlds { let contentWorld = getContentWorld(name: contentWorldName) - evaluateJavaScript(source, in: nil, in: contentWorld, completionHandler: nil) + evaluateJavaScript(source, frame: nil, contentWorld: contentWorld, completionHandler: nil) } } else { evaluateJavaScript(source, completionHandler: nil) @@ -1964,7 +2004,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi if #available(iOS 14.0, *) { for contentWorldName in userScriptsContentWorlds { let contentWorld = getContentWorld(name: contentWorldName) - evaluateJavaScript(source, in: nil, in: contentWorld, completionHandler: nil) + evaluateJavaScript(source, frame: nil, contentWorld: contentWorld, completionHandler: nil) } } else { evaluateJavaScript(source, completionHandler: nil) @@ -2192,7 +2232,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi jsToInject = getAllPluginUserScriptMergedJS() + "\n" + jsToInject } let contentWorld = getContentWorld(name: contentWorldName) - evaluateJavaScript(jsToInject, in: nil, in: contentWorld) { (evalResult) in + evaluateJavaScript(jsToInject, frame: nil, contentWorld: contentWorld) { (evalResult) in guard let result = result else { return } @@ -2230,12 +2270,42 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi } } + public override func evaluateJavaScript(_ javaScriptString: String, completionHandler: ((Any?, Error?) -> Void)? = nil) { + if let applePayAPIEnabled = options?.applePayAPIEnabled, applePayAPIEnabled { + if let completionHandler = completionHandler { + completionHandler(nil, nil) + } + return + } + super.evaluateJavaScript(javaScriptString, completionHandler: completionHandler) + } + + @available(iOS 14.0, *) + public func evaluateJavaScript(_ javaScript: String, frame: WKFrameInfo? = nil, contentWorld: WKContentWorld, completionHandler: ((Result) -> Void)? = nil) { + if let applePayAPIEnabled = options?.applePayAPIEnabled, applePayAPIEnabled { + return + } + super.evaluateJavaScript(javaScript, in: frame, in: contentWorld, completionHandler: completionHandler) + } + public func evaluateJavascript(source: String, contentWorldName: String?, result: @escaping FlutterResult) { injectDeferredObject(source: source, contentWorldName: contentWorldName, withWrapper: nil, result: result) } + @available(iOS 14.0, *) + public func callAsyncJavaScript(_ functionBody: String, arguments: [String : Any] = [:], frame: WKFrameInfo? = nil, contentWorld: WKContentWorld, completionHandler: ((Result) -> Void)? = nil) { + if let applePayAPIEnabled = options?.applePayAPIEnabled, applePayAPIEnabled { + return + } + super.callAsyncJavaScript(functionBody, arguments: arguments, in: frame, in: contentWorld, completionHandler: completionHandler) + } + @available(iOS 10.3, *) public func callAsyncJavaScript(functionBody: String, arguments: [String:Any], contentWorldName: String?, result: @escaping FlutterResult) { + if let applePayAPIEnabled = options?.applePayAPIEnabled, applePayAPIEnabled { + result(nil) + } + var jsToInject = functionBody if #available(iOS 14.0, *) { var contentWorld = WKContentWorld.page @@ -2249,7 +2319,7 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi jsToInject = getAllPluginUserScriptMergedJS() + "\n" + jsToInject } } - callAsyncJavaScript(jsToInject, arguments: arguments, in: nil, in: contentWorld) { (evalResult) in + callAsyncJavaScript(jsToInject, arguments: arguments, frame: nil, contentWorld: contentWorld) { (evalResult) in var body: [String: Any?] = [ "value": nil, "error": nil diff --git a/ios/Classes/InAppWebViewOptions.swift b/ios/Classes/InAppWebView/InAppWebViewOptions.swift similarity index 95% rename from ios/Classes/InAppWebViewOptions.swift rename to ios/Classes/InAppWebView/InAppWebViewOptions.swift index 9ac27598..a9f0e1d2 100755 --- a/ios/Classes/InAppWebViewOptions.swift +++ b/ios/Classes/InAppWebView/InAppWebViewOptions.swift @@ -66,11 +66,20 @@ public class InAppWebViewOptions: Options { var pageZoom = 1.0 var limitsNavigationsToAppBoundDomains = false var useOnNavigationResponse = false + var applePayAPIEnabled = false override init(){ super.init() } + override func parse(options: [String: Any?]) -> InAppWebViewOptions { + let _ = super.parse(options: options) + if #available(iOS 13.0, *) {} else { + applePayAPIEnabled = false + } + return self + } + override func getRealOptions(obj: InAppWebView?) -> [String: Any?] { var realOptions: [String: Any?] = toMap() if let webView = obj { diff --git a/ios/Classes/ChromeSafariBrowserManager.swift b/ios/Classes/SafariViewController/ChromeSafariBrowserManager.swift similarity index 100% rename from ios/Classes/ChromeSafariBrowserManager.swift rename to ios/Classes/SafariViewController/ChromeSafariBrowserManager.swift diff --git a/ios/Classes/SafariBrowserOptions.swift b/ios/Classes/SafariViewController/SafariBrowserOptions.swift similarity index 100% rename from ios/Classes/SafariBrowserOptions.swift rename to ios/Classes/SafariViewController/SafariBrowserOptions.swift diff --git a/ios/Classes/SafariViewController.swift b/ios/Classes/SafariViewController/SafariViewController.swift similarity index 100% rename from ios/Classes/SafariViewController.swift rename to ios/Classes/SafariViewController/SafariViewController.swift diff --git a/lib/src/in_app_webview_controller.dart b/lib/src/in_app_webview_controller.dart index b615e79b..f74e5083 100644 --- a/lib/src/in_app_webview_controller.dart +++ b/lib/src/in_app_webview_controller.dart @@ -701,7 +701,7 @@ class InAppWebViewController { call.arguments["hitTestResult"]; InAppWebViewHitTestResultType? type = InAppWebViewHitTestResultType.fromValue( - hitTestResultMap?["type"].toInt()); + hitTestResultMap?["type"]?.toInt()); String? extra = hitTestResultMap?["extra"]; InAppWebViewHitTestResult hitTestResult = InAppWebViewHitTestResult(type: type, extra: extra); diff --git a/lib/src/webview.dart b/lib/src/webview.dart index cce7afb6..ac7a57d4 100644 --- a/lib/src/webview.dart +++ b/lib/src/webview.dart @@ -151,7 +151,7 @@ abstract class WebView { ///[IOSInAppWebViewOptions.enableViewportScale], [IOSInAppWebViewOptions.allowsAirPlayForMediaPlayback], ///[IOSInAppWebViewOptions.allowsPictureInPictureMediaPlayback], [IOSInAppWebViewOptions.isFraudulentWebsiteWarningEnabled], ///[IOSInAppWebViewOptions.allowsInlineMediaPlayback], [IOSInAppWebViewOptions.suppressesIncrementalRendering], [IOSInAppWebViewOptions.selectionGranularity], - ///[IOSInAppWebViewOptions.ignoresViewportScaleLimits], + ///[IOSInAppWebViewOptions.ignoresViewportScaleLimits], [IOSInAppWebViewOptions.limitsNavigationsToAppBoundDomains], ///will have no effect due to a `WKWebView` limitation when creating the new window WebView: it's impossible to return the new `WKWebView` ///with a different `WKWebViewConfiguration` instance (see https://developer.apple.com/documentation/webkit/wkuidelegate/1536907-webview). ///So, these options will be inherited from the caller WebView. diff --git a/lib/src/webview_options.dart b/lib/src/webview_options.dart index 8408b571..cb0ea5d4 100755 --- a/lib/src/webview_options.dart +++ b/lib/src/webview_options.dart @@ -1,4 +1,5 @@ import 'package:flutter/foundation.dart'; +import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'content_blocker.dart'; import 'types.dart'; @@ -869,6 +870,59 @@ class IOSInAppWebViewOptions ///Set to `true` to be able to listen at the [WebView.iosOnNavigationResponse] event. The default value is `false`. bool useOnNavigationResponse; + ///Set to `true` to enable Apple Pay API for the [WebView] at its first page load or on the next page load (using [InAppWebViewController.setOptions]). The default value is `false`. + /// + ///**IMPORTANT NOTE**: As written in the official [Safari 13 Release Notes](https://developer.apple.com/documentation/safari-release-notes/safari-13-release-notes#Payment-Request-API), + ///it won't work if any script injection APIs is used (such as [InAppWebViewController.evaluateJavascript] or [UserScript]). + ///So, when this attribute is `true`, all the methods, options and events implemented using JavaScript won't be called or won't do anything and the result will always be `null`. + /// + ///Methods affected: + ///- [InAppWebViewController.addUserScript] + ///- [InAppWebViewController.addUserScripts] + ///- [InAppWebViewController.removeUserScript] + ///- [InAppWebViewController.removeUserScripts] + ///- [InAppWebViewController.removeAllUserScripts] + ///- [InAppWebViewController.evaluateJavascript] + ///- [InAppWebViewController.callAsyncJavaScript] + ///- [InAppWebViewController.injectJavascriptFileFromUrl] + ///- [InAppWebViewController.injectJavascriptFileFromAsset] + ///- [InAppWebViewController.injectCSSCode] + ///- [InAppWebViewController.injectCSSFileFromUrl] + ///- [InAppWebViewController.injectCSSFileFromAsset] + ///- [InAppWebViewController.findAllAsync] + ///- [InAppWebViewController.findNext] + ///- [InAppWebViewController.clearMatches] + ///- [InAppWebViewController.pauseTimers] + ///- [InAppWebViewController.getSelectedText] + ///- [InAppWebViewController.getHitTestResult] + ///- [InAppWebViewController.requestFocusNodeHref] + ///- [InAppWebViewController.requestImageRef] + /// + ///Options affected: + ///- [WebView.initialUserScripts] + ///- [InAppWebViewOptions.supportZoom] + ///- [InAppWebViewOptions.useOnLoadResource] + ///- [InAppWebViewOptions.useShouldInterceptAjaxRequest] + ///- [InAppWebViewOptions.useShouldInterceptFetchRequest] + ///- [IOSInAppWebViewOptions.enableViewportScale] + /// + ///Events affected: + ///- the `hitTestResult` argument of [WebView.onLongPressHitTestResult] will be empty + ///- the `hitTestResult` argument of [ContextMenu.onCreateContextMenu] will be empty + ///- [WebView.onLoadResource] + ///- [WebView.shouldInterceptAjaxRequest] + ///- [WebView.onAjaxReadyStateChange] + ///- [WebView.onAjaxProgress] + ///- [WebView.shouldInterceptFetchRequest] + ///- [WebView.onConsoleMessage] + ///- [WebView.onPrint] + ///- [WebView.onWindowFocus] + ///- [WebView.onWindowBlur] + ///- [WebView.onFindResultReceived] + /// + ///**NOTE**: available on iOS 13.0+. + bool applePayAPIEnabled; + IOSInAppWebViewOptions( {this.disallowOverScroll = false, this.enableViewportScale = false, @@ -898,7 +952,8 @@ class IOSInAppWebViewOptions this.mediaType, this.pageZoom = 1.0, this.limitsNavigationsToAppBoundDomains = false, - this.useOnNavigationResponse = false}); + this.useOnNavigationResponse = false, + this.applePayAPIEnabled = false}); @override Map toMap() { @@ -939,6 +994,7 @@ class IOSInAppWebViewOptions "pageZoom": pageZoom, "limitsNavigationsToAppBoundDomains": limitsNavigationsToAppBoundDomains, "useOnNavigationResponse": useOnNavigationResponse, + "applePayAPIEnabled": applePayAPIEnabled, }; } @@ -993,6 +1049,7 @@ class IOSInAppWebViewOptions options.pageZoom = map["pageZoom"]; options.limitsNavigationsToAppBoundDomains = map["limitsNavigationsToAppBoundDomains"]; options.useOnNavigationResponse = map["useOnNavigationResponse"]; + options.applePayAPIEnabled = map["applePayAPIEnabled"]; return options; }