WKWebView can't connect to external content in iOS 17.5+

My app Frax has long used a mechanism where a local webpage calls out to web-hosted content. In iOS 17.5+ (and iOS 18 beta) this has recently stopped working. The content fails to load, and the console log (running on iOS 17.6.1) contains:

nw_application_id_create_self NECP_CLIENT_ACTION_GET_SIGNED_CLIENT_ID [80: Authentication error]
Failed to resolve host network app id

followed shortly by:

Error acquiring assertion: <Error Domain=RBSServiceErrorDomain Code=1 "((target is not running or doesn't have entitlement com.apple.developer.web-browser-engine.rendering AND target is not running or doesn't have entitlement com.apple.developer.web-browser-engine.networking AND target is not running or doesn't have entitlement com.apple.developer.web-browser-engine.webcontent))" UserInfo={NSLocalizedFailureReason=((target is not running or doesn't have entitlement com.apple.developer.web-browser-engine.rendering AND target is not running or doesn't have entitlement com.apple.developer.web-browser-engine.networking AND target is not running or doesn't have entitlement com.apple.developer.web-browser-engine.webcontent))}>
0x128024480 - ProcessAssertion::acquireSync Failed to acquire RBS assertion 'XPCConnectionTerminationWatchdog' for process with PID=9736, error: (null)

This same code has worked reliably for years, and continues to work properly under iOS 16 and earlier. But there are increasing reports of this new error showing up around the web. Nothing in recent iOS 17 release notes sheds any light on what might have changed, and all my efforts to troubleshoot or mitigate this issue have failed. Any help on how to solve or work around this would be greatly appreciated!

Answered by iter9_dev in 812340022

Finally solved: it turned out I just needed to set the 'customUserAgent' property of the WKWebView. It's not clear why this wasn't required in iOS versions prior to iOS 17.5, but in any case the behavior seems to be working correctly again with this fix!

Here's a link to a sample project demonstrating the issue. (You may need to create a certificate/profile with the required entitlements.) Just build and run on an older device (pre iOS 17.5) to see the expected behavior, or on a newer device (iOS 17.5+) to see the problematic behavior and console messages.

Our engineering teams need to investigate this issue, as resolution may involve changes to Apple's software. I'd greatly appreciate it if you could open a bug report, include sample project and log info, and post the FB number here once you do. Bug Reporting: How and Why? has tips on creating your bug report.

You can always load content with WKURLSchemeHandler.

First you set the WKURLSchemeHandler:


enum LocalObjectType: String {
    case html = "html"
    case css = "css"
    case javascript = "javascript"
    case png = "png"
    case https = "https"
    case pdf = "pdf"
}

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        let config = WKWebViewConfiguration()
        config.setURLSchemeHandler(LocalLoaderCustomSchemeHandler(), forURLScheme: scheme)
        let webView = WKWebView(frame: view.frame, configuration: config)
        webView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        view.addSubview(webView)
        webView.load(URLRequest(url: URL(string: scheme + ":\(LocalObjectType.html)" )!))
    }

}

Then handle the types as they come:

    
    func webView(_ webView: WKWebView, start urlSchemeTask: WKURLSchemeTask) {
        guard let url = urlSchemeTask.request.url else {
            return
        }
        let type = url.lastPathComponent 
        var response: URLResponse?
        var data: Data?
        if type == LocalObjectType.html.rawValue { ...} else if type == LocalObjectType.png.rawValue {
            if let resource = Bundle.main.url(forResource: "image", withExtension: "png"),
               let resourceData = try? Data(contentsOf: resource) {
                data = resourceData
                response = URLResponse(
                    url: url,
                    mimeType: "image/png",
                    expectedContentLength: data!.count,
                    textEncodingName: nil)
            }
        } else if type == LocalObjectType.https.rawValue {
            if let resource = URL(string: "https://pngimg.com/uploads/frisbee/frisbee_PNG21.png"),
               let resourceData = try? Data(contentsOf: resource) {
                data = resourceData
                response = URLResponse(
                    url: url,
                    mimeType: "image/png",
                    expectedContentLength: data!.count,
                    textEncodingName: nil)
            }
        } else if type == LocalObjectType.pdf.rawValue {
            if let resource = Bundle.main.url(forResource: "image", withExtension: "pdf"),
               let resourceData = try? Data(contentsOf: resource) {
                data = resourceData
                response = URLResponse(
                    url: url,
                    mimeType: "application/pdf",
                    expectedContentLength: data!.count,
                    textEncodingName: nil)
            }
        }
        if let response = response, let data = data {
            urlSchemeTask.didReceive(response)
            urlSchemeTask.didReceive(data)
            urlSchemeTask.didFinish()
        }

Rico

WWDR - DTS - Software Engineer

@iter9_dev did you get any resolution to this issue?

The separate ticket you created isn't visible to the rest of us (https://feedbackassistant.apple.com/feedback/14966935).

A lot of devs seem to be struggling with this issue.

Accepted Answer

Finally solved: it turned out I just needed to set the 'customUserAgent' property of the WKWebView. It's not clear why this wasn't required in iOS versions prior to iOS 17.5, but in any case the behavior seems to be working correctly again with this fix!

@iter9_dev What did you set customUserAgent to be?

WKWebView can't connect to external content in iOS 17.5+
 
 
Q