Hi Brian,
Safari App Extensions are automatically discovered, without launching the containing app, when downloaded through the App Store. Therefore, I must support a use case where the user installs my containing app from the App Store, goes to Safari's prefs without opening my containing app first, and turns my extension on. That means I have to have initialization logic in my app and my extension.
Your post says that there's one instance of the process per App Extension, but I can't independently verify this.
I'm debugging a Safari app extension in Xcode 11.4.1 (11E503a), Safari 13.1 (15609.1.20.111.8) and macOS Catalina 10.15.4 (19E287). When I choose to run my extension (not the containing app) and attach to Safari, Safari runs, then my extension's initializer is run several times in sub-millisecond succession, and runs in parallel (along with the beginRequest(with:) method). I tested the parallelization by running many NSLog statements in my init and verifying the printed order in the console.
If I tried to run initialization logic in this sort of environment, I'm afraid of the kinds of bugs that might appear!
In the course of writing this post, I created a blank Safari App Extension project and had the same thing happen. Simply adding this code to the SafariExtensionHandler, then attaching the app extension to Safari shows the problem:
var counter = 0
override init() {
super.init()
counter += 1
NSLog(String(counter))
}
deinit {
NSLog("Disappearing...")
}
objc[58615]: Class AMSupportURLConnectionDelegate is implemented in both /System/Library/PrivateFrameworks/OSPersonalization.framework/Versions/A/OSPersonalization (0x7fff92e61b68) and /System/Library/PrivateFrameworks/MobileDevice.framework/Versions/A/MobileDevice (0x1048fe228). One of the two will be used. Which one is undefined.
objc[58615]: Class AMSupportURLSession is implemented in both /System/Library/PrivateFrameworks/OSPersonalization.framework/Versions/A/OSPersonalization (0x7fff92e61bb8) and /System/Library/PrivateFrameworks/MobileDevice.framework/Versions/A/MobileDevice (0x1048fe278). One of the two will be used. Which one is undefined.
2020-05-15 19:25:31.213733-0700 Safari[58615:5517884] [Extensions] Unable to access keychain item for the list of installed extensions because it does not exist
2020-05-15 19:25:32.848653-0700 basicsafariextension Extension[58618:5517957] [subsystems ] Bootstrapping; external subsystem UIKit_PKSubsystem refused setup
2020-05-15 19:25:32.878416-0700 basicsafariextension Extension[58618:5517957] 1
2020-05-15 19:25:32.878689-0700 basicsafariextension Extension[58618:5517957] 1
2020-05-15 19:25:32.878864-0700 basicsafariextension Extension[58618:5517957] 1
2020-05-15 19:25:32.879073-0700 basicsafariextension Extension[58618:5517957] 1
2020-05-15 19:25:32.879233-0700 basicsafariextension Extension[58618:5517957] 1
2020-05-15 19:25:32.879501-0700 basicsafariextension Extension[58618:5517957] 1
2020-05-15 19:25:32.893023-0700 basicsafariextension Extension[58618:5517957] Disappearing...
2020-05-15 19:25:32.893492-0700 basicsafariextension Extension[58618:5517957] Disappearing...
(Yes, deinit is only run twice after Safari loads...)
Why is my init code being run so many times if there's only one instance of the process?
EDIT: I discovered that the first number after the name of the process is the PID, which clearly shows one copy of the process. But the multiple, parallel inits are still a cause for concern. How can I handle this?