The Starter Project

After you have all the necessary tools installed, just open up XCode and click create a new project. You will be prompted to choose the platform.

Click on VisionOS and choose the App and hit Next

App creation dialog

You can give your project a name and some other details

Project details dialog

Here, you specify the project name, the team it belongs to and the bundle identifier.

  • The team I selected here is my Personal Team / My developer account. If you have a team that you want to work with, you choose that.

  • The organization identifier is how Apple will identify the app’s organisation when you submit it to the App Store. This combined with the Product Name will form the Bundle Identifier which is what the App Store uses to identify each app.

This is normal for all iOS developers.

Once you choose where you want the project to go in the next screen, your project will open up.

Starter Project in XCode

This is what my project looks like.

  • The left pane is where the project navigation happens.

  • The Editor is divided into two parts, one showing the code and the other showing the canvas with a preview of how the app will look like once built.

I’ll be honest, I tried to use the previews and I never got them to work and even when they did, I think it was just faster for me to build to the simulator. They are amazing tools in iOS, but in Vision OS, they were not as useful.

You can close the preview/canvas by clicking on the button here and unchecking the canvas from the drop down.

Closing the canvas

Now lets take a look at the code we have.

Open the {project-name}App file in the project. For me, this is MediumWindowApp

import SwiftUI

@main
struct MediumWindowApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }

        ImmersiveSpace(id: "ImmersiveSpace") {
            ImmersiveView()
        }
    }
}

The @main here signifies that this is the main point of entry into our App.

The MediumWindowApp is derived from the App class, which will handle all the instantiations for us.

Let’s break this down.

The App Struct has a variable in it called body which is a Scene

Every app has one scene that will be loaded on Start. This is the Scene for our app. And that scene contains, the WindowGroup and Immersive Space.

As the name implies WindowGroup is just a group of UI windows. And ImmersiveSpace is a 3D space that’s immersive. Please note that the ImmersiveSpace has an id also called ImmersiveSpace

For VisionOS apps, the first window group in the body is displayed automatically on start. For us, it is the ContentView()

To look into what ContentView() shows, we can open the ContentView file. This is the file that Xcode opened for me when I created this project.

Let us concentrate on this part of the code first

VStack {
    Model3D(named: "Scene", bundle: realityKitContentBundle)
        .padding(.bottom, 50)

    Text("Hello, world!")

    Toggle("Show ImmersiveSpace", isOn: $showImmersiveSpace)
        .font(.title)
        .frame(width: 360)
        .padding(24)
        .glassBackgroundEffect()
}

It is a stack of a Model3D , a Text and a Toggle
If you run the app in the simulator ( ⌘ + r ) in xcode, you should be seeing this.

Placeholder App run in the simulator

As you can see, it is a 3D object, some text and a toggle in a vertical stack. Try modifying the text in the Text("Hello, World") field and run it again to see the changes.

As you can see from the code, the toggle is hooked up to a binding called showImmersiveSpace

.onChange(of: showImmersiveSpace) { _, newValue in
    Task {
        if newValue {
            switch await openImmersiveSpace(id: "ImmersiveSpace") {
            case .opened:
                immersiveSpaceIsShown = true
            case .error, .userCancelled:
                fallthrough
            @unknown default:
                immersiveSpaceIsShown = false
                showImmersiveSpace = false
            }
        } else if immersiveSpaceIsShown {
            await dismissImmersiveSpace()
            immersiveSpaceIsShown = false
        }
    }
}

We monitor that variable here and we have a Task to openImmersiveSpace(id:"ImmersiveSpace") The id, ImmersiveSpace is from the App file as we noted earlier. So, when you click the toggle, we open the immersive space with this id.

And when you toggle it again, we call dismissImmersiveSpace which closes it.

We’ll head more into what the Model3D call does, and what the ImmersiveView file does in the next article. But I hope this provides a good starting point for the starter project.

Next
Next

Introduction to Apple Vision Pro