I will leave the discussion of why UI elements are sometimes not initialized for non-UI (background) launches to others who have more expertise on these things. Here, I will address the CoreBluetooth problem you are obviously having due to this behavior.
In general it is not a correct pattern to make app-wide non-UI functionality dependent on UI elements like Views.
Indeed, CoreBluetooth works at the app level, and needs to be initialized and used at the app level, not hidden behind a view. When the system relaunches your app due to the sensor coming back in range, it is doing so because the expectation is your app needs to take some action and respond to the BLE event that occurred (whether it is the sensor coming in or out of range, new data arriving, connection dropping, etc.) as soon as possible, and it should not be waiting for the app views to be rebuilt after launch, even in the 9 out of 10 case this seems to work for you.
The correct use is to bring all CoreBluetooth functionality to the app level. Prior to SwiftUI, this would have been done in the Application Delegate class, which controls the app's life cycle, and it is executed before anything else in the app.
In SwiftUI, this can still be done, but in a roundabout way.
For CoreBluetooth to function when relaunched in the background (by Bluetooth State Restoration), before anything else, you need to reinstantiate your CBManager (CBCentralManager or CBPeripheralManager based on your use case) immediately, preferably inside applicationDidFinishLaunching() with the same CBCentralManagerOptionRestoreIdentifierKey, so the system can hand over the preserved manager back to your app. To do that your willRestore() function will be called when ready, so make sure you also move that to the same class I will describe below.
This needs to be don in an app'a AppDelegate.
Because SwiftUI does not expose an AppDelegate you can add code to, you will need to do it the way it is described at UIApplicationDelegateAdaptor
Basically you would create a class that contains the necessary app delegate functions, and then use the @UIApplicationDelegateAdaptor construct so that class is executed when the app is launched =- this will happen whether it is launched in the background or the foreground.
If how to make this change is not clear, you can probably find examples of it on the internet. And we also do have a CoreBluetooth sample Interacting with Bluetooth peripherals during background app refresh that implements this construct.
As this is a watchOS sample, the code itself may not be of direct use to you, but the project will demonstrate how the "App Delegate" is constructed for CoreBluetooth purposes in a SwiftUI app.
Argun Tekant /
WWDR Engineering /
Core Technologies