Skip to main content

Installation

Requirements: iOS 14.0+, Xcode 15.0+, Swift 5.7+ The iOS SDK ships as pre-built frameworks. Add them to your Xcode target:
FrameworkAction
PlaudBleSDK.frameworkEmbed & Sign
PlaudWiFiSDK.frameworkEmbed & Sign
PlaudDeviceBasicSDK.frameworkEmbed & Sign
PlaudDeviceBasicSDK.bundleCopy Bundle Resources
Frameworks are located at sdk/ios/ in the Plaud SDK repo.
SDK frameworks are compiled for arm64 (physical devices only). Simulator is not supported.

Methods

Plaud Device SDK Initialization

The SDK is initialized with a User Token and your regional domain.
If you haven’t onboarded to the Plaud Developer Platform, see our quickstart onboarding steps.If you’d like more details on how to retrieve your User Token and the token exchange flow, see the Authentication API reference.
Swift
import PlaudDeviceBasicSDK

PlaudDeviceAgent.shared.initSDK(
    userAccessToken: "user-token",
    customDomain: "platform-us.plaud.ai"  // domain only, no https://
)
userAccessToken
string
required
User Access Token (JWT), used for device authentication. The handshake token is automatically parsed from the JWT sub field.
customDomain
string
required
Your regional Plaud server domain without https:// prefix. All SDK network requests use this domain.For more information on how to find your regional server domain, see the Authentication API docs.

Refreshing User Token

If the User Token is refreshed (e.g., after re-login), you can update it:
Swift
PlaudDeviceAgent.shared.setUserAccessToken(newToken)
newToken
string
required
Refreshed User Token (JWT)
This automatically updates the handshake token and refreshes the RSA key pair.

Connecting (binding) to a Plaud Device

The .startScan() will call the bleScanResult callback defined in the PlaudDeviceAgentProtocol
Swift
PlaudDeviceAgent.shared.delegate = self

PlaudDeviceAgent.shared.startScan()

extension DeviceManager: PlaudDeviceAgentProtocol {
    func bleScanResult(bleDevices: [BleDevice]) {
    //...
        let match = bleDevices.first(where: { $0.serialNumber == lastSN }),
        PlaudDeviceAgent.shared.connectBleDevice(bleDevice: match, deviceToken: userId)
    }
    //...
}
bleDevice
BleDevice
required
A scanned/connected device
deviceToken
deviceToken
If needed, a unique identifier for that device

PlaudDeviceAgentProtocol Callbacks

The PlaudDeviceAgentProtocol is a delegate protocol with a few key callbacks for the PlaudDeviceAgent. See the Protocols section for the full list of callbacks.
CallbackDescription
bleScanResult(bleDevices: [BleDevice])Scan results updated
bleConnectState(state: Int)1 = connected, 0 = disconnected
bleBind(sn:status:protVersion:timezone:)Binding status updated
blePenState(state:privacy:keyState:uDisk:findMyToken:hasSndpKey:deviceAccessToken:)Device state changed

File Synchronization

The exportAudio method exports audio files from Plaud device to your users’ phone, reporting progress through the AudioExportCallback. The .getFileList accesses files on your users’ Plaud device, and the .deleteFile method will delete an audio file off of your users’ Plaud device.
Swift
// Get file list from device
PlaudDeviceAgent.shared.getFileList(startSessionId: 0)

extension SyncManager: AudioExportCallback {
    public func onComplete(outputPath: String) {
        // ...
        PlaudDeviceAgent.shared.exportAudio(
            sessionId: sessionId,
            outputDir: outputDir,
            format: .wav,
            channels: 1,
            callback: self
        )
    }
}

// Delete file from device
PlaudDeviceAgent.shared.deleteFile(sessionId: sessionId)
sessionId
Int
required
Session ID
outputDir
String
required
Output Directory
format
AudioExportFormat
required
.opus | .mp3 | .wav | .pcm
channels
Int
pcm = 0, mp3 = 1, wav = 2, opus = 3
callback
AudioExportCallback
required
See AudioExportCallback for details.func onProgress(_ progress: Int, message: String)func onComplete(outputPath: String)func onError(_ error: String)

WiFi Fast Transfer

Alternative to a BLE (Bluetooth Low Energy) transfer, the Plaud NotePin S can initialize a WiFi Fast Transfer when charging. The WiFi Fast Transfer is ~10x faster than BLE transfers.
Requires the Hotspot Configuration entitlement in your iOS app settings.
PlaudDeviceAgent.shared.setDeviceWiFi(open: true)

extension DeviceManager: PlaudDeviceAgentProtocol {
    func bleWiFiOpen(_ status: Int, _ wifiName: String, _ wholeName: String, _ wifiPass: String) {
        PlaudWiFiAgent.shared.bleDevice = BleAgent.shared.bleDevice
        PlaudWiFiAgent.shared.connectWifi(ssid: wifiName, password: wifiPass)
    }
}

private class WiFiExportHandler: NSObject, AudioExportCallback {
    //...
    func onComplete(outputPath: String) {
        PlaudWiFiAgent.shared.exportAudioViaWiFi(
            sessionId: next.sessionId,
            outputDir: outputDir,
            format: AudioExportFormat.opus,
            channels: 1,
            callback: handler
        )
    }
}

Protocol Callbacks

The WiFi Fast Transfer has two key callbacks, one on the PlaudDeviceAgentProtocol and another on the AudioExportCallback.
ProtocolCallbackDescription
PlaudDeviceAgent ProtocolbleWiFiOpen(_ status: Int, _ wifiName: String, _ wholeName: String, _ wifiPass: String)Called when Plaud device opens hotspot
AudioExportCallbackonCompleteCalled when a file has downloaded

Firmware Update (OTA)

The Embedded SDK handles the entire OTA flow: version query → download → MD5 verify → CRC → BLE packet push → device restart → reconnect.

Check for Firmware Updates

Swift
// Check for update
PlaudDeviceAgent.shared.checkFirmwareUpdate { result in
    guard result.hasUpdate else { return }
    print("New version: \(result.latestVersion), release notes: \(result.releaseNotes)")
}
firmwareCheck
(PlaudFirmwareCheckResult) -> Void
required
Callback function with type PlaudFirmwareCheckResult

Download Firmware Update

Swift
// One-call firmware update
PlaudDeviceAgent.shared.startFirmwareUpdate(
    progress: { phase, percentage in
        // phase: .downloading / .installing / .restarting / .complete
        // percentage: 0.0 ~ 1.0
    },
    completion: { result in
        if result.success {
            print("Updated to \(result.version)")
        } else {
            print("Failed: \(result.errorMessage ?? "")")
        }
    }
)
progress
(PlaudFirmwarePhase, Float) -> Void
required
Callback that reports firmware update progress.
  • phase: Current phase of the update (PlaudFirmwarePhase)
  • percentage: Progress from 0.0 to 1.0
completion
(PlaudFirmwareUpdateResult) -> Void
required
Callback when the update completes.
If you already have the firmware file downloaded, use pushFirmwareFile() instead:

Push Firmware Update

Swift
PlaudDeviceAgent.shared.pushFirmwareFile(
    filePath: localPath,
    toVersion: "V1.2.8",
    progress: { phase, pct in },
    completion: { result in }
)
filePath
String
required
Full path to the locally downloaded firmware file
toVersion
String
required
Target firmware version to update to (e.g., “V1.2.8”)
progress
(PlaudFirmwarePhase, Float) -> Void
required
Callback that reports firmware update progress.
  • phase: Current phase (downloading / installing / restarting / complete)
  • percentage: Progress from 0.0 to 1.0
completion
(PlaudFirmwareUpdateResult) -> Void
required
Callback when the update completes with success, version, and errorMessage fields.

Protocols

The Embedded SDK is delegate-driven. You implement protocols and assign yourself as the delegate to receive device events, transfer progress, and results. These three protocols should cover most use cases.
Most callbacks are delivered on the SDK’s internal dispatch queues — not the main thread. Marshal to the main queue before touching UIKit or published state.

PlaudDeviceAgentProtocol

The primary delegate for PlaudDeviceAgent. Assign it once and it drives the entire BLE lifecycle — scan, connect, bind, device state, recording, and file sync.
Swift
PlaudDeviceAgent.shared.delegate = self

extension DeviceManager: PlaudDeviceAgentProtocol {
    // REQUIRED — overall device state after handshake
    func blePenState(state: Int, privacy: Int, keyState: Int, uDisk: Int,
                     findMyToken: Int, hasSndpKey: Int, deviceAccessToken: Int) {
        // ...
    }
}
blePenState is the only required member. Every other callback is @objc optional — implement only the ones you need.
The most commonly used callbacks, grouped by concern:
GroupCallbackDescription
ConnectionblePenState(...)Required. Device state reported after the handshake completes
ConnectionbleConnectState(state: Int)1 = connected, 0 = disconnected
ConnectionbleScanResult(bleDevices: [BleDevice])Scan results updated
ConnectionbleScanOverTime()Scan timed out with no results
ConnectionbleBind(sn:status:protVersion:timezone:)Binding status updated
Device statebleStorage(total: Int, free: Int, duration: Int)Storage usage on the device
Device statebleChargingState(isCharging: Bool, level: Int)Charging / battery level changed
RecordingbleRecordStart(sessionId:start:status:scene:startTime:reason:)Recording started
RecordingbleRecordStop(sessionId:reason:fileExist:fileSize:)Recording stopped
RecordingblePcmData(sessionId:millsec:pcmData:isMusic:)Live PCM chunks for waveform / metering
File syncbleFileList(bleFiles: [BleFile])Result of getFileList(...)
File syncbleData(sessionId: Int, start: Int, data: Data)A chunk of file data during sync
File syncbleDataComplete()File transfer finished
File syncbleDeleteFile(sessionId: Int, status: Int)Result of deleteFile(...)
WiFibleWiFiOpen(_ status: Int, _ wifiName: String, _ wholeName: String, _ wifiPass: String)Device opened its hotspot — hand off to PlaudWiFiAgent
OTAbleFotaResult(uid: Int, status: Int, errmsg: String?)Firmware push result
The SDK also exposes a lower-level BleAgentProtocol on BleAgent with 60+ required callbacks. Prefer PlaudDeviceAgentProtocol — the facade handles the handshake, decryption, and format conversion for you, and lets you implement only the callbacks you care about.

AudioExportCallback

Reports progress, completion, and errors for .exportAudio (BLE) and .exportAudioViaWiFi (WiFi).
Swift
extension SyncManager: AudioExportCallback {
    func onProgress(_ progress: Int, message: String) {
        // progress: 0–100
    }
    func onComplete(outputPath: String) {
        // decoded file is ready at outputPath
    }
    func onError(_ error: String) {
        // ...
    }
}
onProgress(_ progress: Int, message: String)
func
required
Export progress, 0100, with a human-readable status message.
onComplete(outputPath: String)
func
required
Called when decoding finishes; outputPath is the full path to the written file.
onError(_ error: String)
func
required
Called if export fails, with a description of the error.

PlaudWiFiAgentProtocol

The delegate for PlaudWiFiAgent, used during WiFi Fast Transfer. Assign it before calling connectWifi(...). The handshake must complete (wifiHandshake with status 0) before listing or transferring files.
Swift
PlaudWiFiAgent.shared.delegate = self

extension DeviceManager: PlaudWiFiAgentProtocol {
    func wifiHandshake(_ status: Int) {
        guard status == 0 else { return }   // 0 = handshake done, ready to transfer
        // begin transfer
    }
}
All members are @objc optional.
CallbackDescription
wifiHandshake(_ status: Int)0 = handshake complete, ready to list/transfer
wifiConnectionStatus(_ ssid: String, _ connected: Bool)WiFi connection state changed
wifiFileList(_ files: [BleFile])Result of getFileList(...) over WiFi
wifiSyncFileData(_ sessionId:_ offset:_ count:_ binData:)A chunk of file data
wifiDataComplete()Single-file transfer finished
wifiDownloadAllProgress(_ totalFiles:_ currentFileIndex:_ currentFile:_ totalProgress:)Progress while downloading all files
wifiDownloadAllCompleted(_ completedFiles: Int, _ failedFiles: Int)Batch download finished
wifiCommonErr(_ cmd: Int, _ status: Int)A command failed
wifiClose(_ status: Int)WiFi transfer session closed
WiFi Fast Transfer requires the Hotspot Configuration entitlement in your app. See WiFi Fast Transfer for the full connect-and-transfer flow.