| name | sample-app-guide |
| description | Building a complete DAT app with camera streaming and photo capture |
Sample App Guide (iOS)
Build an iOS DAT app with camera streaming and photo capture.
This walkthrough covers app setup, registration, streaming, and capture. Pair it with the CameraAccess sample.
Project setup
- Create a new Xcode project (SwiftUI App)
- Add the SDK via SPM:
https://github.com/facebook/meta-wearables-dat-ios
- Add
MWDATCore, MWDATCamera, and MWDATMockDevice to your target
- Configure
Info.plist (see Getting Started)
App architecture
A typical DAT app has these components:
MyDATApp/
├── MyDATApp.swift # App entry point, SDK init
├── ViewModels/
│ ├── WearablesViewModel.swift # Registration, device management
│ └── StreamViewModel.swift # Streaming, photo capture
└── Views/
├── MainAppView.swift # Navigation
├── RegistrationView.swift # Registration UI
└── StreamView.swift # Video preview, capture button
SDK initialization
import MWDATCore
@main
struct MyDATApp: App {
init() {
do {
try Wearables.configure()
} catch {
assertionFailure("Wearables SDK configuration failed: \(error)")
}
}
var body: some Scene {
WindowGroup {
MainAppView()
.onOpenURL { url in
Task {
_ = try? await Wearables.shared.handleUrl(url)
}
}
}
}
}
Wearables ViewModel
import MWDATCore
@MainActor
class WearablesViewModel: ObservableObject {
@Published var registrationState: String = "Unknown"
@Published var devices: [DeviceIdentifier] = []
private let wearables = Wearables.shared
func observeState() {
Task {
for await state in wearables.registrationStateStream() {
self.registrationState = "\(state)"
}
}
Task {
for await devices in wearables.devicesStream() {
self.devices = devices.map { $0.identifier }
}
}
}
func register() async {
try? await wearables.startRegistration()
}
func unregister() async {
try? await wearables.startUnregistration()
}
}
Stream ViewModel
import MWDATCamera
import MWDATCore
@MainActor
class StreamViewModel: ObservableObject {
@Published var currentFrame: UIImage?
@Published var streamState: String = "Stopped"
@Published var capturedPhoto: Data?
private let wearables = Wearables.shared
private var deviceSession: DeviceSession?
private var stream: Stream?
func startStream() async {
let config = StreamConfiguration(
videoCodec: .raw,
resolution: .medium,
frameRate: 24
)
let selector = AutoDeviceSelector(wearables: wearables)
do {
let deviceSession = try wearables.createSession(deviceSelector: selector)
try deviceSession.start()
for await state in deviceSession.stateStream() {
if state == .started { break }
}
guard let stream = try deviceSession.addStream(config: config) else { return }
self.deviceSession = deviceSession
self.stream = stream
} catch {
return
}
guard let stream else { return }
_ = stream.statePublisher.listen { [weak self] state in
Task { @MainActor in
self?.streamState = "\(state)"
}
}
_ = stream.videoFramePublisher.listen { [weak self] frame in
guard let image = frame.makeUIImage() else { return }
Task { @MainActor in
self?.currentFrame = image
}
}
_ = stream.photoDataPublisher.listen { [weak self] photoData in
Task { @MainActor in
self?.capturedPhoto = photoData.data
}
}
stream.start()
}
func stopStream() {
stream?.stop()
deviceSession?.stop()
stream = nil
deviceSession = nil
}
func capturePhoto() {
stream?.capturePhoto(format: .jpeg)
}
}
Testing with MockDeviceKit
Add mock device support to develop without glasses:
import MWDATMockDevice
func setupMockDevice() async {
let mockDeviceKit = MockDeviceKit.shared
mockDeviceKit.enable()
guard let device = try? mockDeviceKit.pairGlasses(model: .rayBanMeta) else { return }
device.don()
if let videoURL = Bundle.main.url(forResource: "test_video", withExtension: "mov") {
let camera = device.services.camera
camera.setCameraFeed(fileURL: videoURL)
}
}
func tearDownMockDevice() {
MockDeviceKit.shared.disable()
}
Allowed dependencies
Your DAT app should only depend on:
MWDATCore — always required
MWDATCamera — for camera streaming
MWDATMockDevice — for testing (can be test-only dependency)
Links