Add iOS 12 support to a new Xcode 11 Project
Tags: ios, swift
Published: 2019-11-08 12:49:44

When you create a new project in Xcode 11, you automatically get the new `SceneDelegate` for free. This is great if you want to build an app that's for iOS 13 and newer but as soon as you change your deployment target to an iOS version that's lower than iOS 13, your app will have trouble compiling. In this Quick Tip, I will show you how to update your project in order to make it compile for iOS 12 and below. You will first learn how to use the `SceneDelegate` for iOS 13 and up, and use the `AppDelegate` as a fallback for older versions of iOS. After that, I will show you how to opt-out of using the `SceneDelegate` completely if you're absolutely sure that you're not interested in any of its benefits for iOS 13.

## Making the existing template work for iOS 12
Since the `UIWindowSceneDelegate` is only available in iOS 13 and up, we'll need to exclude the entire `SceneDelegate` object if the app is compiled for iOS 12 or below. To do this, add an `@available` annotation to the `SceneDelegate` class as shown in the following code snippet:

```swift
@available(iOS 13, *)
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
```

This ensures that the `SceneDelegate` is not included in iOS 12 builds. Next, go to the `AppDelegate` and add the same `@available` annotation to `application(_:configurationForConnecting:options)` and `application(_:didDiscardSceneSessions)` as shown in the following code snippet:

```swift
@available(iOS 13, *)
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
  // ...
}

@available(iOS 13, *)
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
  // ...
}
```

Lastly, since applications that use storyboards must a `window` property defined on the `AppDelegate` for iOS 12 and below, add the following property to the `AppDelegate`:

```swift
var window: UIWindow?
```

This will allow iOS to instantiate the `Main.storyboard` and use it to create and populate the `window` object on iOS 12. For iOS 13 and above the `window` will remain unset because the `SceneDelegate` will set its own window on those versions of iOS.

Your app should be able to run on iOS 12 and 13 now. One last thing you might want to add to `application(_:didFinishLaunchingWithOptions:)` is the following:

```swift
if #available(iOS 13, *) {
  // do nothing / do things that should only be done for iOS 13
} else {
  // do iOS 12 specific window setup
}
```

This will allow you to do some version dependent set up in your `AppDelegate`.

Keep in mind that now that you have the `AppDelegate` for iOS 12 and the `SceneDelegate` for iOS 13 you have different entry points in your code for different iOS versions. This means that you might have to do some special setup or apply duplicated logic in the `AppDelegate` or `SceneDelegate` depending on what you need to achieve. If you don't want to do this, you can also opt-out of the `SceneDelegate` completely. Let's see how.

## Opting out of the SceneDelegate completely
To opt-out of using the `SceneDelegate` in your project, you should take the following steps:

1. Begin by deleting the `SceneDelegate.swift` file from your project. 
2. Next, open `AppDelegate.swift` and remove all scene related methods from that file. 
3. Lastly, you'll need to open your `Info.plist` and remove the `Application Scene Manifest` key from that file.

Three simple steps and you're able to work on your project in the same way you used to do in Xcode 10. Very nice.

## In summary
In this Quick Tip, you've learned how to add a couple of clever `@available` and `if #available` statements to your code to make sure your projects work on iOS 12 and below. While this isn't a lot of work, I think it's still somewhat inconvenient that we have to do this to make Xcode 11 work for in a very reasonable scenario. Supporting older iOS versions is something a lot of developers have to do so it would have been nice to see Apple accommodate this when creating a new project in Xcode. I would recommend against using the approach of opting out of the `SceneDelegate` entirely because it has some awesome advantages that I describe in my posts [Understanding the iOS 13 Scene Delegate](https://www.donnywals.com/understanding-the-ios-13-scene-delegate/) and [Adding support for multiple windows to your iPadOS app](https://www.donnywals.com/adding-support-for-multiple-windows-to-your-ipados-app/).

When you deploy your app to iOS 12 and use the `SceneDelegate` for iOS 13, you will run into some come duplication between the `AppDelegate` for iOS 12 and the `SceneDelegate` for iOS 13. I chose to omit suggestions to make this manageable because I really wanted to keep this post short. I'm sure you can come up with some way to encapsulate the duplicated logic in some kind of helper object that you can use to configure your app in either the `AppDelegate` or the `SceneDelegate`. I might write something about this in the future. Make sure to follow me on [Twitter](https://twitter.com/donnywals). Don't hesitate to reach out to me if you have any questions or suggestions for me!