SFSpeechRecognizer è la principale API di riconoscimento vocale di Apple nell’ecosistema iOS. Il framework fornisce l’accesso al motore ASR del dispositivo attraverso Speech.framework, supportando la trascrizione in streaming in tempo reale e il riconoscimento una tantum di file audio. SFSpeechRecognizer è disponibile su iOS 10+, macOS 10.15+, watchOS 6+ e tvOS 17+. Con iOS 17, Apple ha aggiunto una modalità on-device completa che consente il riconoscimento vocale senza connessione Internet. Secondo Apple Speech Documentation, 2025, SFSpeechRecognizer è utilizzato in oltre 200.000 applicazioni App Store e processa milioni di richieste al giorno con un WER del 7% in inglese.
Punti chiave
SFSpeechRecognizer è una classe di Speech.framework che rappresenta un riconoscitore vocale per una lingua specifica. Viene inizializzata con un Locale (ru_RU, en_US, zh_CN). SFSpeechRecognizer gestisce una richiesta di riconoscimento (SFSpeechRecognitionRequest) e restituisce un risultato (SFSpeechRecognitionResult) con trascrizioni e metadati. Supporta due tipi di richieste: SFSpeechAudioBufferRecognitionRequest (flusso audio in diretta) e SFSpeechURLRecognitionRequest (file audio). Entrambi restituiscono SFTranscription — un array di ipotesi alternative di riconoscimento.
SFSpeechRecognitionResult contiene: bestTranscription (migliore ipotesi, SFTranscription), transcriptions (tutte le alternative), isFinal (finale/intermedio). SFTranscription contiene: formattedString (testo), segments (array di SFTranscriptionSegment con timestamp, confidenza, substringRange, alternativeSubstrings). La confidenza per ogni segmento (0..1) — consente di filtrare i frammenti inaffidabili. I segments sono una caratteristica chiave di Speech.framework: forniscono un markup parola per parola con punteggi di confidenza.
Architettura di SFSpeechRecognizer: AVFoundation (cattura audio) → Audio Buffer → SFSpeechAudioBufferRecognitionRequest → SFSpeechRecognizer (motore ASR) → SFSpeechRecognitionResult → SFSpeechRecognitionTask (controllo: cancel, finish, pause). Il motore ASR di Apple utilizza un’architettura ibrida: Conformer (encoder) + RNNT (decoder) per on-device, Transducer per il cloud. I modelli sono ottimizzati per Apple Neural Engine (ANE). Su A17 Pro, l’ASR on-device funziona con RTF 0.3–0.6 (più veloce del tempo reale).
| Componente | Scopo | Versione iOS |
|---|---|---|
| SFSpeechRecognizer | Classe principale di riconoscimento | iOS 10+ |
| SFSpeechAudioBufferRecognitionRequest | Flusso audio in diretta | iOS 10+ |
| SFSpeechURLRecognitionRequest | File audio (.wav, .m4a) | iOS 10+ |
| SFSpeechRecognitionTask | Gestione richieste (cancel, finish) | iOS 10+ |
| Riconoscimento on-device | ASR offline | iOS 17+ |
| Riconoscimento combinato | Ibrido on-device + cloud | iOS 17+ |
Requisiti audio: SFSpeechRecognizer accetta LPCM (16 kHz, 16 bit, mono) o Opus (iOS 17+). AVFoundation può catturare buffer di qualsiasi formato, la richiesta converte automaticamente. Lunghezza minima: 0.5 secondi (rilevamento silenzio). Massima: 1 minuto (cloud) / 2 minuti (on-device) per richiesta. Per trascrizioni lunghe, suddividere l’audio in chunk da 30–60 secondi con sovrapposizione di 2–5 secondi.
Autorizzazioni utente: SFSpeechRecognizer richiede due autorizzazioni esplicite. NSMicrophoneUsageDescription (Privacy — Microphone Usage Description) — per l’accesso al microfono. NSSpeechRecognitionUsageDescription (Privacy — Speech Recognition Usage Description) — per l’accesso al riconoscimento vocale. Entrambe sono stringhe che spiegano il motivo all’utente. SFSpeechRecognizer.requestAuthorization — mostra il dialogo delle autorizzazioni. Stati: notDetermined, denied, restricted, authorized. Senza lo stato authorized, chiamare il recognizer restituisce l’errore 216 (Speech framework error).
Verifica disponibilità: SFSpeechRecognizer.isAvailable — verifica se ASR è disponibile per la lingua corrente. Su iOS 16-, isAvailable = false senza Internet. Su iOS 17+, isAvailable = true per le lingue on-device anche offline. SFSpeechRecognizer.supportedLocales — metodo statico per ottenere l’elenco delle lingue supportate dal dispositivo. Si consiglia di verificare isAvailable prima di ogni avvio (l’utente potrebbe disabilitare Siri/Dettatura nelle impostazioni). La disponibilità dipende dalla regione: cinese — solo in Cina, arabo — negli EAU.
// Configurazione di SFSpeechRecognizer
import Speech
SFSpeechRecognizer.requestAuthorization { status in
guard status == .authorized else { return }
}
let recognizer = SFSpeechRecognizer(locale: Locale(identifier: "ru_RU"))!
guard recognizer.isAvailable else {
print("ASR non disponibile. Abilita Siri e Dettatura nelle Impostazioni")
return
}
let request = SFSpeechAudioBufferRecognitionRequest()
request.requiresOnDeviceRecognition = true
Gestione degli errori: SFSpeechRecognizer viene chiamato con un completion handler che può restituire un Error. Errori principali: 203 — nessun Internet (cloud, iOS 16-); 216 — non autorizzato (nessun permesso); 301 — errore audio (problema microfono/formato); 401 — servizio non disponibile (servizio sovraccarico); 601 — lingua non disponibile (lingua non supportata sul dispositivo). Per on-device iOS 17+, errori principali: 301 (audio), 601 (lingua). Gestire sempre il completion handler — gli errori possono verificarsi in qualsiasi momento durante la registrazione.
Pipeline ASR in diretta: AVAudioEngine (cattura microfono) → installTap (buffer audio) → request.append(buffer) → SFSpeechRecognizer → recognitionTask → delegate/resultHandler. AVAudioEngine offre bassa latenza (5–10 ms dal microfono al buffer). SFSpeechRecognitionDelegate: didHypothesizeTranscription (ogni 200–500 ms — testo parziale), didFinishRecognition (risultato finale). Task.isFinishing — può annullare quando il riconoscimento è completo. Per il riconoscimento continuo (dettatura infinita), creare una nuova attività dopo isFinal.
SFSpeechRecognitionTaskDelegate: metodi opzionali. speechRecognitionDidDetectSpeech (inizio discorso) — per indicazione nell’interfaccia utente. didHypothesizeTranscription (testo intermedio) — per visualizzazione mentre si parla. didFinishRecognition (risultato finale) — per finalizzare il testo. didFinishSuccessfully (successo/errore) — per completamento. didProcessAudio (buffer audio elaborato) — per misuratore RMS. Si consiglia di implementare didHypothesizeTranscription — l’utente vede il testo immediatamente senza ritardo. La trascrizione finale è per il salvataggio.
// Riconoscimento vocale in diretta
let audioEngine = AVAudioEngine()
let request = SFSpeechAudioBufferRecognitionRequest()
request.shouldReportPartialResults = true
recognitionTask = recognizer.recognitionTask(with: request) { result, error in
if let result = result {
textView.text = result.bestTranscription.formattedString
}
if error != nil || result?.isFinal == true {
audioEngine.stop()
request.endAudio()
}
}
let inputNode = audioEngine.inputNode
let recordingFormat = inputNode.outputFormat(forBus: 0)
inputNode.installTap(onBus: 0, bufferSize: 1024,
format: recordingFormat) { buffer, _ in
request.append(buffer)
}
audioEngine.prepare()
try audioEngine.start()
Riconoscimento continuo: per la modalità “ascolta sempre” (input vocale, assistente), è necessario riavviare l’attività dopo isFinal. Creare un ciclo: finishTask → request = SFSpeechAudioBufferRecognitionRequest() → recognitionTask = recognizer.recognitionTask(with: request). Per evitare pause, sovrapporre la fine di un’attività con l’inizio della successiva (avviare una nuova richiesta 1–2 secondi prima della fine della precedente). AVFoundation AVAudioSession — configurare .playAndRecord per riproduzione e registrazione simultanee. Su iOS 17+, l’ASR continuo con on-device consuma 2–5% di batteria all’ora (A15+).
SFSpeechURLRecognitionRequest — una richiesta per riconoscere un file audio tramite URL. Supporta i formati: .wav (16 kHz, 16 bit, mono), .m4a (AAC), .mp4, .mov. Lunghezza massima: ~1 minuto per il cloud, ~2 minuti per on-device. Per file più lunghi, suddividere in chunk (AVAssetExportSession + trim). SFSpeechURLRecognitionRequest non supporta lo streaming (nessun risultato parziale) — solo il risultato finale. Per risultati parziali con un file, convertire in una richiesta di buffer audio.
Ottenere la trascrizione di un file audio: SFSpeechRecognizer.recognitionTask(with: request) resultHandler. Estrarre bestTranscription.formattedString. Per timestamp a livello di parola — segments da bestTranscription.segments (segment.duration, segment.timestamp, segment.substring). Confidenza per segmento — confidenza ASR per ogni parola (usare per filtrare). Ipotesi alternative — alternative di transcriptionFormatter per parole con bassa confidenza. Per file con più parlanti, SFSpeechRecognitionRequest può restituire più richieste (una per parlante, iOS 17+).
// Trascrizione file audio
let audioURL = Bundle.main.url(forResource: "recording", withExtension: "m4a")!
let request = SFSpeechURLRecognitionRequest(url: audioURL)
request.requiresOnDeviceRecognition = true
recognizer.recognitionTask(with: request) { result, error in
guard let result = result, error == nil else {
print("Errore: \(error?.localizedDescription ?? "unknown")")
return
}
let transcription = result.bestTranscription
let text = transcription.formattedString
let words = transcription.segments.map { segment in
Word(text: segment.substring,
start: segment.timestamp,
duration: segment.duration,
confidence: segment.confidence)
}
}
Suddivisione di file audio lunghi: per file > 1 minuto, suddividere in chunk da 30–60 secondi con sovrapposizione di 2–3 secondi (cucitura). AVAssetExportSession + CMTimeRange — esportare chunk. Alternativa: UISelectionView (l’utente seleziona un segmento). Cucitura delle trascrizioni: concatenare testi, cucire per sovrapposizione (le ultime 2–3 parole del chunk precedente vengono confrontate con le prime 2–3 del successivo — rimuovere duplicati). Vosk e Whisper supportano l’audio lungo nativamente, SFSpeechRecognizer no. Per trascrizioni lunghe, consiglio Whisper (Core ML) — nessun limite di lunghezza.
Modalità On-device (iOS 17+): request.requiresOnDeviceRecognition = true. L’ASR viene eseguito localmente su Apple Neural Engine (ANE). Vantaggi: nessun Internet necessario, privacy (l’audio non lascia mai il dispositivo), costo zero (gratuito), bassa latenza (RTF 0.3–0.6). Svantaggi: precisione inferiore (WER 12–14% vs 7–12%), limite di 2 minuti per richiesta, set linguistico limitato (non tutte le 60 lingue sono disponibili on-device). Il modello on-device occupa ~50–100 MB sul dispositivo e viene scaricato alla prima richiesta.
Cloud (iOS 16-): request.requiresOnDeviceRecognition = false (o parametro assente). ASR sui server Apple — più preciso (WER 7% EN, 12% RU), più lingue, fino a 1 minuto per richiesta. Richiede Internet (WiFi o cellulare). Apple non addebita costi agli sviluppatori per l’ASR cloud (gratuito). Limiti: 1 richiesta al minuto per applicazione (non specificato), ma Apple potrebbe limitare a scala di produzione. L’ASR cloud fornisce qualità best-effort senza SLA. Per applicazioni aziendali, utilizzare Google Cloud ASR o Whisper (Core ML).
| Parametro | On-device (iOS 17+) | Cloud (iOS 10+) |
|---|---|---|
| Richiede Internet | No | Sì |
| WER (EN) | 10–12% | 7% |
| WER (RU) | 12–14% | 12% |
| Latenza (RTF) | 0.3–0.6 | 0.3–0.8 (+rete) |
| Lunghezza max | 2 minuti | 1 minuto |
| Privacy | Completa | L’audio lascia il dispositivo |
| Gratuito | Sì | Sì |
Riconoscimento combinato (iOS 17+): request.requiresOnDeviceRecognition = false con Internet (cloud), = true in offline (fallback). Apple seleziona automaticamente la modalità. Per app critiche per la precisione: verificare NetworkMonitor (NWPathMonitor) — utilizzare cloud con Internet, on-device senza. Per app critiche per la privacy: sempre on-device. Per trascrizione: cloud (più preciso). Per input vocale: on-device (più veloce). Si consiglia Combinato: 80% cloud, 20% fallback on-device.
Input vocale in tastiera personalizzata — SFSpeechRecognizer integrato nelle estensioni tastiera (iOS 10+). L’utente preme il pulsante microfono, ASR trascrive la voce in testo e lo inserisce nel campo di testo. Requisiti: risultati parziali (vedere il testo in tempo reale), on-device (la tastiera deve funzionare senza Internet). SFSpeechRecognizer + AVSpeechSynthesizer — input vocale + output vocale. Per tastiere personalizzate su iOS 17+, utilizzare on-device. Limitazioni dell’estensione tastiera: AVAudioEngine è disponibile ma con restrizioni di tempo (esecuzione in background limitata).
Trascrizione di riunioni e lezioni — app per registrare e trascrivere audio (Otter.ai, Rev, Apple Voice Memos). SFSpeechURLRecognitionRequest elabora file .m4a. Per registrazioni lunghe (30–60 minuti) — Whisper Core ML (nessun limite di lunghezza). I segments di SFSpeechRecognizer con timestamp — per sincronizzare il testo con l’audio (evidenziazione del testo durante la riproduzione). Confidenza per segmento — per visualizzare frammenti inaffidabili (evidenziazione gialla). Per la diarizzazione dei parlanti (chi ha parlato) — Apple non fornisce API, utilizzare pyannote-audio + Whisper sul server.
Comandi vocali nelle app iOS — SFSpeechRecognizer + framework VGS (Voice Grammar Services) per eseguire comandi: “apri impostazioni”, “invia messaggio”, “accendi la luce”. Riconoscimento basato su grammatica: SFSpeechRecognitionRequest contextualStrings = array di comandi. Ciò migliora la precisione del riconoscimento dei comandi al 95% (vs 85% in forma libera). SFSpeechRecognitionTask.cancel — per interrompere dopo l’esecuzione del comando. VGS + SFSpeechRecognizer + Shortcuts — comandi vocali personalizzati senza scrivere interfaccia utente. Per accessibilità: Voice Control (integrato) + SFSpeechRecognizer (comandi personalizzati).
// Comandi vocali con stringhe contestuali
let request = SFSpeechAudioBufferRecognitionRequest()
request.requiresOnDeviceRecognition = true
request.shouldReportPartialResults = true
request.contextualStrings = ["open contacts", "send message",
"show notifications", "accendi la torcia"]
recognitionTask = recognizer.recognitionTask(with: request) { result, _ in
guard let text = result?.bestTranscription.formattedString.lowercased() else { return }
voiceCommands.first { text.contains($0) }.map { command in
DispatchQueue.main.async { self.executeCommand(command) }
recognitionTask?.cancel()
}
}
Dettatura in app mediche e legali — SFSpeechRecognizer per creare documenti strutturati tramite voce. Adattamento di dominio: contextualStrings con termini medici/legali (500+ frasi). SFSpeechRecognitionRequest.customLmProbability — impatto di contextualStrings (0.1–1.0). Per la dettatura medica, utilizzare on-device (privacy dei dati del paziente). Whisper ottimizzato su dati medici — alternativa con WER 5% invece del 12% di SFSpeechRecognizer base. Conformità HIPAA: modalità on-device (i dati non lasciano mai il dispositivo). Per trascrizione appuntamenti — SFSpeechURLRecognitionRequest + segments con timestamp del parlante.
Domande frequenti
SFSpeechRecognizer è disponibile da iOS 10, macOS 10.15, watchOS 6 e tvOS 17. La modalità on-device da iOS 17 (requiresOnDeviceRecognition). Su iOS 10–16, SFSpeechRecognizer funziona solo attraverso i server cloud di Apple (richiede Internet). Tutte le versioni richiedono l’autorizzazione esplicita dell’utente (NSMicrophoneUsageDescription + NSSpeechRecognitionUsageDescription). SFSpeechRecognizer.supportedLocales — elenco dinamico, dipende dalla regione e dal modello del dispositivo.
Sì, creando nuovi recognitionTask dopo isFinal. Riavviare l’attività dopo il completamento della precedente per il riconoscimento continuo. Su iOS 17, l’ASR continuo on-device consuma 2–5% di batteria all’ora (A15+). Su iOS 16-, l’ASR continuo richiede Internet (traffico ~1 MB/minuto). Per il riconoscimento veramente continuo (sempre in ascolto), utilizzare Vosk (offline) o Whisper Core ML. SFSpeechRecognizer non supporta la modalità sempre accesa su iOS 16-.
Utilizzare result.bestTranscription.segments — ogni SFTranscriptionSegment contiene confidence (Float 0..1) per la parola. segments[i].substring — testo della parola. segments[i].confidence — confidenza ASR per quella parola. Le parole con confidence < 0.5 sono inaffidabili — evidenziarle nell’interfaccia utente. segments[i].timestamp — tempo di inizio (TimeInterval). segments[i].duration — durata. segments[i].alternativeSubstrings — ipotesi alternative di riconoscimento per la parola. Per file lunghi, l’iterazione su segments fornisce confidenza per parola senza analisi manuale.
203 è SFSpeechError.ErrorCode.opportunistic (nessun Internet per ASR cloud). Si verifica su iOS 16- o quando request.requiresOnDeviceRecognition = false senza Internet. Soluzione: impostare requiresOnDeviceRecognition = true (iOS 17+) per il funzionamento offline. Su iOS 16-, utilizzare NWPathMonitor — quando non c’è Internet, visualizzare un messaggio che dice “il riconoscimento vocale richiede una connessione Internet”. Alternativa: Vosk (offline, iOS 12+) come fallback quando non è disponibile alcuna rete.
SFSpeechRecognizer — API integrata di Apple, gratuita, facile da integrare, ma con limiti di lunghezza (1–2 minuti), precisione WER 7–14% e solo per l’ecosistema iOS. Whisper Core ML — open-source (MIT), supporta 99 lingue, WER 6–10%, nessun limite di lunghezza, ma richiede integrazione manuale, modelli Core ML (39M–769M parametri), RTF 0.5–6 (più lento di SFSpeechRecognizer). SFSpeechRecognizer — per input vocale standard. Whisper — per trascrizione di alta precisione di audio lungo.
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche