You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

应用终止前获取AVAudioRecorder录音URL失败的问题咨询

解决滑动关闭APP时录音代理未触发的问题

我太懂你这个困扰了——明明在applicationWillTerminate里调用了stop(),但audioRecorderDidFinishRecording和错误代理就是死活不执行,连录音URL都拿不到。之前做语音笔记APP时我也踩过这个坑,核心问题其实和系统的异步回调机制有关,咱们来一步步解决:

问题根源

AVAudioRecorder的stop()方法是异步触发代理回调的,而applicationWillTerminate的5秒窗口期看似充裕,但系统可能在代理回调执行前就直接终止了APP进程,导致代理代码根本没机会运行。

解决方案:放弃等待代理,主动控制录音收尾

与其依赖不可靠的代理回调,不如提前规划录音文件路径,在APP终止时直接处理预存的文件路径,同时用后台任务争取更多执行时间。

修改后的代码示例

import AVFoundation
import UIKit

class RecorderManager: NSObject, AVAudioRecorderDelegate {
    var micRecorder: AVAudioRecorder?
    var recordingURL: URL? // 提前保存录音文件的URL
    private var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid
    
    override init() {
        super.init()
        setupNotificationObserver()
    }
    
    private func setupNotificationObserver() {
        NotificationCenter.default.addObserver(
            self,
            selector: #selector(applicationWillTerminate(notification:)),
            name: UIApplication.willTerminateNotification,
            object: nil
        )
    }
    
    // 启动录音时就确定并保存文件URL
    func startRecording() {
        guard let documentsDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
            print("无法获取文档目录")
            return
        }
        // 生成唯一的录音文件名,避免覆盖
        let timestamp = Date().timeIntervalSince1970
        recordingURL = documentsDir.appendingPathComponent("recording_\(timestamp).m4a")
        
        let audioSettings: [String: Any] = [
            AVFormatIDKey: Int(kAudioFormatMPEG4AAC),
            AVSampleRateKey: 44100.0,
            AVNumberOfChannelsKey: 1,
            AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue
        ]
        
        do {
            micRecorder = try AVAudioRecorder(url: recordingURL!, settings: audioSettings)
            micRecorder?.delegate = self
            micRecorder?.prepareToRecord()
            micRecorder?.record()
        } catch {
            print("录音初始化失败:\(error.localizedDescription)")
            recordingURL = nil
        }
    }
    
    @objc private func applicationWillTerminate(notification: Notification) {
        guard let recorder = micRecorder, recorder.isRecording else { return }
        
        // 启动后台任务,告诉系统"我还有收尾工作没做完"
        backgroundTaskID = UIApplication.shared.beginBackgroundTask(withName: "FinishRecording") { [weak self] in
            // 超时后强制结束后台任务
            UIApplication.shared.endBackgroundTask(self?.backgroundTaskID ?? .invalid)
            self?.backgroundTaskID = .invalid
        }
        
        // 停止录音
        recorder.stop()
        
        // 不等代理,直接用预存的URL处理文件
        if let url = recordingURL, FileManager.default.fileExists(atPath: url.path) {
            saveRecordingToCoreData(url: url)
            print("APP终止时成功保存录音:\(url)")
        } else {
            print("录音文件不存在,保存失败")
        }
        
        // 手动结束后台任务
        if backgroundTaskID != .invalid {
            UIApplication.shared.endBackgroundTask(backgroundTaskID)
            backgroundTaskID = .invalid
        }
    }
    
    // 正常录音结束时的代理回调(依然保留,处理非终止场景)
    func audioRecorderDidFinishRecording(_ recorder: AVAudioRecorder, successfully flag: Bool) {
        if flag {
            saveRecordingToCoreData(url: recorder.url)
        } else {
            print("正常录音结束失败")
        }
    }
    
    func audioRecorderEncodeErrorDidOccur(_ recorder: AVAudioRecorder, error: Error?) {
        if let error = error {
            print("录音编码错误:\(error.localizedDescription)")
        }
    }
    
    // 封装CoreData保存逻辑
    private func saveRecordingToCoreData(url: URL) {
        // 这里实现你的CoreData保存逻辑,比如将URL路径转成字符串存储
        // 示例:
        // let recordingEntity = RecordingEntity(context: persistentContainer.viewContext)
        // recordingEntity.filePath = url.path
        // try? persistentContainer.viewContext.save()
    }
}

关键优化点

  1. 提前保存录音URL:在启动录音时就生成并存储文件路径,避免依赖代理返回的URL
  2. 使用后台任务:通过beginBackgroundTask向系统申请额外的执行时间,确保文件保存完成
  3. 主动处理文件:APP终止时直接用预存URL操作文件,不再等待异步代理回调
  4. 保留原有代理:正常场景下(用户主动停止录音),代理依然可以正常工作

内容的提问来源于stack exchange,提问作者Lance Samaria

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 06:48:39