Skip to content

Commit

Permalink
Remove access to application launch options via @Application on macOS (
Browse files Browse the repository at this point in the history
…#100)

# Remove access to application launch options via @Application on macOS

## ♻️ Current situation & Problem
The current version of Spezi crashes when using the
`ApplicationDelegateAdaptor` with the `.spezi()` view modifier on macOS
platforms. This results from a broken assumption about the
initialization order upon Spezi bootup on macOS (not Catalyst!): The
`.spezi()` view modifier is evaluated (and therefore `Spezi`
initialized) before `SpeziAppDelegate/applicationWillFinishLaunching()`
is called.
This currently leads to a `precondition` failure on macOS within
`SpeziAppDelegate/applicationWillFinishLaunching()` as `Spezi` is
already initialized.

Background: We initialize `Spezi` on macOS within the
`SpeziAppDelegate/applicationWillFinishLaunching()` so that the
application launch options are accessible via `@Application`
(`@Application(\.launchOptions)`).

We noticed that error when lifting the SpeziSpeech module to visionOS &
macOS: StanfordSpezi/SpeziSpeech#5

## ⚙️ Release Notes 
- Remove access to application launch options via @Application on macOS,
fixing a crash upon Spezi initialization


## 📚 Documentation
Adjusted documentation in line about not supporting launch options on
macOS anymore


## ✅ Testing
Manual testing 


## 📝 Code of Conduct & Contributing Guidelines 

By submitting creating this pull request, you agree to follow our [Code
of
Conduct](https://github.com/StanfordSpezi/.github/blob/main/CODE_OF_CONDUCT.md)
and [Contributing
Guidelines](https://github.com/StanfordSpezi/.github/blob/main/CONTRIBUTING.md):
- [x] I agree to follow the [Code of
Conduct](https://github.com/StanfordSpezi/.github/blob/main/CODE_OF_CONDUCT.md)
and [Contributing
Guidelines](https://github.com/StanfordSpezi/.github/blob/main/CONTRIBUTING.md).
  • Loading branch information
philippzagar authored Feb 24, 2024
1 parent c8482d0 commit 0ced3ef
Show file tree
Hide file tree
Showing 4 changed files with 7 additions and 20 deletions.
17 changes: 5 additions & 12 deletions Sources/Spezi/Spezi/KnowledgeSources/LaunchOptionsKey.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@
import SpeziFoundation
import SwiftUI


struct LaunchOptionsKey: DefaultProvidingKnowledgeSource {
typealias Anchor = SpeziAnchor

#if os(iOS) || os(visionOS) || os(tvOS)
typealias Value = [UIApplication.LaunchOptionsKey: Any]
#elseif os(macOS)
typealias Value = [AnyHashable: Any]
/// Currently not supported as ``SpeziAppDelegate/applicationWillFinishLaunching(_:)`` on macOS
/// is executed after the initialization of ``Spezi`` via `View/spezi(_:)` is done, breaking our initialization assumption in ``SpeziAppDelegate/applicationWillFinishLaunching(_:)``.
typealias Value = [Never: Any]
#else // os(watchOS)
typealias Value = [Never: Any]
#endif
Expand Down Expand Up @@ -48,17 +51,7 @@ extension Spezi {
public var launchOptions: [UIApplication.LaunchOptionsKey: Any] {
storage[LaunchOptionsKey.self]
}
#elseif os(macOS)
/// The launch options of the application.
///
/// You can access the launch options within your `configure()` method of your ``Module`` or ``Standard``.
///
/// - Note: For more information refer to the documentation of
/// [`applicationWillFinishLaunching(_:)`](https://developer.apple.com/documentation/appkit/nsapplicationdelegate/1428623-applicationwillfinishlaunching).
public var launchOptions: [AnyHashable: Any] {
storage[LaunchOptionsKey.self]
}
#else // os(watchOS)
#else // os(watchOS) || os(macOS)
/// The launch options of the application on platforms that don't support launch options.
public var launchOptions: [Never: Any] {
storage[LaunchOptionsKey.self]
Expand Down
2 changes: 1 addition & 1 deletion Sources/Spezi/Spezi/Spezi+Preview.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public enum LifecycleSimulationOptions {
case launchWithOptions(_ launchOptions: [UIApplication.LaunchOptionsKey: Any])
#elseif os(macOS)
/// Injects the ``Spezi/launchOptions`` property to be accessed via the `@Application` property wrapper.
case launchWithOptions(_ launchOptions: [AnyHashable: Any])
case launchWithOptions(_ launchOptions: [Never: Any])
#else // os(watchOS)
/// Injects the ``Spezi/launchOptions`` property to be accessed via the `@Application` property wrapper.
case launchWithOptions(_ launchOptions: [Never: Any])
Expand Down
6 changes: 0 additions & 6 deletions Sources/Spezi/Spezi/SpeziAppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -124,12 +124,6 @@ open class SpeziAppDelegate: NSObject, ApplicationDelegate {
return // see note above for why we don't launch this within the preview simulator!
}

precondition(_spezi == nil, "\(#function) was called when Spezi was already initialized. Unable to pass options!")

var storage = SpeziStorage()
storage[LaunchOptionsKey.self] = notification.userInfo
self._spezi = Spezi(from: configuration, storage: storage)

setupNotificationDelegate()
}
#elseif os(watchOS)
Expand Down
2 changes: 1 addition & 1 deletion Tests/UITests/TestAppUITests/LifecycleHandlerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ final class LifecycleHandlerTests: XCTestCase {
let chrome = XCUIApplication(bundleIdentifier: "com.apple.RealityChrome")
XCTAssert(chrome.buttons["CloseButton"].exists)
chrome.buttons["CloseButton"].tap()
sleep(1)
sleep(3)
app.activate()
#elseif !os(macOS)
let homeScreen = XCUIApplication(bundleIdentifier: XCUIApplication.homeScreenBundle)
Expand Down

0 comments on commit 0ced3ef

Please sign in to comment.