@ -27,9 +27,10 @@ class ScannerViewModel: NSObject, ObservableObject, AVCaptureMetadataOutputObjec
switch AVCaptureDevice . authorizationStatus ( for : . video ) {
switch AVCaptureDevice . authorizationStatus ( for : . video ) {
case . authorized :
case . authorized :
logInfo ( " ✅ 相机权限已授权 " , className : " ScannerViewModel " )
logInfo ( " ✅ 相机权限已授权 ,立即设置捕获会话 " , className : " ScannerViewModel " )
cameraAuthorizationStatus = . authorized
cameraAuthorizationStatus = . authorized
setupCaptureSession ( )
setupCaptureSession ( )
// s e t u p C a p t u r e S e s s i o n 现 在 会 自 动 启 动 扫 描
case . notDetermined :
case . notDetermined :
logInfo ( " ❓ 相机权限未确定,请求权限 " , className : " ScannerViewModel " )
logInfo ( " ❓ 相机权限未确定,请求权限 " , className : " ScannerViewModel " )
@ -51,9 +52,10 @@ class ScannerViewModel: NSObject, ObservableObject, AVCaptureMetadataOutputObjec
AVCaptureDevice . requestAccess ( for : . video ) { [ weak self ] granted in
AVCaptureDevice . requestAccess ( for : . video ) { [ weak self ] granted in
DispatchQueue . main . async {
DispatchQueue . main . async {
if granted {
if granted {
logInfo ( " ✅ 相机权限请求成功 " , className : " ScannerViewModel " )
logInfo ( " ✅ 相机权限请求成功 ,立即设置捕获会话 " , className : " ScannerViewModel " )
self ? . cameraAuthorizationStatus = . authorized
self ? . cameraAuthorizationStatus = . authorized
self ? . setupCaptureSession ( )
self ? . setupCaptureSession ( )
// s e t u p C a p t u r e S e s s i o n 现 在 会 自 动 启 动 扫 描
} else {
} else {
logWarning ( " ❌ 相机权限请求被拒绝 " , className : " ScannerViewModel " )
logWarning ( " ❌ 相机权限请求被拒绝 " , className : " ScannerViewModel " )
self ? . cameraAuthorizationStatus = . denied
self ? . cameraAuthorizationStatus = . denied
@ -78,15 +80,25 @@ class ScannerViewModel: NSObject, ObservableObject, AVCaptureMetadataOutputObjec
func refreshCameraPermission ( ) {
func refreshCameraPermission ( ) {
logInfo ( " 🔍 重新检查相机权限状态 " , className : " ScannerViewModel " )
logInfo ( " 🔍 重新检查相机权限状态 " , className : " ScannerViewModel " )
// 先 停 止 当 前 扫 描
if captureSession ? . isRunning = = true {
stopScanning ( )
}
// 重 新 检 查 权 限
checkCameraPermission ( )
checkCameraPermission ( )
}
}
// MARK: - 相 机 设 置
// MARK: - 相 机 设 置
private func setupCaptureSession ( ) {
private func setupCaptureSession ( ) {
logInfo ( " 🔧 开始设置捕获会话 " , className : " ScannerViewModel " )
captureSession = AVCaptureSession ( )
captureSession = AVCaptureSession ( )
guard let videoCaptureDevice = AVCaptureDevice . default ( for : . video ) else {
guard let videoCaptureDevice = AVCaptureDevice . default ( for : . video ) else {
logError ( " ❌ 无法获取视频设备 " , className : " ScannerViewModel " )
showAlert = true
showAlert = true
return
return
}
}
@ -99,13 +111,16 @@ class ScannerViewModel: NSObject, ObservableObject, AVCaptureMetadataOutputObjec
do {
do {
videoInput = try AVCaptureDeviceInput ( device : videoCaptureDevice )
videoInput = try AVCaptureDeviceInput ( device : videoCaptureDevice )
} catch {
} catch {
logError ( " ❌ 创建视频输入失败: \( error . localizedDescription ) " , className : " ScannerViewModel " )
showAlert = true
showAlert = true
return
return
}
}
if captureSession . canAddInput ( videoInput ) {
if captureSession . canAddInput ( videoInput ) {
captureSession . addInput ( videoInput )
captureSession . addInput ( videoInput )
logInfo ( " ✅ 成功添加视频输入 " , className : " ScannerViewModel " )
} else {
} else {
logError ( " ❌ 无法添加视频输入 " , className : " ScannerViewModel " )
showAlert = true
showAlert = true
return
return
}
}
@ -117,10 +132,19 @@ class ScannerViewModel: NSObject, ObservableObject, AVCaptureMetadataOutputObjec
captureSession . addOutput ( metadataOutput )
captureSession . addOutput ( metadataOutput )
metadataOutput . setMetadataObjectsDelegate ( self , queue : DispatchQueue . main )
metadataOutput . setMetadataObjectsDelegate ( self , queue : DispatchQueue . main )
metadataOutput . metadataObjectTypes = [ . qr , . ean8 , . ean13 , . code128 , . code39 , . upce , . pdf417 , . aztec ]
metadataOutput . metadataObjectTypes = [ . qr , . ean8 , . ean13 , . code128 , . code39 , . upce , . pdf417 , . aztec ]
logInfo ( " ✅ 成功添加元数据输出 " , className : " ScannerViewModel " )
} else {
} else {
logError ( " ❌ 无法添加元数据输出 " , className : " ScannerViewModel " )
showAlert = true
showAlert = true
return
return
}
}
logInfo ( " ✅ 捕获会话设置完成,准备启动扫描 " , className : " ScannerViewModel " )
// 设 置 完 成 后 立 即 启 动 扫 描
DispatchQueue . main . asyncAfter ( deadline : . now ( ) + 0.1 ) { [ weak self ] in
self ? . startScanning ( )
}
}
}
// MARK: - 扫 描 控 制
// MARK: - 扫 描 控 制
@ -128,23 +152,70 @@ class ScannerViewModel: NSObject, ObservableObject, AVCaptureMetadataOutputObjec
func startScanning ( ) {
func startScanning ( ) {
logInfo ( " 🔄 开始扫描 " , className : " ScannerViewModel " )
logInfo ( " 🔄 开始扫描 " , className : " ScannerViewModel " )
// 检 查 相 机 权 限
guard cameraAuthorizationStatus = = . authorized else {
logWarning ( " ❌ 相机权限未授权,无法启动扫描 " , className : " ScannerViewModel " )
return
}
// 检 查 捕 获 会 话 是 否 已 设 置
guard captureSession != nil else {
logWarning ( " ⚠️ 捕获会话未设置,重新设置 " , className : " ScannerViewModel " )
setupCaptureSession ( )
return
}
// 检 查 会 话 是 否 已 经 在 运 行
// 检 查 会 话 是 否 已 经 在 运 行
if captureSession ? . isRunning = = true {
if captureSession .isRunning {
logInfo ( " ℹ ️ 扫描会话已经在运行" , className : " ScannerViewModel " )
logInfo ( " ℹ ️ 扫描会话已经在运行" , className : " ScannerViewModel " )
return
return
}
}
// 检 查 会 话 配 置 是 否 完 整
if captureSession . inputs . isEmpty || captureSession . outputs . isEmpty {
logWarning ( " ⚠️ 捕获会话配置不完整,重新设置 " , className : " ScannerViewModel " )
setupCaptureSession ( )
return
}
logInfo ( " 🚀 启动扫描会话 " , className : " ScannerViewModel " )
DispatchQueue . global ( qos : . userInitiated ) . async { [ weak self ] in
DispatchQueue . global ( qos : . userInitiated ) . async { [ weak self ] in
guard let self = self else { return }
guard let self = self else { return }
self . captureSession ? . startRunning ( )
self . captureSession ? . startRunning ( )
// 检 查 启 动 状 态
// 检 查 启 动 状 态
DispatchQueue . main . asyncAfter ( deadline : . now ( ) + 0.2 ) {
DispatchQueue . main . asyncAfter ( deadline : . now ( ) + 0. 3 ) {
if self . captureSession ? . isRunning = = true {
if self . captureSession ? . isRunning = = true {
logInfo ( " ✅ 扫描会话启动成功 " , className : " ScannerViewModel " )
logInfo ( " ✅ 扫描会话启动成功 " , className : " ScannerViewModel " )
} else {
} else {
logWarning ( " ⚠️ 扫描会话启动失败 " , className : " ScannerViewModel " )
logWarning ( " ⚠️ 扫描会话启动失败,尝试重试 " , className : " ScannerViewModel " )
// 启 动 失 败 时 重 试 一 次
DispatchQueue . main . asyncAfter ( deadline : . now ( ) + 0.5 ) {
self . retryStartScanning ( )
}
}
}
}
}
private func retryStartScanning ( ) {
logInfo ( " 🔄 重试启动扫描 " , className : " ScannerViewModel " )
guard captureSession != nil else {
logError ( " ❌ 捕获会话为空,无法重试 " , className : " ScannerViewModel " )
return
}
DispatchQueue . global ( qos : . userInitiated ) . async { [ weak self ] in
self ? . captureSession ? . startRunning ( )
DispatchQueue . main . asyncAfter ( deadline : . now ( ) + 0.2 ) {
if self ? . captureSession ? . isRunning = = true {
logInfo ( " ✅ 重试启动扫描成功 " , className : " ScannerViewModel " )
} else {
logError ( " ❌ 重试启动扫描失败 " , className : " ScannerViewModel " )
}
}
}
}
}
}