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

iOS 15中ShazamKit调用session.match(signature)无匹配且代理方法未触发问题求助

解决ShazamKit匹配无回调的问题

我仔细看了你的代码和问题描述,核心问题其实出在SHSession的生命周期上,另外还有几个细节可以优化,帮你一步步解决:

1. 最关键的问题:SHSession被提前释放了

你在recognizeSong方法里创建的SHSession是局部变量,当方法执行完毕后,ARC会立即释放这个session实例——这就导致后续的匹配请求还没完成,session就不存在了,自然不会触发didFind或didNotFindMatchFor代理方法。

解决方案:把SHSession改成ViewController的实例属性,让它的生命周期和VC保持一致:

class ViewController: UIViewController {
    // 改成实例变量,确保生命周期足够长
    private lazy var session: SHSession = {
        let session = SHSession()
        session.delegate = self
        return session
    }()
    
    // 其他代码不变...
}

然后在recognizeSong里直接用这个self.session,不要再重新创建局部的session。

2. 音频缓冲处理的优化

你计算frameCapacity的方式file.length / 26可能会导致读取的音频片段不完整,生成的signature有效时长不足,影响匹配结果。建议直接使用音频文件的完整长度来创建buffer:

// 替换原来的frameCapacity计算
let frameCapacity = AVAudioFrameCount(file.length)
guard let buffer = AVAudioPCMBuffer(pcmFormat: file.processingFormat, frameCapacity: frameCapacity) else {
    print("Failed to create a buffer")
    return
}
// 读取完整音频到buffer
try file.read(into: buffer)

另外,生成signature后可以打印它的时长,确认是否有效:

let signature = generator.signature()
print("Signature duration: \(signature.duration)") // 应该和音频文件时长接近
session.match(signature)

3. 完善代理方法的日志输出

即使没有匹配到歌曲,didNotFindMatchFor也应该输出日志,方便你确认方法是否被调用:

func session(_ session: SHSession, didNotFindMatchFor signature: SHSignature, error: Error?) {
    if let error = error {
        print("Match failed with error: \(error.localizedDescription)")
    } else {
        print("No matching song found, no error returned")
    }
}

4. 额外注意事项

  • 确保你的苹果开发者账号已经正确启用ShazamKit服务,并且App ID的配置和你测试用的App一致;
  • 测试用的音频文件要确保是完整的、音质清晰的歌曲片段(至少几秒以上,太短的话ShazamKit无法识别);
  • 因为你是处理沙盒内的音频文件,不需要申请麦克风权限,这点没问题,完全符合你司音乐播放器的需求。

修改后的完整代码示例:

import ShazamKit
import UIKit
import AVFoundation

class ViewController: UIViewController {
    private lazy var session: SHSession = {
        let session = SHSession()
        session.delegate = self
        return session
    }()
    
    lazy var recoButton: UIButton = {
        let button = UIButton(frame: CGRect(x: 0, y: 0, width: 120, height: 60))
        button.layer.cornerRadius = 8
        button.backgroundColor = .brown
        button.setTitle("Recognize", for: .normal)
        button.addTarget(self, action: #selector(recognizeSong), for: .touchUpInside)
        return button
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(recoButton)
        recoButton.center = view.center
    }
    
    @objc func recognizeSong(_ sender: UIButton) {
        print("reco button tapped")
        if #available(iOS 15, *) {
            do {
                guard let url = Bundle.main.url(forResource: "Baby One More Time", withExtension: "mp3") else {
                    print("Audio file not found")
                    return
                }
                let file = try AVAudioFile(forReading: url)
                let frameCapacity = AVAudioFrameCount(file.length)
                guard let buffer = AVAudioPCMBuffer(pcmFormat: file.processingFormat, frameCapacity: frameCapacity) else {
                    print("Failed to create audio buffer")
                    return
                }
                try file.read(into: buffer)
                
                let generator = SHSignatureGenerator()
                try generator.append(buffer, at: nil)
                let signature = generator.signature()
                print("Generated signature with duration: \(signature.duration)")
                
                session.match(signature)
            } catch {
                print("Error during recognition: \(error.localizedDescription)")
            }
        } else {
            let alert = UIAlertController(title: "Unsupported", message: "ShazamKit requires iOS 15 or later", preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: "OK", style: .default))
            present(alert, animated: true)
        }
    }
}

extension ViewController: SHSessionDelegate {
    func session(_ session: SHSession, didFind match: SHMatch) {
        print("Match found!")
        let items = match.mediaItems
        items.forEach { item in
            print("Title: \(item.title ?? "Unknown Title")")
            print("Artist: \(item.artist ?? "Unknown Artist")")
            print("Artwork URL: \(item.artworkURL?.absoluteString ?? "No Artwork")")
        }
    }
    
    func session(_ session: SHSession, didNotFindMatchFor signature: SHSignature, error: Error?) {
        if let error = error {
            print("Match failed with error: \(error.localizedDescription)")
        } else {
            print("No matching song found in Shazam's database")
        }
    }
}

按照上面的修改,你应该能正常触发代理方法,无论是匹配成功还是失败都会有对应的日志输出。

内容的提问来源于stack exchange,提问作者Zhou Haibo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 17:17:34