|
|
# 重新扫描后无法扫描问题修复说明
|
|
|
|
|
|
## 🚨 问题描述
|
|
|
|
|
|
用户反馈按重新扫描按钮返回扫描后,存在扫描不了的问题。即重新扫描后,相机无法继续检测二维码。
|
|
|
|
|
|
## 🔍 问题分析
|
|
|
|
|
|
### 1. **会话状态管理问题**
|
|
|
- `metadataOutput` 方法中调用 `stopScanning()` 后,会话被停止
|
|
|
- 重新扫描时,会话可能没有正确重启
|
|
|
- 缺少会话状态的验证和错误处理
|
|
|
|
|
|
### 2. **时序问题**
|
|
|
- 延迟时间过短(0.1秒),可能导致会话重启失败
|
|
|
- 没有等待会话完全停止就开始重启
|
|
|
- 缺少会话状态的检查机制
|
|
|
|
|
|
### 3. **错误处理缺失**
|
|
|
- 没有检查会话是否真的在运行
|
|
|
- 缺少会话启动失败的重试机制
|
|
|
- 没有提供详细的调试信息
|
|
|
|
|
|
## 🛠️ 修复方案
|
|
|
|
|
|
### 1. **优化会话重启逻辑**
|
|
|
|
|
|
#### **改进 `restartScanning()` 方法**
|
|
|
```swift
|
|
|
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. **增强会话状态管理**
|
|
|
|
|
|
#### **添加会话状态检查方法**
|
|
|
```swift
|
|
|
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()` 方法**
|
|
|
```swift
|
|
|
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()` 方法**
|
|
|
```swift
|
|
|
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()` 方法**
|
|
|
```swift
|
|
|
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 模式下添加会话状态检查按钮:
|
|
|
```swift
|
|
|
// 调试按钮:检查会话状态
|
|
|
#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. **基本重新扫描测试**
|
|
|
1. 扫描包含多个二维码的图片
|
|
|
2. 等待预览暂停状态
|
|
|
3. 点击重新扫描按钮
|
|
|
4. 验证是否返回扫描状态
|
|
|
5. 检查控制台日志输出
|
|
|
|
|
|
### 2. **扫描恢复测试**
|
|
|
1. 重新扫描后,移动设备对准二维码
|
|
|
2. 验证是否能重新检测到二维码
|
|
|
3. 检查扫描会话是否正常运行
|
|
|
|
|
|
### 3. **会话状态测试**
|
|
|
1. 使用调试按钮检查会话状态
|
|
|
2. 验证会话状态检查逻辑
|
|
|
3. 测试自动重试机制
|
|
|
|
|
|
### 4. **边界情况测试**
|
|
|
1. 快速连续点击重新扫描按钮
|
|
|
2. 在不同设备方向上测试
|
|
|
3. 在不同屏幕尺寸下测试
|
|
|
|
|
|
## 🔧 技术实现细节
|
|
|
|
|
|
### 1. **线程管理**
|
|
|
- 主线程:UI 状态更新和日志记录
|
|
|
- 后台线程:会话启动/停止操作
|
|
|
- 适当的延迟确保操作顺序
|
|
|
|
|
|
### 2. **状态同步**
|
|
|
- 使用 `@Published` 属性同步状态
|
|
|
- 通过回调函数传递状态变化
|
|
|
- 确保 UI 和业务逻辑的一致性
|
|
|
|
|
|
### 3. **错误恢复**
|
|
|
- 会话启动失败时自动重试
|
|
|
- 状态检查失败时自动修复
|
|
|
- 提供详细的错误信息
|
|
|
|
|
|
### 4. **性能优化**
|
|
|
- 使用适当的 QoS 级别
|
|
|
- 避免不必要的会话操作
|
|
|
- 优化延迟时间设置
|
|
|
|
|
|
## 📋 修复检查清单
|
|
|
|
|
|
- ✅ 优化会话重启逻辑
|
|
|
- ✅ 增加延迟时间(0.5秒)
|
|
|
- ✅ 添加会话状态检查
|
|
|
- ✅ 实现自动重试机制
|
|
|
- ✅ 改进错误处理
|
|
|
- ✅ 增强日志记录
|
|
|
- ✅ 添加调试功能
|
|
|
- ✅ 确保代码编译通过
|
|
|
|
|
|
## 🎯 预期效果
|
|
|
|
|
|
修复后,用户应该能够:
|
|
|
|
|
|
1. **正常重新扫描**:点击重新扫描按钮后能正确返回扫描状态
|
|
|
2. **持续扫描功能**:重新扫描后能继续检测二维码
|
|
|
3. **稳定运行**:扫描会话能正确启动和运行
|
|
|
4. **错误恢复**:即使出现问题也能自动恢复
|
|
|
|
|
|
## 🚀 部署说明
|
|
|
|
|
|
1. **编译验证**:确保项目能够正常编译
|
|
|
2. **功能测试**:测试重新扫描功能是否正常
|
|
|
3. **扫描测试**:验证重新扫描后是否能继续检测
|
|
|
4. **性能测试**:确保修复不会影响应用性能
|
|
|
|
|
|
通过这些修复,重新扫描后无法扫描的问题应该得到根本解决,用户体验将显著提升。 |