From b15ae759d55e595870ee458e82ad5006d6bffb45 Mon Sep 17 00:00:00 2001 From: Lorenzo Pichilli Date: Mon, 8 Feb 2021 18:28:35 +0100 Subject: [PATCH] added createPdf ios webview method, fixed null config takeScreenshot android exception --- CHANGELOG.md | 6 +- README.md | 3 +- .../InAppWebView/InAppWebView.java | 63 ++++++++++--------- example/.flutter-plugins-dependencies | 2 +- example/ios/Flutter/Flutter.podspec | 18 ++++++ .../ios/Flutter/flutter_export_environment.sh | 8 ++- example/ios/Runner.xcodeproj/project.pbxproj | 6 +- example/lib/in_app_webiew_example.screen.dart | 1 + ios/Classes/InAppWebView.swift | 24 +++++++ ios/Classes/InAppWebViewMethodHandler.swift | 11 ++++ lib/src/in_app_webview_controller.dart | 9 +++ lib/src/types.dart | 28 +++++++++ 12 files changed, 140 insertions(+), 39 deletions(-) create mode 100644 example/ios/Flutter/Flutter.podspec diff --git a/CHANGELOG.md b/CHANGELOG.md index 4821b4e6..654c23ab 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,12 +5,12 @@ - Added `allowUniversalAccessFromFileURLs` and `allowFileAccessFromFileURLs` WebView options also for iOS (also thanks to [liranhao](https://github.com/liranhao)) - Added limited cookies support on iOS below 11.0 using JavaScript - Added `IOSCookieManager` class and `CookieManager.instance().ios.getAllCookies` iOS-specific method -- Added `UserScript`, `UserScriptInjectionTime`, `ContentWorld`, `AndroidWebViewFeature`, `AndroidServiceWorkerController`, `AndroidServiceWorkerClient`, `ScreenshotConfiguration` classes +- Added `UserScript`, `UserScriptInjectionTime`, `ContentWorld`, `AndroidWebViewFeature`, `AndroidServiceWorkerController`, `AndroidServiceWorkerClient`, `ScreenshotConfiguration`, `IOSWKPDFConfiguration` classes - 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` iOS-specific webview options -- Added `handlesURLScheme` iOS-specific webview method +- Added `isDirectionalLockEnabled`, `mediaType`, `pageZoom`, `limitsNavigationsToAppBoundDomains` iOS-specific WebView options +- Added `handlesURLScheme`, `createPdf` iOS-specific WebView methods - Added `iosAnimated` optional argument to `zoomBy` WebView method - Added `screenshotConfiguration` optional argument to `takeScreenshot` WebView method - Updated integration tests diff --git a/README.md b/README.md index 2e5d9814..19f66a21 100755 --- a/README.md +++ b/README.md @@ -449,7 +449,7 @@ Screenshots: * `setContextMenu(ContextMenu contextMenu)`: Sets or updates the WebView context menu to be used next time it will appear. * `setOptions({required InAppWebViewGroupOptions options})`: Sets the WebView options with the new options and evaluates them. * `stopLoading`: Stops the WebView from loading. -* `takeScreenshot`: Takes a screenshot (in PNG format) of the WebView's visible viewport and returns a `Uint8List`. Returns `null` if it wasn't be able to take it. +* `takeScreenshot({ScreenshotConfiguration? screenshotConfiguration})`: Takes a screenshot (in PNG format) of the WebView's visible viewport and returns a `Uint8List`. Returns `null` if it wasn't be able to take it. * `zoomBy({required double zoomFactor, bool iosAnimated = false})`: Performs a zoom operation in this WebView. * `static getDefaultUserAgent`: Gets the default user agent. @@ -493,6 +493,7 @@ Android-specific methods can be called using the `InAppWebViewController.android iOS-specific methods can be called using the `InAppWebViewController.ios` attribute. Static methods can be called using the `IOSInAppWebViewController` class directly. +* `createPdf({IOSWKPDFConfiguration? iosWKPdfConfiguration})`: Generates PDF data from the web view’s contents asynchronously. * `hasOnlySecureContent`: A Boolean value indicating whether all resources on the page have been loaded over securely encrypted connections. * `reloadFromOrigin`: Reloads the current page, performing end-to-end revalidation using cache-validating conditionals if possible. * `static handlesURLScheme(String urlScheme)`: Returns a Boolean value that indicates whether WebKit natively supports resources with the specified URL scheme. diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebView.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebView.java index 0ff3a5c1..3e156fd7 100755 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebView.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/InAppWebView/InAppWebView.java @@ -1132,7 +1132,7 @@ final public class InAppWebView extends InputAwareWebView { WebStorage.getInstance().deleteAllData(); } - public void takeScreenshot(final Map screenshotConfiguration, final MethodChannel.Result result) { + public void takeScreenshot(final @Nullable Map screenshotConfiguration, final MethodChannel.Result result) { headlessHandler.post(new Runnable() { @Override public void run() { @@ -1163,40 +1163,45 @@ final public class InAppWebView extends InputAwareWebView { Bitmap resized = Bitmap.createBitmap(b, rectX, rectY, rectWidth, rectHeight); - Map rect = (Map) screenshotConfiguration.get("rect"); - if (rect != null) { - rectX = (int) Math.floor(rect.get("x") * scale + 0.5); - rectY = (int) Math.floor(rect.get("y") * scale + 0.5); - rectWidth = Math.min(resized.getWidth(), (int) Math.floor(rect.get("width") * scale + 0.5)); - rectHeight = Math.min(resized.getHeight(), (int) Math.floor(rect.get("height") * scale + 0.5)); - resized = Bitmap.createBitmap( - b, - rectX, - rectY, - rectWidth, - rectHeight); - } - - Double snapshotWidth = (Double) screenshotConfiguration.get("snapshotWidth"); - if (snapshotWidth != null) { - int dstWidth = (int) Math.floor(snapshotWidth * scale + 0.5); - float ratioBitmap = (float) resized.getWidth() / (float) resized.getHeight(); - int dstHeight = (int) ((float) dstWidth / ratioBitmap); - resized = Bitmap.createScaledBitmap(resized, dstWidth, dstHeight, true); - } - ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - Bitmap.CompressFormat compressFormat = Bitmap.CompressFormat.PNG; - try { - compressFormat = Bitmap.CompressFormat.valueOf((String) screenshotConfiguration.get("compressFormat")); - } catch (IllegalArgumentException e) { - e.printStackTrace(); + int quality = 100; + + if (screenshotConfiguration != null) { + Map rect = (Map) screenshotConfiguration.get("rect"); + if (rect != null) { + rectX = (int) Math.floor(rect.get("x") * scale + 0.5); + rectY = (int) Math.floor(rect.get("y") * scale + 0.5); + rectWidth = Math.min(resized.getWidth(), (int) Math.floor(rect.get("width") * scale + 0.5)); + rectHeight = Math.min(resized.getHeight(), (int) Math.floor(rect.get("height") * scale + 0.5)); + resized = Bitmap.createBitmap( + b, + rectX, + rectY, + rectWidth, + rectHeight); + } + + Double snapshotWidth = (Double) screenshotConfiguration.get("snapshotWidth"); + if (snapshotWidth != null) { + int dstWidth = (int) Math.floor(snapshotWidth * scale + 0.5); + float ratioBitmap = (float) resized.getWidth() / (float) resized.getHeight(); + int dstHeight = (int) ((float) dstWidth / ratioBitmap); + resized = Bitmap.createScaledBitmap(resized, dstWidth, dstHeight, true); + } + + try { + compressFormat = Bitmap.CompressFormat.valueOf((String) screenshotConfiguration.get("compressFormat")); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } + + quality = (Integer) screenshotConfiguration.get("quality"); } resized.compress( compressFormat, - (Integer) screenshotConfiguration.get("quality"), + quality, byteArrayOutputStream); try { diff --git a/example/.flutter-plugins-dependencies b/example/.flutter-plugins-dependencies index 58ebbeae..d20f8952 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/.pub-cache/git/plugins-16f3281b04b0db12e609352b1c9544901392e428/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.0.1+1/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.4/","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/.pub-cache/git/plugins-16f3281b04b0db12e609352b1c9544901392e428/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.0.1+1/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.4/","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-08 01:11:20.039088","version":"1.26.0-18.0.pre.90"} \ 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/.pub-cache/git/plugins-16f3281b04b0db12e609352b1c9544901392e428/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.0.1+1/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.4/","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/.pub-cache/git/plugins-16f3281b04b0db12e609352b1c9544901392e428/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.0.1+1/","dependencies":[]},{"name":"url_launcher","path":"/Users/lorenzopichilli/flutter/.pub-cache/hosted/pub.dartlang.org/url_launcher-6.0.0-nullsafety.4/","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-08 18:26:05.315620","version":"1.26.0-18.0.pre.90"} \ No newline at end of file diff --git a/example/ios/Flutter/Flutter.podspec b/example/ios/Flutter/Flutter.podspec new file mode 100644 index 00000000..2c4421cf --- /dev/null +++ b/example/ios/Flutter/Flutter.podspec @@ -0,0 +1,18 @@ +# +# NOTE: This podspec is NOT to be published. It is only used as a local source! +# This is a generated file; do not edit or check into version control. +# + +Pod::Spec.new do |s| + s.name = 'Flutter' + s.version = '1.0.0' + s.summary = 'High-performance, high-fidelity mobile apps.' + s.homepage = 'https://flutter.io' + s.license = { :type => 'MIT' } + s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' } + s.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s } + s.ios.deployment_target = '8.0' + # Framework linking is handled by Flutter tooling, not CocoaPods. + # Add a placeholder to satisfy `s.dependency 'Flutter'` plugin podspecs. + s.vendored_frameworks = 'path/to/nothing' +end diff --git a/example/ios/Flutter/flutter_export_environment.sh b/example/ios/Flutter/flutter_export_environment.sh index d22068ce..e95c3106 100755 --- a/example/ios/Flutter/flutter_export_environment.sh +++ b/example/ios/Flutter/flutter_export_environment.sh @@ -2,12 +2,14 @@ # 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=lib/main.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=flutter.inspector.structuredErrors%3Dtrue,FLUTTER_WEB_AUTO_DETECT%3Dtrue" export "DART_OBFUSCATION=false" -export "TRACK_WIDGET_CREATION=false" +export "EXTRA_FRONT_END_OPTIONS=--no-sound-null-safety" +export "TRACK_WIDGET_CREATION=true" export "TREE_SHAKE_ICONS=false" -export "PACKAGE_CONFIG=.packages" +export "PACKAGE_CONFIG=/Users/lorenzopichilli/Desktop/flutter_inappwebview/example/.dart_tool/package_config.json" diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index a6a7ee19..c967f816 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -9,7 +9,7 @@ /* Begin PBXBuildFile section */ 020EF14E4245221B2C22ACE5 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B0FC2CF7A6002799890B3102 /* Pods_Runner.framework */; }; 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; - 25A517508F43E58C47090625 /* (null) in Frameworks */ = {isa = PBXBuildFile; }; + 25A517508F43E58C47090625 /* BuildFile in Frameworks */ = {isa = PBXBuildFile; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 61FF730023634CA10069C557 /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 61FF72FF23634CA10069C557 /* libsqlite3.tbd */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; @@ -58,7 +58,7 @@ buildActionMask = 2147483647; files = ( 61FF730023634CA10069C557 /* libsqlite3.tbd in Frameworks */, - 25A517508F43E58C47090625 /* (null) in Frameworks */, + 25A517508F43E58C47090625 /* BuildFile in Frameworks */, 020EF14E4245221B2C22ACE5 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -262,6 +262,7 @@ "${BUILT_PRODUCTS_DIR}/flutter_inappwebview/flutter_inappwebview.framework", "${BUILT_PRODUCTS_DIR}/integration_test/integration_test.framework", "${BUILT_PRODUCTS_DIR}/path_provider/path_provider.framework", + "${BUILT_PRODUCTS_DIR}/pdf_viewer_plugin/pdf_viewer_plugin.framework", "${BUILT_PRODUCTS_DIR}/url_launcher/url_launcher.framework", ); name = "[CP] Embed Pods Frameworks"; @@ -271,6 +272,7 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_inappwebview.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/integration_test.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/pdf_viewer_plugin.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/url_launcher.framework", ); runOnlyForDeploymentPostprocessing = 0; diff --git a/example/lib/in_app_webiew_example.screen.dart b/example/lib/in_app_webiew_example.screen.dart index 4f231d14..6375e057 100755 --- a/example/lib/in_app_webiew_example.screen.dart +++ b/example/lib/in_app_webiew_example.screen.dart @@ -138,6 +138,7 @@ class _InAppWebViewExampleScreenState extends State { setState(() { this.url = url ?? ''; }); + // RenderObject renderBox = webViewKey.currentContext!.findRenderObject()!; // print(renderBox.paintBounds.size); }, diff --git a/ios/Classes/InAppWebView.swift b/ios/Classes/InAppWebView.swift index a8c7c861..44289415 100755 --- a/ios/Classes/InAppWebView.swift +++ b/ios/Classes/InAppWebView.swift @@ -1742,6 +1742,30 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi } } + public func createPdf (configuration: [String: Any?]?, completionHandler: @escaping (_ pdf: Data?) -> Void) { + if #available(iOS 14.0, *) { + let pdfConfiguration: WKPDFConfiguration = .init() + if let configuration = configuration { + if let rect = configuration["rect"] as? [String: Double] { + pdfConfiguration.rect = CGRect(x: rect["x"]!, y: rect["y"]!, width: rect["width"]!, height: rect["height"]!) + } + } + createPDF(configuration: pdfConfiguration) { (result) in + switch (result) { + case .success(let data): + completionHandler(data) + return + case .failure(let error): + print(error.localizedDescription) + completionHandler(nil) + return + } + } + } else { + completionHandler(nil) + } + } + public func loadUrl(url: URL, headers: [String: String]?) { var request = URLRequest(url: url) currentURL = url diff --git a/ios/Classes/InAppWebViewMethodHandler.swift b/ios/Classes/InAppWebViewMethodHandler.swift index 2a02ee42..eebb3c52 100644 --- a/ios/Classes/InAppWebViewMethodHandler.swift +++ b/ios/Classes/InAppWebViewMethodHandler.swift @@ -402,6 +402,17 @@ class InAppWebViewMethodHandler: FlutterMethodCallDelegate { result(nil) } break + case "createPdf": + if webView != nil { + let configuration = arguments!["iosWKPdfConfiguration"] as? [String: Any?] + webView!.createPdf(configuration: configuration, completionHandler: { (pdf) -> Void in + result(pdf) + }) + } + else { + result(nil) + } + break default: result(FlutterMethodNotImplemented) break diff --git a/lib/src/in_app_webview_controller.dart b/lib/src/in_app_webview_controller.dart index 54852eb4..edf163c9 100644 --- a/lib/src/in_app_webview_controller.dart +++ b/lib/src/in_app_webview_controller.dart @@ -2336,6 +2336,15 @@ class IOSInAppWebViewController { .invokeMethod('hasOnlySecureContent', args); } + ///Generates PDF data from the web view’s contents asynchronously. + /// + ///[iosWKPdfConfiguration] represents the object that specifies the portion of the web view to capture as PDF data. + Future createPdf({IOSWKPDFConfiguration? iosWKPdfConfiguration}) async { + Map args = {}; + args.putIfAbsent('iosWKPdfConfiguration', () => iosWKPdfConfiguration?.toMap()); + return await _controller._channel.invokeMethod('createPdf', args); + } + ///Returns a Boolean value that indicates whether WebKit natively supports resources with the specified URL scheme. /// ///[urlScheme] represents the URL scheme associated with the resource. diff --git a/lib/src/types.dart b/lib/src/types.dart index 76e407e2..60b76289 100755 --- a/lib/src/types.dart +++ b/lib/src/types.dart @@ -4841,6 +4841,34 @@ class ScreenshotConfiguration { return this.toMap(); } + @override + String toString() { + return toMap().toString(); + } +} + +///An iOS-specific class that represents the configuration data to use when generating a PDF representation of a web view’s contents. +/// +///**NOTE**: available on iOS 14.0+. +class IOSWKPDFConfiguration { + ///The portion of your web view to capture, specified as a rectangle in the view’s coordinate system. + ///The default value of this property is `null`, which captures everything in the view’s bounds rectangle. + ///If you specify a custom rectangle, it must lie within the bounds rectangle of the [WebView] object. + InAppWebViewRect? rect; + + IOSWKPDFConfiguration({ + this.rect}); + + Map toMap() { + return { + "rect": rect?.toMap() + }; + } + + Map toJson() { + return this.toMap(); + } + @override String toString() { return toMap().toString();