NeurofitVitals. All public types are
Sendable, and events are delivered on the main thread.
1
Add the package
Binary license. Your delivery contains Source license. Add the SDK folder as a local package dependency and link the The package manifest uses Swift tools 5.9,
NeurofitVitals.xcframework (and a zip with its SwiftPM
checksum). Either drag it into your app target (Frameworks, Libraries and Embedded Content, set to Embed and
Sign), or reference it from a local Swift package with a binaryTarget:Package.swift
NeurofitVitals product.
The package depends on the PpgCore engine package that ships next to it (ppgcore/ports/swift), and the
sources use access-level imports (internal import PpgCore), so building them needs Xcode 16 or newer.Package.swift
platforms: [.iOS(.v15)] and Swift 5 language mode; the product
is a dynamic library. There are no dependencies beyond Apple frameworks.2
Declare camera usage
Add The SDK samples the accelerometer through Core Motion to help estimate breathing rate. That does not show a
permission prompt; adding
NSCameraUsageDescription to your Info.plist. iOS shows this text in the permission prompt.Info.plist
NSMotionUsageDescription is still recommended, and name the accelerometer in your
consent copy. See Privacy and compliance.Info.plist
3
Activate the SDK
Call With the binary xcframework the key must list your bundle identifier, including any development identifier
you run under; only a Debug build of the SDK sources relaxes that check to a warning. See
License keys for the key format,
activate(licenseKey:) once, early in the app’s life, before you create a session. Verification is
offline and fast; call it synchronously at launch. The call throws when the key is malformed, signed by
another key, issued for a different bundle identifier, or does not cover this SDK build’s date.updatesUntil and the debug behaviour.4
Check device support and camera access
start() also prompts when access is not yet determined, so the explicit request is for your own flow (a
rationale screen before the system prompt).5
Create a session and listen for events
A
VitalsSession owns the camera, the torch and one reading at a time. Consume events as an AsyncStream,
or set a delegate if you prefer callbacks. Both deliver on the main thread.start() turns on the camera and torch and moves the session to positioning. It throws .alreadyRunning
if called while running, .notActivated if activation was lost, .cameraDenied, .cameraRestricted or
.cameraUnavailable for camera problems, .unsupportedDevice(reason:) when the device cannot sustain a
reading, and .internalError on a session that was stopped or has finished. A failed start() leaves the
session idle, so you can call it again after fixing the cause. VitalsSession.init itself throws
.notActivated, .unsupportedDevice(reason:) or .internalError("Invalid configuration: ...").6
Show the camera preview (optional)
The session exposes an
AVCaptureVideoPreviewLayer you can place in your own view. Many apps show a small
red circle of the fingertip so the user sees their pulse in the glow.7
Use the result
VitalsResult is Codable, so you can store or upload it as JSON. Field meanings, units and how to treat
the withheld tier are on the Metrics page.Guidance copy
Guidance is an enum; the SDK does not ship strings. Map each case to your own localized copy. The NEUROFIT
app’s copy is listed on the Reading lifecycle page as a starting point.
Lifecycle notes
- Call
stop()when your reading screen disappears. It is idempotent, turns the torch off and releases the camera. A stopped session cannot be restarted; create a new one. - Create a new
VitalsSessionfor each reading screen. A completed or failed session does not restart. The one exception is a cancel withautoRestartAfterCancel = false: the session goes back toidlewith the camera off andstart()works again. - The reading needs the app in the foreground. Backgrounding, a phone call, another app taking the camera or a
media-services reset while positioning or measuring ends the session with
.failed(.interrupted(reason:))(for backgrounding the reason is “The app moved to the background”); recreate the session when the user returns. Lock the reading screen’s orientation while a session runs. - Keep the phone still and the screen on for the duration. Consider
UIApplication.shared.isIdleTimerDisabledwhile a session is running. - For debugging,
VitalsSDK.isLoggingEnabled = truelogs state transitions toos.Logger(subsystemcom.neurofit.vitals); it is off by default and never logs values or frames.
Running the package tests
The package’s unit tests run on the Simulator (no camera needed). Pick the simulator by id, because a name such asiPhone 15 can match several installed runtimes:
Next steps
- Reading lifecycle: every state, event and guidance value.
- Metrics: definitions, units and validated accuracy.
- API reference (iOS): every public type.