---
title: iOS quickstart
description: The by-hand iOS quickstart — add the Extentos Swift package, set the Info.plist keys, initialize, and make your first capability call.
type: tutorial
platform: ios
related:
  - /docs/sdk/ios
  - /docs/sdk/ios/install
  - /docs/getting-started/with-agent
---

The Extentos iOS SDK installs from
[`github.com/extentos/swift-glasses`](https://github.com/extentos/swift-glasses) via
Swift Package Manager — `.package(url: "https://github.com/extentos/swift-glasses", from: "2.1.2")`
(current version on the [install page](/docs/sdk/ios/install)). This page is the
by-hand path; the [agent-driven flow](/docs/getting-started/with-agent) automates
every step below.

## 1. Add the package

In Xcode: *File → Add Package Dependencies…* →
`https://github.com/extentos/swift-glasses` → dependency rule **Up to Next Major
Version**, starting at `2.0.0`. Link **`GlassesCore`**; add `GlassesUI` only if
you render the packaged connection page (a voice app doesn't). Other manifest
forms: [Install](/docs/sdk/ios/install). Requirements: the Swift 6 toolchain,
Meta DAT (`meta-wearables-dat-ios`) 0.8.0+ (resolved transitively), and
deployment target **iOS 16.0+ — or 17.0+ if you add `GlassesLocal`** for
[on-device models](/docs/concepts/local-models). Pick 17 up front if that's
anywhere in your plan.

## 2. Add the Info.plist keys

**Which keys you need depends on your path** — see [choose your path](/docs/getting-started/choose-your-path).

**Voice apps** need the privacy strings your capabilities imply — `NSMicrophoneUsageDescription` and `NSSpeechRecognitionUsageDescription` — plus `UIBackgroundModes: ["audio"]` if the assistant must keep listening while your app is backgrounded, plus the two Extentos keys `EXTENTOS_APP_ID` and `EXTENTOSProjectKey`. **No Meta keys and no Meta Developer account.** The project key is not a Meta credential: it's how a debug build on a real iPhone authenticates to the managed gateway, and an assistant app without it fails at runtime with `AssistantError.NoApiKey` after a perfectly clean build.

**Camera or display apps** additionally need the Meta DAT set: the `MWDAT` dict (including an explicit `DAMEnabled`), `CFBundleURLTypes` (a custom scheme, not a universal link), `LSApplicationQueriesSchemes: ["fb-viewapp"]`, `UISupportedExternalAccessoryProtocols: ["com.meta.ar.wearable"]`, and the Bluetooth/external-accessory `UIBackgroundModes`.

Full set with values: [Info.plist setup](/docs/sdk/ios/info-plist).

## 3. Initialize

Create the SDK entry point once, at your `App` entry point, and forward the Meta
auth callback:

```swift
import GlassesCore

@main
struct MyApp: App {
    // usedCapabilities is load-bearing on iOS — it picks the transport.
    // A voice app declares [.microphone, .speaker]; add .camera / .display
    // if you use them. Leaving it empty resolves to real glasses.
    let glasses: any ExtentosGlasses = Extentos.create(config: ExtentosConfig(
        usedCapabilities: [.microphone, .speaker]
    ))
    // Leave `debug` at its false default for anything you run on a real phone.
    // `debug: true` opens a pending browser-simulator socket and waits for the
    // MCP bridge to bind it — which is what you want during the simulator dev
    // loop, and which strands the app on a phone with no bridge running.

    var body: some Scene {
        WindowGroup {
            ContentView(glasses: glasses)
                .onOpenURL { url in Task { _ = await glasses.handleUrl(url) } }
        }
    }
}
```

`ExtentosConfig`'s full field list (transport choice, environment, consent flags, …)
is in the [iOS API reference](/docs/reference/ios-api); details:
[Initialization](/docs/sdk/ios/initialization).

## 4. Make your first capability call

Every call is `async` and returns an `ExtentosResult` — pattern-match it
(`if case .success(let photo) = await glasses.camera.capturePhoto()`); don't wrap in
`do/catch`. See [Threading](/docs/sdk/ios/threading).

## 5. Drop in the connection page — camera and display apps only

Skip this step if you're building a voice app: it renders no connection page, so it doesn't need `GlassesUI` at all. See [choose your path](/docs/getting-started/choose-your-path).

```swift
import GlassesUI

ExtentosConnectionPage(glasses: glasses)   // status, capabilities, toggles — library-owned UI
```

## 6. Verify in the simulator

Run against the [browser simulator](/docs/concepts/transport-vs-app) — the same
library code as production with only the transport swapped, so a green run here is
meaningful. With `debug: true`, the SDK's `Auto` transport resolution picks the
simulator transport during development.
