Revision control
Copy as Markdown
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
import Foundation
import WebKit
public struct WKWebViewParameters {
/// A boolean value customizable with a user preference indicating whether JavaScript can
/// open windows without user interaction.
var blockPopups: Bool
/// A boolean value indicating if we have a persitent webview data store.
var isPrivate: Bool
/// The type of pull refresh that is going to be instantiated and displayed by the webview.
var pullRefreshType: EnginePullRefreshViewType
/// A value indicating the user preference for audio visual media types
var autoPlay: WKAudiovisualMediaTypes
/// FXIOS-11986 - Allow Client to pass down it's own scheme handler for now, this will be internal later on
var schemeHandler: SchemeHandler
public init(blockPopups: Bool,
isPrivate: Bool,
autoPlay: WKAudiovisualMediaTypes,
schemeHandler: SchemeHandler,
pullRefreshType: EnginePullRefreshViewType = UIRefreshControl.self) {
self.blockPopups = blockPopups
self.isPrivate = isPrivate
self.autoPlay = autoPlay
self.schemeHandler = schemeHandler
self.pullRefreshType = pullRefreshType
}
/// Default internal Webview parameters initializer for WebEngine reader mode purpose
init() {
self.blockPopups = false
self.isPrivate = false
self.autoPlay = .all
self.schemeHandler = WKInternalSchemeHandler()
self.pullRefreshType = UIRefreshControl.self
}
}
/// Provider to get a configured `WKEngineConfiguration`
/// Only one configuration provider per application should exists.
@MainActor
public protocol WKEngineConfigurationProvider {
func createConfiguration(parameters: WKWebViewParameters) -> WKEngineConfiguration
}
/// FXIOS-11986 - This will be internal when the WebEngine is fully integrated in Firefox iOS
public struct DefaultWKEngineConfigurationProvider: WKEngineConfigurationProvider {
private static let normalSessionsProcessPool = WKProcessPool()
private static let privateSessionsProcessPool = WKProcessPool()
private static let nonPersistentStore = WKWebsiteDataStore.nonPersistent()
private static let defaultStore = WKWebsiteDataStore.default()
private static let defaultDataDetectorTypes: WKDataDetectorTypes = [.phoneNumber]
private let configuration: WKWebViewConfiguration
public init(configuration: WKWebViewConfiguration = WKWebViewConfiguration()) {
self.configuration = configuration
}
public func createConfiguration(parameters: WKWebViewParameters) -> WKEngineConfiguration {
// Since our app creates multiple web views, we assign the same WKProcessPool object to web views that
// may safely share a process space
configuration.processPool = parameters.isPrivate
? DefaultWKEngineConfigurationProvider.privateSessionsProcessPool
: DefaultWKEngineConfigurationProvider.normalSessionsProcessPool
configuration.preferences.javaScriptCanOpenWindowsAutomatically = !parameters.blockPopups
configuration.mediaTypesRequiringUserActionForPlayback = parameters.autoPlay
configuration.userContentController = WKUserContentController()
configuration.allowsInlineMediaPlayback = true
configuration.dataDetectorTypes = DefaultWKEngineConfigurationProvider.defaultDataDetectorTypes
// TODO: FXIOS-8086 - Evaluate if ignoresViewportScaleLimits is still needed
// We do this to go against the configuration of the <meta name="viewport">
// tag to behave the same way as Safari :-(
configuration.ignoresViewportScaleLimits = true
if #available(iOS 15.4, *) {
configuration.preferences.isElementFullscreenEnabled = true
}
// The cookie store should only be created once, otherwise we can loose them
configuration.websiteDataStore = parameters.isPrivate
? DefaultWKEngineConfigurationProvider.nonPersistentStore
: DefaultWKEngineConfigurationProvider.defaultStore
// Popup WKWebViewConfiguration can have the scheme already registered thus registering again
// leads to crash
if configuration.urlSchemeHandler(forURLScheme: parameters.schemeHandler.scheme) == nil {
configuration.setURLSchemeHandler(parameters.schemeHandler,
forURLScheme: parameters.schemeHandler.scheme)
}
return DefaultEngineConfiguration(webViewConfiguration: configuration)
}
}