diff --git a/Assets/Plugins/iOS/CameraFocusHelper.mm b/Assets/Plugins/iOS/CameraFocusHelper.mm new file mode 100644 index 0000000..4a41aaa --- /dev/null +++ b/Assets/Plugins/iOS/CameraFocusHelper.mm @@ -0,0 +1,69 @@ +#import +#import + +extern "C" { + + /// 启用连续自动对焦和自动曝光 + void _EnableContinuousAutoFocus() + { + dispatch_async(dispatch_get_main_queue(), ^{ + AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; + if (!device) return; + + NSError *error = nil; + + // 锁定设备开始配置 + if ([device lockForConfiguration:&error]) { + + // 连续自动对焦模式(持续调整,适合扫描二维码) + if ([device isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus]) { + device.focusMode = AVCaptureFocusModeContinuousAutoFocus; + } + + // 连续自动曝光 + if ([device isExposureModeSupported:AVCaptureExposureModeContinuousAutoExposure]) { + device.exposureMode = AVCaptureExposureModeContinuousAutoExposure; + } + + // 对焦范围限制为近距(适合二维码) + if ([device respondsToSelector:@selector(setAutoFocusRangeRestriction:)]) { + if ([device isAutoFocusRangeRestrictionSupported]) { + device.autoFocusRangeRestriction = AVCaptureAutoFocusRangeRestrictionNear; + } + } + + // 启用低光增强(昏暗环境提高识别率) + if ([device respondsToSelector:@selector(setAutomaticallyEnablesLowLightBoostWhenAvailable:)]) { + device.automaticallyEnablesLowLightBoostWhenAvailable = YES; + } + + [device unlockForConfiguration]; + + NSLog(@"[CameraFocusHelper] 已启用连续自动对焦"); + } else { + NSLog(@"[CameraFocusHelper] 锁定设备失败: %@", error.localizedDescription); + } + }); + } + + /// 触发一次自动对焦(用于手动点按时调用) + void _TriggerAutoFocus() + { + dispatch_async(dispatch_get_main_queue(), ^{ + AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; + if (!device) return; + + NSError *error = nil; + if ([device lockForConfiguration:&error]) { + if ([device isFocusModeSupported:AVCaptureFocusModeAutoFocus]) { + device.focusMode = AVCaptureFocusModeAutoFocus; + } + if ([device isExposureModeSupported:AVCaptureExposureModeAutoExpose]) { + device.exposureMode = AVCaptureExposureModeAutoExpose; + } + [device unlockForConfiguration]; + } + }); + } + +} diff --git a/Assets/Scripts/UI/Pages/ConnectDevice/ScanQRcode.cs b/Assets/Scripts/UI/Pages/ConnectDevice/ScanQRcode.cs index eece869..ebdfdaa 100644 --- a/Assets/Scripts/UI/Pages/ConnectDevice/ScanQRcode.cs +++ b/Assets/Scripts/UI/Pages/ConnectDevice/ScanQRcode.cs @@ -1,6 +1,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Runtime.InteropServices; using Kill.UI.Components; using UnityEngine; using UnityEngine.UI; @@ -41,6 +42,14 @@ namespace Kill.UI.Pages public bool enableAutoFocus = true; [Tooltip("对焦间隔(秒)")] public float focusInterval = 1f; + +#if UNITY_IOS && !UNITY_EDITOR + [DllImport("__Internal")] + private static extern void _EnableContinuousAutoFocus(); + + [DllImport("__Internal")] + private static extern void _TriggerAutoFocus(); +#endif // 摄像头相关 private WebCamTexture webCamTexture; private WebCamDevice currentDevice; @@ -162,7 +171,14 @@ namespace Kill.UI.Pages // 等待摄像头启动 yield return new WaitUntil(() => webCamTexture.width > 100); - webCamTexture.autoFocusPoint=new Vector2(0.5f,0.5f); + + // iOS: 调用原生插件强制开启连续自动对焦 +#if UNITY_IOS && !UNITY_EDITOR + if (enableAutoFocus) + { + _EnableContinuousAutoFocus(); + } +#endif // 调整预览画面比例 AdjustPreviewAspect(); @@ -170,6 +186,11 @@ namespace Kill.UI.Pages // 开始预览更新和扫描 StartCoroutine(PreviewUpdateCoroutine()); StartCoroutine(ScanCoroutine()); + // 启动自动对焦维护协程(仅非 iOS 平台使用 autoFocusPoint,iOS 走原生插件) + if (enableAutoFocus) + { + StartCoroutine(AutoFocusCoroutine()); + } } @@ -264,6 +285,29 @@ namespace Kill.UI.Pages previewTexture.Apply(); } + /// + /// 自动对焦维护协程 + /// iOS: 走原生插件(连续自动对焦已启用,只需定期触发即可) + /// 其他平台: 使用 WebCamTexture.autoFocusPoint 定期设置对焦点 + /// + private IEnumerator AutoFocusCoroutine() + { + while (isScanning) + { +#if UNITY_IOS && !UNITY_EDITOR + // iOS 通过原生插件触发一次自动对焦 + _TriggerAutoFocus(); +#else + // Android/其他: 定期重置对焦点到画面中心 + if (webCamTexture != null && webCamTexture.isPlaying) + { + webCamTexture.autoFocusPoint = new Vector2(0.5f, 0.5f); + } +#endif + yield return new WaitForSeconds(focusInterval); + } + } + [SerializeField] private float previewUpdateInterval = 0.03f; // 预览更新间隔(20fps) ///