Safari Web Extension Handler doesn't respond to Message when neither Debugger nor Console is attached

I have a Safari Web Extension that communicates with its native App through UserDefaults within an App Group.

The WebExtensionHandler is also used to carry out other functions for the Web Extension on request.

I am currently troubleshooting a bug where a request from the Extension to the WebExtensionHandler remains unanswered.

The bug only occurs on physical devices, in the simulator, it always behaves as expected. When XCode is attached to the App or App Extension process, the bug also does not trigger. When the Console App is used to monitor events on the device, the bug also does not trigger.

Here is the code for the WebExtensionHandler:

import SafariServices

func respondWith(_ context: NSExtensionContext, string: String) {
    let response = NSExtensionItem()
    response.userInfo = [ SFExtensionMessageKey: string ]
    context.completeRequest(returningItems: [response], completionHandler: nil)
}

class SafariWebExtensionHandler: NSObject, NSExtensionRequestHandling {
    var sharedPrefs = UserDefaults.init(suiteName: "group.eu.waiyu.app")!

    func beginRequest(with context: NSExtensionContext) {
        let item = context.inputItems[0] as! NSExtensionItem
        let message = item.userInfo?[SFExtensionMessageKey] as! Dictionary<String,Any>

        switch message["type"] as! String {
        // other cases...

        case "get_config":
            if let config = sharedPrefs.string(forKey: "config") {
                respondWith(context, string: config)
            } else {
                let defaultConfig = message["defaultConfig"]!
                respondWith(context, string: defaultConfig as! String)
            }

        default:
            respondWith(context, string: "Unknown Message type")
        }
    }

}

Even though it appears that something goes wrong when accessing sharedPrefs when the bug is triggered, other requests are answered correctly (before and after triggering the bug).

As per some solutions to similar issues (https://stackoverflow.com/questions/38275395/failed-to-read-values-in-cfprefsplistsource-ios-10) I have tried different App Group IDs:

  • the main Bundle ID, prefixed with "group."
  • an ID different from both main bundle and extension bundle, prefixed with "group."
  • "group.TEAMID." prefix (TEAMID being the developer team id)

Is there anything I can try with regards to the code? Are there any other debugging workflows I can try that do not involve attaching to the device, that might allow me to capture more information about the bug?

Replies

So far this only appears to affect the "get_config" message. In the main bundle I use the same UserDefaults contructor and get this error:

Couldn't read values in CFPrefPlistSource<[...]> (Domain: [group id], User: kCFPreferencesAnyuser, ByHost: Yes, Container: (null), Contents Need Refresh: Yes): Using kCFPreferencesAnyUser with a container is only allowed for System Containers, detaching from cfprefsd

This is what led me to the Stackoverflow answer and the attempted fixes above. However this didn't solve the issue or remove this error message.

  • This message can be ignored. It's not an actual error See there

Add a Comment

I'm not sure if this will help you or not but I was having this issue and this post helped me out! https://developer.apple.com/forums/thread/13038

I was registering defaults (.register(defaults: ...) but it turns out those are only held in memory and aren't actually in persistent storage. So you just have to .set the defaults to get them to be stored persistently! My extension could read the values after that.

  • Thanks for the suggestion, but in my case I am really writing values to the store using .set(), and when it works, it does actually keep them.

Add a Comment