diff --git a/Assets/Plugins/iOS/CameraFocusHelper.mm b/Assets/Plugins/iOS/CameraFocusHelper.mm index 59290e7..49138e0 100644 --- a/Assets/Plugins/iOS/CameraFocusHelper.mm +++ b/Assets/Plugins/iOS/CameraFocusHelper.mm @@ -1,23 +1,64 @@ #import #import +/// 通过名称查找摄像头设备 +static AVCaptureDevice *FindCameraByName(const char *cameraName) +{ + if (cameraName == NULL || strlen(cameraName) == 0) { + return [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; + } + + NSString *name = [NSString stringWithUTF8String:cameraName]; + + // iOS 10+ DiscoverySession + if (@available(iOS 10.0, *)) { + AVCaptureDeviceDiscoverySession *session = [AVCaptureDeviceDiscoverySession + discoverySessionWithDeviceTypes:@[AVCaptureDeviceTypeBuiltInWideAngleCamera, + AVCaptureDeviceTypeBuiltInTelephotoCamera, + AVCaptureDeviceTypeBuiltInUltraWideCamera] + mediaType:AVMediaTypeVideo + position:AVCaptureDevicePositionUnspecified]; + for (AVCaptureDevice *device in session.devices) { + if ([device.localizedName containsString:name] || + [device.modelID containsString:name]) { + return device; + } + } + // 没找到精确匹配,返回第一个活跃的 + for (AVCaptureDevice *device in session.devices) { + if (device.isConnected && !device.isSuspended) { + return device; + } + } + } + + return [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; +} + extern "C" { - /// 启用连续自动对焦和自动曝光 - void _EnableContinuousAutoFocus() + /// 启用连续自动对焦和自动曝光(传入 C# 选中的摄像头名称) + void _EnableContinuousAutoFocus(const char *cameraName) { dispatch_async(dispatch_get_main_queue(), ^{ - AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; - if (!device) return; + AVCaptureDevice *device = FindCameraByName(cameraName); + if (!device) { + NSLog(@"[CameraFocusHelper] 未找到摄像头设备"); + return; + } + + NSLog(@"[CameraFocusHelper] 配置设备: %@ (name=%@, model=%@)", + device.localizedName, device.localizedName, device.modelID); NSError *error = nil; - - // 锁定设备开始配置 if ([device lockForConfiguration:&error]) { - // 连续自动对焦模式(持续调整,适合扫描二维码) + // 连续自动对焦 if ([device isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus]) { device.focusMode = AVCaptureFocusModeContinuousAutoFocus; + NSLog(@"[CameraFocusHelper] 已设为连续自动对焦"); + } else { + NSLog(@"[CameraFocusHelper] 设备不支持连续自动对焦"); } // 连续自动曝光 @@ -25,36 +66,34 @@ extern "C" { device.exposureMode = AVCaptureExposureModeContinuousAutoExposure; } - // 对焦范围限制为近距(适合二维码) - if ([device respondsToSelector:@selector(setAutoFocusRangeRestriction:)]) { - if ([device isAutoFocusRangeRestrictionSupported]) { - device.autoFocusRangeRestriction = AVCaptureAutoFocusRangeRestrictionNear; - } + // 对焦范围限制为近距 + if ([device respondsToSelector:@selector(isAutoFocusRangeRestrictionSupported)] && + [device isAutoFocusRangeRestrictionSupported]) { + device.autoFocusRangeRestriction = AVCaptureAutoFocusRangeRestrictionNear; + NSLog(@"[CameraFocusHelper] 已设对焦范围为近距"); } [device unlockForConfiguration]; - - NSLog(@"[CameraFocusHelper] 已启用连续自动对焦"); + NSLog(@"[CameraFocusHelper] 摄像头配置完成"); } else { - NSLog(@"[CameraFocusHelper] 锁定设备失败: %@", error.localizedDescription); + NSLog(@"[CameraFocusHelper] lockForConfiguration 失败: %@", error.localizedDescription); } }); } - /// 触发一次自动对焦(用于手动点按时调用) - void _TriggerAutoFocus() + /// 确保连续自动对焦仍在生效(传入 C# 选中的摄像头名称) + void _EnsureContinuousAutoFocus(const char *cameraName) { dispatch_async(dispatch_get_main_queue(), ^{ - AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; + AVCaptureDevice *device = FindCameraByName(cameraName); if (!device) return; NSError *error = nil; if ([device lockForConfiguration:&error]) { - if ([device isFocusModeSupported:AVCaptureFocusModeAutoFocus]) { - device.focusMode = AVCaptureFocusModeAutoFocus; - } - if ([device isExposureModeSupported:AVCaptureExposureModeAutoExpose]) { - device.exposureMode = AVCaptureExposureModeAutoExpose; + if (device.focusMode != AVCaptureFocusModeContinuousAutoFocus && + [device isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus]) { + device.focusMode = AVCaptureFocusModeContinuousAutoFocus; + NSLog(@"[CameraFocusHelper] 重新设回连续自动对焦"); } [device unlockForConfiguration]; } diff --git a/Assets/Scripts/UI/Pages/ConnectDevice/ScanQRcode.cs b/Assets/Scripts/UI/Pages/ConnectDevice/ScanQRcode.cs index ebdfdaa..b2e9489 100644 --- a/Assets/Scripts/UI/Pages/ConnectDevice/ScanQRcode.cs +++ b/Assets/Scripts/UI/Pages/ConnectDevice/ScanQRcode.cs @@ -45,10 +45,10 @@ namespace Kill.UI.Pages #if UNITY_IOS && !UNITY_EDITOR [DllImport("__Internal")] - private static extern void _EnableContinuousAutoFocus(); + private static extern void _EnableContinuousAutoFocus(string cameraName); [DllImport("__Internal")] - private static extern void _TriggerAutoFocus(); + private static extern void _EnsureContinuousAutoFocus(string cameraName); #endif // 摄像头相关 private WebCamTexture webCamTexture; @@ -59,6 +59,9 @@ namespace Kill.UI.Pages // 扫描结果回调 public event Action OnQRCodeScanned; + // iOS 摄像头名称(供原生对焦插件使用) + private string selectedCameraName; + void OnEnable() { StartScan(); @@ -148,17 +151,32 @@ namespace Kill.UI.Pages yield break; } - // 优先使用后置摄像头,并选择支持自动对焦的摄像头 + // 优先使用后置主摄(广角),iOS 多摄设备排除超广角/长焦 string deviceName = devices[0].name; + currentDevice = devices[0]; for (int i = 0; i < devices.Length; i++) { if (!devices[i].isFrontFacing) { - deviceName = devices[i].name; - currentDevice = devices[i]; - break; + string lowerName = devices[i].name.ToLower(); + // iOS 多摄命名: "Back Camera", "Telephoto Camera", "Ultra Wide Camera" + // 优先选不带 telephoto/ultra wide 的后置摄像头(即主摄) + if (!lowerName.Contains("telephoto") && !lowerName.Contains("ultra wide")) + { + deviceName = devices[i].name; + currentDevice = devices[i]; + break; + } + // 兜底:第一个后置 + if (deviceName == devices[0].name) + { + deviceName = devices[i].name; + currentDevice = devices[i]; + } } } + Debug.Log($"[ScanQRcode] 选中摄像头: {deviceName}"); + selectedCameraName = deviceName; RectTransform cameraPreviewRect=cameraPreview.GetComponent(); // 使用较低的扫描分辨率以提高性能 int targetWidth = 2160; @@ -172,11 +190,13 @@ namespace Kill.UI.Pages // 等待摄像头启动 yield return new WaitUntil(() => webCamTexture.width > 100); - // iOS: 调用原生插件强制开启连续自动对焦 + // iOS: 延迟后调用原生插件强制开启连续自动对焦 + // (等待 Unity 内部 AVCaptureSession 完全就绪) #if UNITY_IOS && !UNITY_EDITOR if (enableAutoFocus) { - _EnableContinuousAutoFocus(); + yield return new WaitForSeconds(1.5f); + _EnableContinuousAutoFocus(deviceName); } #endif // 调整预览画面比例 @@ -287,7 +307,7 @@ namespace Kill.UI.Pages /// /// 自动对焦维护协程 - /// iOS: 走原生插件(连续自动对焦已启用,只需定期触发即可) + /// iOS: 走原生插件周期确保连续对焦模式不被重置 /// 其他平台: 使用 WebCamTexture.autoFocusPoint 定期设置对焦点 /// private IEnumerator AutoFocusCoroutine() @@ -295,8 +315,11 @@ namespace Kill.UI.Pages while (isScanning) { #if UNITY_IOS && !UNITY_EDITOR - // iOS 通过原生插件触发一次自动对焦 - _TriggerAutoFocus(); + // iOS 通过原生插件确保连续自动对焦仍在生效 + if (!string.IsNullOrEmpty(selectedCameraName)) + { + _EnsureContinuousAutoFocus(selectedCameraName); + } #else // Android/其他: 定期重置对焦点到画面中心 if (webCamTexture != null && webCamTexture.isPlaying)