You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
8.9 KiB
8.9 KiB
重新扫描后无法扫描问题修复说明
🚨 问题描述
用户反馈按重新扫描按钮返回扫描后,存在扫描不了的问题。即重新扫描后,相机无法继续检测二维码。
🔍 问题分析
1. 会话状态管理问题
metadataOutput
方法中调用stopScanning()
后,会话被停止- 重新扫描时,会话可能没有正确重启
- 缺少会话状态的验证和错误处理
2. 时序问题
- 延迟时间过短(0.1秒),可能导致会话重启失败
- 没有等待会话完全停止就开始重启
- 缺少会话状态的检查机制
3. 错误处理缺失
- 没有检查会话是否真的在运行
- 缺少会话启动失败的重试机制
- 没有提供详细的调试信息
🛠️ 修复方案
1. 优化会话重启逻辑
改进 restartScanning()
方法
func restartScanning() {
logInfo("🔄 重新开始扫描", className: "ScannerViewModel")
// 确保在主线程执行UI相关操作
DispatchQueue.main.async { [weak self] in
guard let self = self else { return }
// 先停止当前会话
if self.captureSession?.isRunning == true {
logInfo("🔄 停止当前运行的扫描会话", className: "ScannerViewModel")
self.captureSession?.stopRunning()
}
// 重置检测状态
self.detectedCodes = []
// 延迟后重新启动会话(增加延迟时间)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
guard let self = self else { return }
logInfo("🔄 准备重新启动扫描会话", className: "ScannerViewModel")
// 在后台线程启动会话
DispatchQueue.global(qos: .userInitiated).async {
self.captureSession?.startRunning()
// 检查会话状态
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
if self.captureSession?.isRunning == true {
logInfo("✅ 扫描会话已成功重新启动", className: "ScannerViewModel")
} else {
logWarning("⚠️ 扫描会话启动失败,尝试重新启动", className: "ScannerViewModel")
// 如果启动失败,再次尝试
DispatchQueue.global(qos: .userInitiated).async {
self.captureSession?.startRunning()
DispatchQueue.main.async {
if self.captureSession?.isRunning == true {
logInfo("✅ 扫描会话第二次尝试启动成功", className: "ScannerViewModel")
} else {
logError("❌ 扫描会话启动失败", className: "ScannerViewModel")
}
}
}
}
}
}
}
}
}
2. 增强会话状态管理
添加会话状态检查方法
func isSessionRunning() -> Bool {
return captureSession?.isRunning == true
}
func checkSessionStatus() {
let isRunning = captureSession?.isRunning == true
logInfo("📊 扫描会话状态检查: \(isRunning ? "运行中" : "已停止")", className: "ScannerViewModel")
if !isRunning {
logWarning("⚠️ 扫描会话未运行,尝试重新启动", className: "ScannerViewModel")
startScanning()
}
}
改进 startScanning()
方法
func startScanning() {
logInfo("🔄 开始扫描", className: "ScannerViewModel")
// 检查会话是否已经在运行
if captureSession?.isRunning == true {
logInfo("ℹ️ 扫描会话已经在运行", className: "ScannerViewModel")
return
}
DispatchQueue.global(qos: .userInitiated).async { [weak self] in
guard let self = self else { return }
self.captureSession?.startRunning()
// 检查启动状态
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
if self.captureSession?.isRunning == true {
logInfo("✅ 扫描会话启动成功", className: "ScannerViewModel")
} else {
logWarning("⚠️ 扫描会话启动失败", className: "ScannerViewModel")
}
}
}
}
改进 stopScanning()
方法
func stopScanning() {
logInfo("🔄 停止扫描", className: "ScannerViewModel")
// 检查会话是否在运行
if captureSession?.isRunning == true {
DispatchQueue.global(qos: .userInitiated).async { [weak self] in
self?.captureSession?.stopRunning()
DispatchQueue.main.async {
logInfo("✅ 扫描会话已停止", className: "ScannerViewModel")
}
}
} else {
logInfo("ℹ️ 扫描会话已经停止", className: "ScannerViewModel")
}
}
3. 增强重新扫描流程
改进 resetToScanning()
方法
private func resetToScanning() {
logInfo("🔄 ScannerView 开始重置到扫描状态", className: "ScannerView")
// 重置UI状态
showPreviewPause = false
// 重置扫描状态并重新开始
scannerViewModel.resetDetection()
scannerViewModel.restartScanning()
// 延迟检查会话状态
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
logInfo("🔍 检查扫描会话状态", className: "ScannerView")
self.scannerViewModel.checkSessionStatus()
}
logInfo("✅ ScannerView 已重置到扫描状态", className: "ScannerView")
}
4. 添加调试功能
调试按钮
在 DEBUG 模式下添加会话状态检查按钮:
// 调试按钮:检查会话状态
#if DEBUG
Button(action: {
logInfo("🔍 调试:检查扫描会话状态", className: "CodePositionOverlay")
// 这里可以添加会话状态检查逻辑
}) {
Image(systemName: "info.circle")
.font(.system(size: 16, weight: .medium))
.foregroundColor(.yellow)
.padding(8)
.background(Color.black.opacity(0.6))
.clipShape(Circle())
}
.padding(.trailing, 10)
.padding(.top, 25)
#endif
📱 修复后的功能特性
1. 会话状态管理
- ✅ 正确的会话启动/停止逻辑
- ✅ 会话状态检查和验证
- ✅ 自动重试机制
2. 时序优化
- ✅ 增加延迟时间(0.5秒)
- ✅ 等待会话完全停止后再重启
- ✅ 分阶段的状态检查
3. 错误处理
- ✅ 详细的日志记录
- ✅ 会话状态验证
- ✅ 失败重试机制
4. 调试支持
- ✅ 会话状态检查方法
- ✅ 调试按钮(DEBUG 模式)
- ✅ 详细的操作日志
🧪 测试方法
1. 基本重新扫描测试
- 扫描包含多个二维码的图片
- 等待预览暂停状态
- 点击重新扫描按钮
- 验证是否返回扫描状态
- 检查控制台日志输出
2. 扫描恢复测试
- 重新扫描后,移动设备对准二维码
- 验证是否能重新检测到二维码
- 检查扫描会话是否正常运行
3. 会话状态测试
- 使用调试按钮检查会话状态
- 验证会话状态检查逻辑
- 测试自动重试机制
4. 边界情况测试
- 快速连续点击重新扫描按钮
- 在不同设备方向上测试
- 在不同屏幕尺寸下测试
🔧 技术实现细节
1. 线程管理
- 主线程:UI 状态更新和日志记录
- 后台线程:会话启动/停止操作
- 适当的延迟确保操作顺序
2. 状态同步
- 使用
@Published
属性同步状态 - 通过回调函数传递状态变化
- 确保 UI 和业务逻辑的一致性
3. 错误恢复
- 会话启动失败时自动重试
- 状态检查失败时自动修复
- 提供详细的错误信息
4. 性能优化
- 使用适当的 QoS 级别
- 避免不必要的会话操作
- 优化延迟时间设置
📋 修复检查清单
- ✅ 优化会话重启逻辑
- ✅ 增加延迟时间(0.5秒)
- ✅ 添加会话状态检查
- ✅ 实现自动重试机制
- ✅ 改进错误处理
- ✅ 增强日志记录
- ✅ 添加调试功能
- ✅ 确保代码编译通过
🎯 预期效果
修复后,用户应该能够:
- 正常重新扫描:点击重新扫描按钮后能正确返回扫描状态
- 持续扫描功能:重新扫描后能继续检测二维码
- 稳定运行:扫描会话能正确启动和运行
- 错误恢复:即使出现问题也能自动恢复
🚀 部署说明
- 编译验证:确保项目能够正常编译
- 功能测试:测试重新扫描功能是否正常
- 扫描测试:验证重新扫描后是否能继续检测
- 性能测试:确保修复不会影响应用性能
通过这些修复,重新扫描后无法扫描的问题应该得到根本解决,用户体验将显著提升。