added createWebArchiveData iOS-specific WebView method, Moved saveWebArchive WebView method from Android-specific to cross-platform

This commit is contained in:
Lorenzo Pichilli 2021-02-09 01:39:35 +01:00
parent b15ae759d5
commit 88bfe9036f
12 changed files with 220 additions and 79 deletions

View File

@ -10,7 +10,7 @@
- Added `addUserScript`, `addUserScripts`, `removeUserScript`, `removeUserScripts`, `removeAllUserScripts`, `callAsyncJavaScript` WebView methods - Added `addUserScript`, `addUserScripts`, `removeUserScript`, `removeUserScripts`, `removeAllUserScripts`, `callAsyncJavaScript` WebView methods
- Added `contentWorld` argument to `evaluateJavascript` WebView method - Added `contentWorld` argument to `evaluateJavascript` WebView method
- Added `isDirectionalLockEnabled`, `mediaType`, `pageZoom`, `limitsNavigationsToAppBoundDomains` iOS-specific WebView options - Added `isDirectionalLockEnabled`, `mediaType`, `pageZoom`, `limitsNavigationsToAppBoundDomains` iOS-specific WebView options
- Added `handlesURLScheme`, `createPdf` iOS-specific WebView methods - Added `handlesURLScheme`, `createPdf`, `createWebArchiveData` iOS-specific WebView methods
- Added `iosAnimated` optional argument to `zoomBy` WebView method - Added `iosAnimated` optional argument to `zoomBy` WebView method
- Added `screenshotConfiguration` optional argument to `takeScreenshot` WebView method - Added `screenshotConfiguration` optional argument to `takeScreenshot` WebView method
- Updated integration tests - Updated integration tests
@ -44,6 +44,7 @@
- `allowUniversalAccessFromFileURLs` and `allowFileAccessFromFileURLs` WebView options moved from Android-specific options to cross-platform options - `allowUniversalAccessFromFileURLs` and `allowFileAccessFromFileURLs` WebView options moved from Android-specific options to cross-platform options
- Added `callAsyncJavaScript` name to the list of javaScriptHandlerForbiddenNames - Added `callAsyncJavaScript` name to the list of javaScriptHandlerForbiddenNames
- Changed `zoomBy` WebView method signature - Changed `zoomBy` WebView method signature
- Moved `saveWebArchive` WebView method from Android-specific to cross-platform
## 4.0.0+4 ## 4.0.0+4

View File

@ -494,6 +494,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. 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 views contents asynchronously. * `createPdf({IOSWKPDFConfiguration? iosWKPdfConfiguration})`: Generates PDF data from the web views contents asynchronously.
* `createWebArchiveData`: Creates a web archive of the web views current contents asynchronously.
* `hasOnlySecureContent`: A Boolean value indicating whether all resources on the page have been loaded over securely encrypted connections. * `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. * `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. * `static handlesURLScheme(String urlScheme)`: Returns a Boolean value that indicates whether WebKit natively supports resources with the specified URL scheme.

View File

@ -338,9 +338,9 @@ public class InAppWebViewMethodHandler implements MethodChannel.MethodCallHandle
break; break;
case "saveWebArchive": case "saveWebArchive":
if (webView != null) { if (webView != null) {
String basename = (String) call.argument("basename"); String filePath = (String) call.argument("filePath");
boolean autoname = (boolean) call.argument("autoname"); boolean autoname = (boolean) call.argument("autoname");
webView.saveWebArchive(basename, autoname, new ValueCallback<String>() { webView.saveWebArchive(filePath, autoname, new ValueCallback<String>() {
@Override @Override
public void onReceiveValue(String value) { public void onReceiveValue(String value) {
result.success(value); result.success(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/.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"} {"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-09 01:23:18.308862","version":"1.26.0-18.0.pre.90"}

View File

@ -262,7 +262,6 @@
"${BUILT_PRODUCTS_DIR}/flutter_inappwebview/flutter_inappwebview.framework", "${BUILT_PRODUCTS_DIR}/flutter_inappwebview/flutter_inappwebview.framework",
"${BUILT_PRODUCTS_DIR}/integration_test/integration_test.framework", "${BUILT_PRODUCTS_DIR}/integration_test/integration_test.framework",
"${BUILT_PRODUCTS_DIR}/path_provider/path_provider.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", "${BUILT_PRODUCTS_DIR}/url_launcher/url_launcher.framework",
); );
name = "[CP] Embed Pods Frameworks"; name = "[CP] Embed Pods Frameworks";
@ -272,7 +271,6 @@
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_inappwebview.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_inappwebview.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/integration_test.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}/path_provider.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/pdf_viewer_plugin.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/url_launcher.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/url_launcher.framework",
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;

View File

@ -2,8 +2,10 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>NSDocumentsFolderUsageDescription</key>
<string>InAppWebView requires access to documents folder</string>
<key>NSMicrophoneUsageDescription</key> <key>NSMicrophoneUsageDescription</key>
<string>InAppWebView requires acess to mic.</string> <string>InAppWebView requires access to mic.</string>
<key>CFBundleDevelopmentRegion</key> <key>CFBundleDevelopmentRegion</key>
<string>en</string> <string>en</string>
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
@ -64,7 +66,7 @@
<key>UIViewControllerBasedStatusBarAppearance</key> <key>UIViewControllerBasedStatusBarAppearance</key>
<false/> <false/>
<key>NSCameraUsageDescription</key> <key>NSCameraUsageDescription</key>
<string>InAppWebView requires acess to cam.</string> <string>InAppWebView requires access to cam.</string>
<key>NSLocalNetworkUsageDescription</key> <key>NSLocalNetworkUsageDescription</key>
<string>Allow Flutter tools on your computer to connect and debug your application.</string> <string>Allow Flutter tools on your computer to connect and debug your application.</string>
</dict> </dict>

View File

@ -3,6 +3,7 @@ import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart';
// import 'package:path_provider/path_provider.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import 'main.dart'; import 'main.dart';

View File

@ -18,6 +18,7 @@ Future main() async {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
// await Permission.camera.request(); // await Permission.camera.request();
// await Permission.microphone.request(); // await Permission.microphone.request();
// await Permission.storage.request();
if (Platform.isAndroid) { if (Platform.isAndroid) {
await AndroidInAppWebViewController.setWebContentsDebuggingEnabled(true); await AndroidInAppWebViewController.setWebContentsDebuggingEnabled(true);

View File

@ -1700,70 +1700,117 @@ public class InAppWebView: WKWebView, UIScrollViewDelegate, WKUIDelegate, WKNavi
: currentIndex + steps >= 0 : currentIndex + steps >= 0
} }
@available(iOS 11.0, *)
public func takeScreenshot (with: [String: Any?]?, completionHandler: @escaping (_ screenshot: Data?) -> Void) { public func takeScreenshot (with: [String: Any?]?, completionHandler: @escaping (_ screenshot: Data?) -> Void) {
if #available(iOS 11.0, *) { var snapshotConfiguration: WKSnapshotConfiguration? = nil
var snapshotConfiguration: WKSnapshotConfiguration? = nil if let with = with {
if let with = with { snapshotConfiguration = WKSnapshotConfiguration()
snapshotConfiguration = WKSnapshotConfiguration() if let rect = with["rect"] as? [String: Double] {
if let rect = with["rect"] as? [String: Double] { snapshotConfiguration!.rect = CGRect(x: rect["x"]!, y: rect["y"]!, width: rect["width"]!, height: rect["height"]!)
snapshotConfiguration!.rect = CGRect(x: rect["x"]!, y: rect["y"]!, width: rect["width"]!, height: rect["height"]!)
}
if let snapshotWidth = with["snapshotWidth"] as? Double {
snapshotConfiguration!.snapshotWidth = NSNumber(value: snapshotWidth)
}
if #available(iOS 13.0, *), let afterScreenUpdates = with["iosAfterScreenUpdates"] as? Bool {
snapshotConfiguration!.afterScreenUpdates = afterScreenUpdates
}
} }
takeSnapshot(with: snapshotConfiguration, completionHandler: {(image, error) -> Void in if let snapshotWidth = with["snapshotWidth"] as? Double {
var imageData: Data? = nil snapshotConfiguration!.snapshotWidth = NSNumber(value: snapshotWidth)
if let screenshot = image { }
if let with = with { if #available(iOS 13.0, *), let afterScreenUpdates = with["iosAfterScreenUpdates"] as? Bool {
switch with["compressFormat"] as! String { snapshotConfiguration!.afterScreenUpdates = afterScreenUpdates
case "JPEG": }
let quality = Float(with["quality"] as! Int) / 100 }
imageData = screenshot.jpegData(compressionQuality: CGFloat(quality))! takeSnapshot(with: snapshotConfiguration, completionHandler: {(image, error) -> Void in
break var imageData: Data? = nil
case "PNG": if let screenshot = image {
imageData = screenshot.pngData()! if let with = with {
break switch with["compressFormat"] as! String {
default: case "JPEG":
imageData = screenshot.pngData()! let quality = Float(with["quality"] as! Int) / 100
} imageData = screenshot.jpegData(compressionQuality: CGFloat(quality))!
} break
else { case "PNG":
imageData = screenshot.pngData()!
break
default:
imageData = screenshot.pngData()! imageData = screenshot.pngData()!
} }
} }
completionHandler(imageData) else {
}) imageData = screenshot.pngData()!
} else { }
completionHandler(nil) }
completionHandler(imageData)
})
}
@available(iOS 14.0, *)
public func createPdf (configuration: [String: Any?]?, completionHandler: @escaping (_ pdf: Data?) -> Void) {
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
}
} }
} }
public func createPdf (configuration: [String: Any?]?, completionHandler: @escaping (_ pdf: Data?) -> Void) { @available(iOS 14.0, *)
if #available(iOS 14.0, *) { public func createWebArchiveData (dataCompletionHandler: @escaping (_ webArchiveData: Data?) -> Void) {
let pdfConfiguration: WKPDFConfiguration = .init() createWebArchiveData(completionHandler: { (result) in
if let configuration = configuration { switch (result) {
if let rect = configuration["rect"] as? [String: Double] { case .success(let data):
pdfConfiguration.rect = CGRect(x: rect["x"]!, y: rect["y"]!, width: rect["width"]!, height: rect["height"]!) dataCompletionHandler(data)
} return
case .failure(let error):
print(error.localizedDescription)
dataCompletionHandler(nil)
return
} }
createPDF(configuration: pdfConfiguration) { (result) in })
switch (result) { }
case .success(let data):
completionHandler(data) @available(iOS 14.0, *)
return public func saveWebArchive (filePath: String, autoname: Bool, completionHandler: @escaping (_ path: String?) -> Void) {
case .failure(let error): createWebArchiveData(dataCompletionHandler: { (webArchiveData) in
if let webArchiveData = webArchiveData {
var localUrl = URL(fileURLWithPath: filePath)
if autoname {
if let url = self.url {
// tries to mimic Android saveWebArchive method
let invalidCharacters = CharacterSet(charactersIn: "\\/:*?\"<>|")
.union(.newlines)
.union(.illegalCharacters)
.union(.controlCharacters)
let currentPageUrlFileName = url.path
.components(separatedBy: invalidCharacters)
.joined(separator: "")
let fullPath = filePath + "/" + currentPageUrlFileName + ".webarchive"
localUrl = URL(fileURLWithPath: fullPath)
} else {
completionHandler(nil)
return
}
}
do {
try webArchiveData.write(to: localUrl)
completionHandler(localUrl.path)
} catch {
// Catch any errors
print(error.localizedDescription) print(error.localizedDescription)
completionHandler(nil) completionHandler(nil)
return
} }
} else {
completionHandler(nil)
} }
} else { })
completionHandler(nil)
}
} }
public func loadUrl(url: URL, headers: [String: String]?) { public func loadUrl(url: URL, headers: [String: String]?) {

View File

@ -128,7 +128,7 @@ class InAppWebViewMethodHandler: FlutterMethodCallDelegate {
result(webView?.isLoading ?? false) result(webView?.isLoading ?? false)
break break
case "takeScreenshot": case "takeScreenshot":
if webView != nil { if webView != nil, #available(iOS 11.0, *) {
let screenshotConfiguration = arguments!["screenshotConfiguration"] as? [String: Any?] let screenshotConfiguration = arguments!["screenshotConfiguration"] as? [String: Any?]
webView!.takeScreenshot(with: screenshotConfiguration, completionHandler: { (screenshot) -> Void in webView!.takeScreenshot(with: screenshotConfiguration, completionHandler: { (screenshot) -> Void in
result(screenshot) result(screenshot)
@ -403,7 +403,7 @@ class InAppWebViewMethodHandler: FlutterMethodCallDelegate {
} }
break break
case "createPdf": case "createPdf":
if webView != nil { if webView != nil, #available(iOS 14.0, *) {
let configuration = arguments!["iosWKPdfConfiguration"] as? [String: Any?] let configuration = arguments!["iosWKPdfConfiguration"] as? [String: Any?]
webView!.createPdf(configuration: configuration, completionHandler: { (pdf) -> Void in webView!.createPdf(configuration: configuration, completionHandler: { (pdf) -> Void in
result(pdf) result(pdf)
@ -413,6 +413,28 @@ class InAppWebViewMethodHandler: FlutterMethodCallDelegate {
result(nil) result(nil)
} }
break break
case "createWebArchiveData":
if webView != nil, #available(iOS 14.0, *) {
webView!.createWebArchiveData(dataCompletionHandler: { (webArchiveData) -> Void in
result(webArchiveData)
})
}
else {
result(nil)
}
break
case "saveWebArchive":
if webView != nil, #available(iOS 14.0, *) {
let filePath = arguments!["filePath"] as! String
let autoname = arguments!["autoname"] as! Bool
webView!.saveWebArchive(filePath: filePath, autoname: autoname, completionHandler: { (path) -> Void in
result(path)
})
}
else {
result(nil)
}
break
default: default:
result(FlutterMethodNotImplemented) result(FlutterMethodNotImplemented)
break break

View File

@ -1508,7 +1508,7 @@ class InAppWebViewController {
/// ///
///[screenshotConfiguration] represents the configuration data to use when generating an image from a web views contents. ///[screenshotConfiguration] represents the configuration data to use when generating an image from a web views contents.
/// ///
///**NOTE for iOS**: available from iOS 11.0+. ///**NOTE for iOS**: available on iOS 11.0+.
/// ///
///**Official iOS API**: https://developer.apple.com/documentation/webkit/wkwebview/2873260-takesnapshot ///**Official iOS API**: https://developer.apple.com/documentation/webkit/wkwebview/2873260-takesnapshot
Future<Uint8List?> takeScreenshot({ScreenshotConfiguration? screenshotConfiguration}) async { Future<Uint8List?> takeScreenshot({ScreenshotConfiguration? screenshotConfiguration}) async {
@ -2088,6 +2088,35 @@ class InAppWebViewController {
return CallAsyncJavaScriptResult(value: data["value"], error: data["error"]); return CallAsyncJavaScriptResult(value: data["value"], error: data["error"]);
} }
///Saves the current WebView as a web archive.
///Returns the file path under which the web archive file was saved, or `null` if saving the file failed.
///
///[filePath] represents the file path where the archive should be placed. This value cannot be `null`.
///
///[autoname] if `false`, takes [filePath] to be a file.
///If `true`, [filePath] is assumed to be a directory in which a filename will be chosen according to the URL of the current page.
///
///**NOTE for iOS**: Available on iOS 14.0+. If [autoname] is `false`, the [filePath] must ends with the [WebArchiveFormat.WEBARCHIVE] file extension.
///
///**NOTE for Android**: if [autoname] is `false`, the [filePath] must ends with the [WebArchiveFormat.MHT] file extension.
///
///**Official Android API**: https://developer.android.com/reference/android/webkit/WebView#saveWebArchive(java.lang.String,%20boolean,%20android.webkit.ValueCallback%3Cjava.lang.String%3E)
Future<String?> saveWebArchive(
{required String filePath, bool autoname = false}) async {
if (!autoname) {
if (Platform.isAndroid) {
assert(filePath.endsWith("." + WebArchiveFormat.MHT.toValue()));
} else if (Platform.isIOS) {
assert(filePath.endsWith("." + WebArchiveFormat.WEBARCHIVE.toValue()));
}
}
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent("filePath", () => filePath);
args.putIfAbsent("autoname", () => autoname);
return await _channel.invokeMethod('saveWebArchive', args);
}
///Gets the default user agent. ///Gets the default user agent.
/// ///
///**Official Android API**: https://developer.android.com/reference/android/webkit/WebSettings#getDefaultUserAgent(android.content.Context) ///**Official Android API**: https://developer.android.com/reference/android/webkit/WebSettings#getDefaultUserAgent(android.content.Context)
@ -2180,23 +2209,6 @@ class AndroidInAppWebViewController {
return await _controller._channel.invokeMethod('pageUp', args); return await _controller._channel.invokeMethod('pageUp', args);
} }
///Saves the current WebView as a web archive.
///Returns the filename under which the file was saved, or `null` if saving the file failed.
///
///[basename] the filename where the archive should be placed. This value cannot be `null`.
///
///[autoname] if `false`, takes basename to be a file.
///If `true`, [basename] is assumed to be a directory in which a filename will be chosen according to the URL of the current page.
///
///**Official Android API**: https://developer.android.com/reference/android/webkit/WebView#saveWebArchive(java.lang.String,%20boolean,%20android.webkit.ValueCallback%3Cjava.lang.String%3E)
Future<String?> saveWebArchive(
{required String basename, required bool autoname}) async {
Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent("basename", () => basename);
args.putIfAbsent("autoname", () => autoname);
return await _controller._channel.invokeMethod('saveWebArchive', args);
}
///Performs zoom in in this WebView. ///Performs zoom in in this WebView.
///Returns `true` if zoom in succeeds, `false` if no zoom changes. ///Returns `true` if zoom in succeeds, `false` if no zoom changes.
/// ///
@ -2337,14 +2349,30 @@ class IOSInAppWebViewController {
} }
///Generates PDF data from the web views contents asynchronously. ///Generates PDF data from the web views contents asynchronously.
///Returns `null` if a problem occurred.
/// ///
///[iosWKPdfConfiguration] represents the object that specifies the portion of the web view to capture as PDF data. ///[iosWKPdfConfiguration] represents the object that specifies the portion of the web view to capture as PDF data.
///
///**NOTE**: available only on iOS 14.0+.
///
///**Official iOS API**: https://developer.apple.com/documentation/webkit/wkwebview/3650490-createpdf
Future<Uint8List?> createPdf({IOSWKPDFConfiguration? iosWKPdfConfiguration}) async { Future<Uint8List?> createPdf({IOSWKPDFConfiguration? iosWKPdfConfiguration}) async {
Map<String, dynamic> args = <String, dynamic>{}; Map<String, dynamic> args = <String, dynamic>{};
args.putIfAbsent('iosWKPdfConfiguration', () => iosWKPdfConfiguration?.toMap()); args.putIfAbsent('iosWKPdfConfiguration', () => iosWKPdfConfiguration?.toMap());
return await _controller._channel.invokeMethod('createPdf', args); return await _controller._channel.invokeMethod('createPdf', args);
} }
///Creates a web archive of the web views current contents asynchronously.
///Returns `null` if a problem occurred.
///
///**NOTE**: available only on iOS 14.0+.
///
///**Official iOS API**: https://developer.apple.com/documentation/webkit/wkwebview/3650491-createwebarchivedata
Future<Uint8List?> createWebArchiveData() async {
Map<String, dynamic> args = <String, dynamic>{};
return await _controller._channel.invokeMethod('createWebArchiveData', args);
}
///Returns a Boolean value that indicates whether WebKit natively supports resources with the specified URL scheme. ///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. ///[urlScheme] represents the URL scheme associated with the resource.

View File

@ -4874,3 +4874,43 @@ class IOSWKPDFConfiguration {
return toMap().toString(); return toMap().toString();
} }
} }
///Class that represents the known Web Archive formats used when saving a web page.
class WebArchiveFormat {
final String _value;
const WebArchiveFormat._internal(this._value);
static final Set<WebArchiveFormat> values = [
WebArchiveFormat.MHT,
WebArchiveFormat.WEBARCHIVE
].toSet();
static WebArchiveFormat? fromValue(String? value) {
if (value != null) {
try {
return WebArchiveFormat.values.firstWhere(
(element) => element.toValue() == value);
} catch (e) {
return null;
}
}
return null;
}
String toValue() => _value;
@override
String toString() => _value;
///Web Archive format used only by Android.
static const MHT = const WebArchiveFormat._internal("mht");
///Web Archive format used only by iOS.
static const WEBARCHIVE = const WebArchiveFormat._internal("webarchive");
bool operator ==(value) => value == _value;
@override
int get hashCode => _value.hashCode;
}