Skip to content
This repository has been archived by the owner on Oct 10, 2024. It is now read-only.

Pass pre-built WKWebView instance to makeCustomWebView #41

Merged
merged 1 commit into from
Sep 1, 2023

Conversation

seanpdoyle
Copy link
Contributor

Instead of forcing applications to make an all-or-nothing decision on whether or not they use the pre-built WKWebView provided by the package or roll their own, this commit introduces a mechanism for applications to either configure the pre-built instance or built a fresh instance of their own.

@joemasilotti
Copy link
Owner

Thanks for this, Sean! I like the idea of providing a pre-configured web view to customize. I must be missing something… I don't think it's possible to change the configuration this way.

webView.configuration is a read-only property, so we can't set it with a customized instance. And setting, for example, webView.configuration.applicationNameForUserAgent = "FOO-BAR" doesn't actually apply when the web view renders.

Can you provide a code snippet on how you can customize the configuration using this PR?


// MARK: - Internal

func makeWebView() -> WKWebView {
makeCustomWebView?() ?? WKWebView(frame: .zero, configuration: makeWebViewConfiguration())
makeCustomWebView(WKWebView(frame: .zero, configuration: makeWebViewConfiguration()))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In our application's case, it felt like we'd get the most value out of re-using the configuration instance built by the makeWebViewConfiguration() call (since it as the User Agent already set, shares a Process Pool, etc).

Maybe it'd be better if the closure were changed to provide the configuration instead:

public typealias WebViewBlock = (_ configuration: WKWebViewConfiguration) -> WKWebView

public var makeCustomWebView: WebViewBlock = { configuration in
      return WKWebView(frame: .zero, configuration: configuration)
}

func makeWebView() -> WKWebView {
      makeCustomWebView(makeWebViewConfiguration()))
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've also opened #42. That could either work hand-in-hand with this change as a complement, or be an alternative.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think passing the configuration and requiring the developer to build the web view is the way to go. That provides the most flexibility and default configuration (user agent and process pool).

Rereading the WKWebViewConfiguration docs again, it looks like you must assign it when the web view is instantiated for anything to apply.

You create a WKWebViewConfiguration object in your code, configure its properties, and pass it to the initializer of your WKWebView object. The web view incorporates your configuration settings only at creation time; you cannot change those settings dynamically later.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks you for that feedback and guidance!

The web view incorporates your configuration settings only at creation time; you cannot change those settings dynamically later.

In my experience, that isn't true for variables that are accessible through the configuration itself, like the userContentController that the turbo-ios package utilizes to inject its script:

    init(webView: WKWebView) {
        self.webView = webView
        setup()
    }
    
    private func setup() {
        webView.configuration.userContentController.addUserScript(userScript)
        webView.configuration.userContentController.add(ScriptMessageHandler(delegate: self), name: messageHandlerName)
    }

Those assignments occur after the WebView has been constructed.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's correct. The objects that the configuration holds on to can be assigned at will. But the properties of the configuration cannot.

You can test this by trying to override applicationNameForUserAgent.

let configuration = WKWebViewConfiguration()
configuration.applicationNameForUserAgent = "BEFORE"

let webView = WKWebView(frame: .zero, configuration: configuration)
webView.configuration.applicationNameForUserAgent = "AFTER"

print(webView.configuration.applicationNameForUserAgent) // Optional("BEFORE")

README.md Outdated Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
Sources/TurboConfig.swift Outdated Show resolved Hide resolved
Instead of forcing applications to make an all-or-nothing decision on
whether or not they use the pre-built `WKWebView` provided by the
package or roll their own, this commit introduces a mechanism for
applications to _either_ change the pre-built configuration, or build a
fresh instance of their own.

For example, an application might want to configure the WebView without
needing to generate the process pool or re-implement the User Agent
generation:

```swift
TurboConfig.shared.makeCustomWebView = { (configuration: WKWebViewConfiguration) in
    configuration.preferences.javaScriptCanOpenWindowsAutomatically = true

    let webView = WKWebView(frame: .zero, configuration: configuration)

    if #available(iOS 16.4, *) {
        webView.isInspectable = true
    }

    return webView
}
```
@joemasilotti
Copy link
Owner

Looks great, thanks @seanpdoyle! Will merge when CI passes.

@joemasilotti joemasilotti merged commit 4cc8765 into joemasilotti:main Sep 1, 2023
@seanpdoyle seanpdoyle deleted the customize-web-view branch September 1, 2023 11:00
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants