The best place to initialize the SDK is within your AppDelegate or in a dedicated singleton manager class. This ensures it’s configured once when your app starts.
Optional extra parameters (e.g., language, customDomain)
partnerToken
String
❌
User-level access token from Partner API
Device-specific authentication:
NotePro / NotePins: Use partnerToken for authentication. For appKey/appSecret/bindToken, you can pass any non-empty placeholder value (e.g., “placeholder”)
About partnerToken:
The partnerToken is a user-level access token obtained from the Partner API. Each token is associated with a specific end-user in your application.
Copy
Ask AI
import UIKit// In your AppDelegate or a central manager classclass YourAppManager { // Hold a strong reference to the device agent var deviceAgent: PlaudDeviceAgent? // Initialize with appKey/appSecret (for older Note/NotePin firmware) func initializeWithAppKey() { let agent = PlaudDeviceAgent.shared() agent.delegate = self agent.initSDK( hostName: "YourAppName", appKey: "YOUR_APP_KEY", appSecret: "YOUR_APP_SECRET", bindToken: "YOUR_BIND_TOKEN", extra: [:], partnerToken: nil ) self.deviceAgent = agent } // Initialize with partnerToken (for NotePro, NotePins, and newer Note/NotePin firmware) func initializeWithPartnerToken() { let agent = PlaudDeviceAgent.shared() agent.delegate = self agent.initSDK( hostName: "YourAppName", appKey: "placeholder", // Can be any non-empty value appSecret: "placeholder", // Can be any non-empty value bindToken: "placeholder", // Can be any non-empty value extra: [:], partnerToken: "YOUR_PARTNER_TOKEN" ) self.deviceAgent = agent }}
To receive events from the SDK, you must implement the PlaudDeviceAgentDelegate protocol. This protocol provides feedback on everything from connection status to recording events.
It’s best practice to make your central manager class or a relevant view controller conform to this delegate protocol.
Copy
Ask AI
import Foundationimport PlaudDeviceBasicSDK // For BleDevice, BleFile typesimport PenBleSDK@objc public protocol PlaudDeviceAgentDelegate: AnyObject { // MARK: - Initialization & Connection /// Called with the result of the AppKey verification. @objc optional func plaud(didVerifyAppKeyWith result: Int) /// Reports the Bluetooth connection state. @objc optional func plaud(didUpdateConnectionState state: Int) /// Callback for the device binding (pairing) process. @objc optional func plaud(didBindDevice sn: String?, status: Int, protVersion: Int, timezone: Int) /// Unbind result. @objc optional func plaud(didUnbind status: Int) // MARK: - Device Discovery /// Called when Bluetooth devices are discovered during a scan. @objc optional func plaud(didDiscover devices: [BleDevice]) /// Called when the device scan times out. @objc optional func plaudDidTimeoutScan() // MARK: - Device Status /// Provides the current state of the PLAUD device. @objc optional func plaud(deviceDidUpdateState state: Int, privacy: Int, keyState: Int, uDisk: Int, findMyToken: Int, hasSndpKey: Int, deviceAccessToken: Int) /// Provides the device's name. @objc optional func plaud(didReceiveDeviceName name: String?) /// Reports the device's storage capacity. @objc optional func plaud(didReceiveStorageInfo total: Int, free: Int, duration: Int) /// Reports a change in the device's battery level. @objc optional func plaud(didUpdateBatteryLevel power: Int, oldPower: Int) /// Reports the device's charging status. @objc optional func plaud(didUpdateChargingState isCharging: Bool, level: Int) /// Provides the microphone's current gain value. @objc optional func plaud(didReceiveMicGain value: Int) // MARK: - Recording Control /// Confirms that recording has started. @objc optional func plaud(didStartRecordingWithSessionId sessionId: Int, start: Int, status: Int, scene: Int, startTime: Int, reason: Int) /// Confirms that recording has stopped. @objc optional func plaud(didStopRecordingWithSessionId sessionId: Int, reason: Int, fileExist: Bool, fileSize: Int) /// Confirms that recording has been paused. @objc optional func plaud(didPauseRecordingWithSessionId sessionId: Int, reason: Int, fileExist: Bool, fileSize: Int) /// Confirms that a paused recording has resumed. @objc optional func plaud(didResumeRecordingWithSessionId sessionId: Int, start: Int, status: Int, scene: Int, startTime: Int) // MARK: - File Management /// Provides the list of files stored on the device. @objc optional func plaud(didReceiveFileList files: [BleFile]) /// Reports the result of a file deletion attempt. @objc optional func plaud(didDeleteFileWithSessionId sessionId: Int, status: Int) // MARK: - Data Transfer (Download) /// Indicates the start of a file download. @objc optional func plaud(didStartSyncingFileHead sessionId: Int, status: Int) /// Indicates the end of a file download. @objc optional func plaud(didFinishSyncingFileTail sessionId: Int, crc: Int) /// Delivers chunks of file data during a download. @objc optional func plaud(didReceiveDataChunk sessionId: Int, start: Int, data: Data) /// Reports download progress for a composite file. @objc optional func plaud(didDownloadFile sessionId: Int, desiredOutputPath: String, status: Int, progress: Int, tips: String) /// Called when a file download is manually stopped. @objc optional func plaudDidStopDownloadingFile() // MARK: - Wi-Fi Configuration /// Reports the result of setting a Wi-Fi configuration. @objc optional func plaud(didSetConfigForWifiSync result: Int) /// Provides the list of saved Wi-Fi networks. @objc optional func plaud(didReceiveWifiSyncList list: [UInt32]) /// Reports the result of a Wi-Fi connection test. @objc optional func plaud(didReceiveWifiTestResult index: UInt32, result: Int, rawCode: Int) // MARK: - Firmware Updates (OTA) /// Reports the result of a firmware update (OTA). @objc optional func plaud(didFinishOtaWithResult uid: Int, status: Int, errmsg: String?) /// The device is requesting a specific chunk of the firmware file. @objc optional func plaud(deviceDidRequestOtaPacket uid: Int, start: Int, end: Int)}
To discover nearby PLAUD devices, start a scan. The results will be delivered to the plaud(didDiscover:) delegate method.
Copy
Ask AI
// Get the shared agent instanceguard let deviceAgent = self.deviceAgent else { return }// Start scanning for devicesdeviceAgent.startScan()// Implement the delegate method in your class to receive the results// extension YourViewController: PlaudDeviceAgentDelegate {// func plaud(didDiscover devices: [BleDevice]) {// // Sort devices by signal strength (strongest first)// let sortedDevices = devices.sorted { $0.rssi > $1.rssi }// // Update your UI with the sorted list of devices// self.discoveredDevices = sortedDevices// self.tableView.reloadData()// print("Discovered devices: \(sortedDevices.map { $0.name ?? "Unknown" })")// }// }
Once a device has been discovered, you can connect to it using its BleDevice object.
Copy
Ask AI
// Assume `selectedDevice` is a `BleDevice` object from the scan resultsfunc connect(to device: BleDevice) { guard let deviceAgent = self.deviceAgent else { return } deviceAgent.connect(device)}// Implement the delegate method to handle connection state changes// func plaud(didUpdateConnectionState state: Int) {// let message: String// switch state {// case 0:// message = "Device disconnected or failed to connect."// case 1:// message = "Device connected successfully!"// case 2:// message = "Device connection failed."// default:// message = "Unknown connection state."// }// print(message)// // Update your UI to reflect the new connection status// }
Retrieve the list of recording files stored on the device.
Copy
Ask AI
guard let deviceAgent = self.deviceAgent else { return }// Get all files (startSessionId = 0)deviceAgent.getFileList(startSessionId: 0)// Get files after a specific sessionIddeviceAgent.getFileList(startSessionId: 1234567890)// Get a single file by sessionIddeviceAgent.getFile(sessionId: 1234567890)// Implement the delegate method to receive the file list// func plaud(didReceiveFileList files: [BleFile]) {// for file in files {// print("File: sessionId=\(file.sessionId), size=\(file.fileSize)")// }// }
Send a command to the connected device to begin recording.
Copy
Ask AI
guard let deviceAgent = self.deviceAgent else { return }deviceAgent.startRecord()// Implement the delegate method to confirm recording has started// func plaud(didStartRecordingWithSessionId sessionId: Int, status: Int, ...) {// if status == 0 {// print("Recording started successfully with session ID: \(sessionId)")// } else {// print("Failed to start recording. Status code: \(status)")// }// // Update your recording UI// }
Export a recording file to a specified format. This method handles downloading from device, E2EE decryption (if needed), and format conversion automatically.
Export a recording file using Wi-Fi Fast Transfer for faster download speeds.
The API signature is identical to exportAudio, making it easy to switch between BLE and Wi-Fi transfer channels.
Prerequisites: Wi-Fi must be connected and handshake completed before calling this method. See the Wi-Fi Fast Transfer section below for connection setup.
Wi-Fi Fast Transfer enables high-speed file transfer between the Plaud device and your app via the device’s built-in Wi-Fi hotspot.
Wi-Fi Fast Transfer requires the PenWiFiSDK module (already included in import PenWiFiSDK above).
Ensure the device is connected via Bluetooth before initiating Wi-Fi Fast Transfer.
On iOS 13+, location permission (NSLocationWhenInUseUsageDescription) is required to detect the current Wi-Fi SSID.
After the device is connected via Bluetooth, enable its Wi-Fi hotspot:
Copy
Ask AI
// Ensure Bluetooth is connected firstguard PlaudDeviceAgent.shared().isConnected() else { print("Bluetooth not connected") return}// Open the device Wi-Fi hotspotPlaudDeviceAgent.shared().setDeviceWiFi(open: true)
Receive the hotspot credentials in the PlaudDeviceAgentProtocol delegate:
Copy
Ask AI
/// Device Wi-Fi hotspot opened callback/// - Parameters:/// - status: 0 = success, 1 = recording in progress, 2 = USB disk mode active/// - wifiName: Device hotspot SSID/// - wholeName: Full device name (with SN suffix)/// - wifiPass: Device hotspot passwordfunc bleWiFiOpen(_ status: Int, _ wifiName: String, _ wholeName: String, _ wifiPass: String) { if status == 0 { // Pass the BLE device reference to WiFi agent PlaudWiFiAgent.shared.bleDevice = BleAgent.shared.bleDevice // Proceed to connect WiFi connectToDeviceWiFi(wifiName, wifiPass) }}
// Check if Wi-Fi is connectedlet connected = PlaudWiFiAgent.shared.isConnected// Check if currently downloading a filelet downloading = PlaudWiFiAgent.shared.isDownloading// Get current download speed (KB/s)let speedKBps = PlaudWiFiAgent.shared.currentDownloadSpeedKBps// Get formatted download speed string (e.g., "1.5 MB/s" or "500.0 KB/s")let speedString = PlaudWiFiAgent.shared.getFormattedDownloadSpeed()// Get current connected Wi-Fi namelet wifiName = PlaudWiFiAgent.shared.getCurrentWiFiName()// Check WebSocket connection statuslet wsConnected = PlaudWiFiAgent.shared.isWebSocketConnected()
Prerequisite: Wi-Fi must be connected and handshake completed. See Wi-Fi Fast Transfer above.
Copy
Ask AI
// Delete a recording file on the devicePlaudWiFiAgent.shared.deleteFile(bleFile.sessionId)// Delete result callbackfunc wifiFileDelete(_ sessionId: Int, _ status: Int) { // status 0 = deleted successfully}
After Wi-Fi file transfer is complete, the device will automatically close its Wi-Fi hotspot after approximately 15 seconds of inactivity. You should handle this transition by disconnecting from the hotspot and reconnecting via BLE.
Do not call PlaudWiFiAgent.shared.disconnect() directly. This may cause certain device models to enter an abnormal state. Use NEHotspotConfigurationManager to disconnect from the hotspot instead.
Copy
Ask AI
import NetworkExtension// Step 1: Remove the Wi-Fi hotspot configuration to disconnect the phone from the device hotspotif #available(iOS 11.0, *) { NEHotspotConfigurationManager.shared.removeConfiguration(forSSID: wifiName)}// Step 2: Wait ~15 seconds for the device to close Wi-Fi and resume BLE advertisingDispatchQueue.main.asyncAfter(deadline: .now() + 15.0) { // Step 3: Start a BLE scan to find the device PlaudDeviceAgent.shared().startScan()}// Step 4: In the scan callback, find the target device by serial number and reconnect// func bleScanResult(bleDevices: [BleDevice]) {// for device in bleDevices {// if device.serialNumber == targetSerialNumber {// PlaudDeviceAgent.shared().stopScan()// PlaudDeviceAgent.shared().connectBleDevice(bleDevice: device)// return// }// }// }
After Wi-Fi transfer, you must perform a BLE scan and use the newly discovered BleDevice object to reconnect. Do not reuse the BleDevice object from before the Wi-Fi transfer.