使用AVCaptureDevice API实现的条码扫描在iPhone正常但iPad无法识别
核心问题定位
你的代码在iPad端无法识别条码的核心原因是扫描区域计算、朝向适配的执行顺序和逻辑错误,和系统版本无关,具体问题和修改方案如下:
问题1:扫描区域计算顺序完全错位
你先计算设置了metadataOutput.rectOfInterest,之后才修改previewLayer的videoOrientation属性,rectOfInterest的坐标系依赖预览层的朝向配置,顺序反转会导致扫描区域和你屏幕上显示的黄色框完全不匹配,条码根本不在有效识别范围内。
修复方案
调整代码执行顺序:先完成previewLayer的所有属性配置(包括朝向、frame、videoGravity),再计算设置扫描识别区域。
问题2:iPad端黄色扫描框位置偏移
你给iPad端的scanRectView设置center时多减了一次宽高的半值,导致黄色框本身就不在屏幕中心,和实际识别区域进一步错位:
// 错误代码 scanRectView.center = CGPoint( x:UIScreen.main.bounds.midX - scanSize.width/2, y:UIScreen.main.bounds.midY - scanSize.height/2)
修复方案
统一iPhone和iPad的扫描框居中逻辑:
scanRectView.center = CGPoint(x: UIScreen.main.bounds.midX, y: UIScreen.main.bounds.midY)
问题3:手动转换扫描区域坐标系容易出错
你手动翻转宽高、计算比例来适配rectOfInterest的坐标系,横竖屏场景下很容易计算错误。
修复方案
用AVCaptureVideoPreviewLayer提供的内置方法转换坐标系,自动适配朝向,完全避免手动计算错误:
// 先得到屏幕上实际显示的扫描框坐标 let visualScanRect = CGRect( x: UIScreen.main.bounds.midX - scanSize.width/2, y: UIScreen.main.bounds.midY - scanSize.height/2, width: scanSize.width, height: scanSize.height ) // 直接转换为metadataOutput需要的坐标系 metadataOutput.rectOfInterest = previewLayer.metadataOutputRectConverted(fromLayerRect: visualScanRect)
删掉你原来手动转换scanRect的代码即可。
问题4:变焦系数硬编码可能超出设备支持范围
初代9.7英寸iPad Pro的摄像头变焦范围可能和iPhone不一致,直接硬写1.3可能超出硬件支持范围,导致画面异常影响识别。
修复方案
增加变焦范围校验:
// 替换toggleTorch里的变焦设置代码 let targetZoom: CGFloat = UIDevice.current.userInterfaceIdiom == .pad ? 1.3 : 1.5 let maxSupportedZoom = min(device.activeFormat.videoMaxZoomFactor, 2.0) let minSupportedZoom = device.minAvailableVideoZoomFactor device.videoZoomFactor = max(minSupportedZoom, min(targetZoom, maxSupportedZoom))
临时验证方法
你可以先临时注释掉metadataOutput.rectOfInterest = scanRect这行代码,默认会开启全屏幕识别,如果此时iPad能正常扫描条码,即可确认是扫描区域计算的问题,再按上面的方案调整即可。
内容的提问来源于stack exchange,提问作者juminoz

