diff --git a/Assets/Plugins/iOS/CameraFocusHelper.mm b/Assets/Plugins/iOS/CameraFocusHelper.mm new file mode 100644 index 0000000..54b9a2a --- /dev/null +++ b/Assets/Plugins/iOS/CameraFocusHelper.mm @@ -0,0 +1,71 @@ +#import +#import + +/// 获取当前正在使用的后置摄像头设备 +static AVCaptureDevice *GetActiveRearCamera(void) +{ + // 遍历所有正在运行的 AVCaptureSession,找到后置摄像头的输入 + if (@available(iOS 10.0, *)) { + AVCaptureDeviceDiscoverySession *session = [AVCaptureDeviceDiscoverySession + discoverySessionWithDeviceTypes:@[AVCaptureDeviceTypeBuiltInWideAngleCamera] + mediaType:AVMediaTypeVideo + position:AVCaptureDevicePositionBack]; + for (AVCaptureDevice *d in session.devices) { + if (d.deviceType == AVCaptureDeviceTypeBuiltInWideAngleCamera) { + return d; + } + } + } + return [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; +} + +extern "C" { + + /// 开启连续自动对焦 + void _EnableContinuousAutoFocus(void) + { + AVCaptureDevice *device = GetActiveRearCamera(); + if (!device) return; + + NSError *error = nil; + if ([device lockForConfiguration:&error]) { + if ([device isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus]) { + device.focusMode = AVCaptureFocusModeContinuousAutoFocus; + NSLog(@"[CameraFocusHelper] 已开启连续自动对焦"); + } + if ([device isExposureModeSupported:AVCaptureExposureModeContinuousAutoExposure]) { + device.exposureMode = AVCaptureExposureModeContinuousAutoExposure; + } + [device unlockForConfiguration]; + } else { + NSLog(@"[CameraFocusHelper] 配置失败: %@", error.localizedDescription); + } + } + + /// 触发单次自动对焦(点击对焦用) + void _TriggerAutoFocus(float normalizedX, float normalizedY) + { + AVCaptureDevice *device = GetActiveRearCamera(); + if (!device) return; + + NSError *error = nil; + if ([device lockForConfiguration:&error]) { + if ([device isFocusPointOfInterestSupported]) { + device.focusPointOfInterest = CGPointMake(normalizedX, normalizedY); + device.focusMode = AVCaptureFocusModeAutoFocus; + } + if ([device isExposurePointOfInterestSupported]) { + device.exposurePointOfInterest = CGPointMake(normalizedX, normalizedY); + device.exposureMode = AVCaptureExposureModeAutoExpose; + } + [device unlockForConfiguration]; + + // 1.5秒后恢复连续对焦 + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5 * NSEC_PER_SEC)), + dispatch_get_main_queue(), ^{ + _EnableContinuousAutoFocus(); + }); + } + } + +} diff --git a/Assets/Plugins/iOS/CameraFocusHelper.mm.meta b/Assets/Plugins/iOS/CameraFocusHelper.mm.meta new file mode 100644 index 0000000..94922d0 --- /dev/null +++ b/Assets/Plugins/iOS/CameraFocusHelper.mm.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: bfac996797a54a14fa60abaaaf887145 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + iPhone: iOS + second: + enabled: 1 + settings: + AddToEmbeddedBinaries: false + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/UI/Pages/ConnectDevice/ScanQRcode.cs b/Assets/Scripts/UI/Pages/ConnectDevice/ScanQRcode.cs index eece869..a98cb43 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,15 @@ 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(float normalizedX, float normalizedY); +#endif + // 摄像头相关 private WebCamTexture webCamTexture; private WebCamDevice currentDevice; @@ -60,6 +70,22 @@ namespace Kill.UI.Pages StopScan(); } + void Update() + { +#if UNITY_IOS && !UNITY_EDITOR + if (isScanning && Input.touchCount > 0) + { + Touch touch = Input.GetTouch(0); + if (touch.phase == TouchPhase.Began) + { + float normX = touch.position.x / Screen.width; + float normY = touch.position.y / Screen.height; + _TriggerAutoFocus(normX, normY); + } + } +#endif + } + /// /// 开始扫描 /// @@ -151,18 +177,22 @@ namespace Kill.UI.Pages } } RectTransform cameraPreviewRect=cameraPreview.GetComponent(); - // 使用较低的扫描分辨率以提高性能 - int targetWidth = 2160; - - // 创建摄像头纹理 - webCamTexture = new WebCamTexture(deviceName, targetWidth, 30); + // 使用 1080p 分辨率 + webCamTexture = new WebCamTexture(deviceName, 1920, 1080, 30); // 开始播放 webCamTexture.Play(); // 等待摄像头启动 yield return new WaitUntil(() => webCamTexture.width > 100); - webCamTexture.autoFocusPoint=new Vector2(0.5f,0.5f); + +#if UNITY_IOS && !UNITY_EDITOR + // iOS: 通过原生插件开启连续自动对焦(autoFocusPoint 在 iOS 无效) + _EnableContinuousAutoFocus(); + // 定期维护对焦状态,防止被系统重置 + StartCoroutine(IOsFocusMaintainCoroutine()); +#endif + webCamTexture.autoFocusPoint = new Vector2(0.5f, 0.5f); // 调整预览画面比例 AdjustPreviewAspect(); @@ -215,7 +245,21 @@ namespace Kill.UI.Pages Debug.Log($"[ScanQRcode] 预览调整 - 相机: {cameraWidth}x{cameraHeight}, 预览: {previewWidth}x{previewHeight}"); } - + +#if UNITY_IOS && !UNITY_EDITOR + /// + /// iOS 对焦维护协程 — 定期重新设置连续自动对焦,防止被系统重置 + /// + private IEnumerator IOsFocusMaintainCoroutine() + { + while (isScanning) + { + yield return new WaitForSeconds(3f); + _EnableContinuousAutoFocus(); + } + } +#endif + private Texture2D previewTexture; ///