Unity+Vuforia环境下Android端CameraDevice.SetFlash()失效问题
Unity+Vuforia手电筒无法开启问题排查与解决
环境信息
- 开发工具:Unity 2022.2.7、Vuforia Engine v10.14.4
- 测试设备:小米11 Lite 5G NE(Android 12)
问题描述
通过按钮调用ToggleFlashLight()函数切换手电筒,但始终无法开启。Logcat输出flashlight is on: False和Failed to set camera flash mode。已确认Vuforia初始化完成、相机正常工作,排除这两个因素。
所用代码
public void ToggleFlashLight() { if(isFlashLightOn) { isFlashLightOn = false; } else { isFlashLightOn = true; } bool wasFlashLisgtActivated = VuforiaBehaviour.Instance.CameraDevice.SetFlash(isFlashLightOn); Debug.Log("flashlight is on: " + wasFlashLisgtActivated); }
AndroidManifest内容
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="com.unity3d.player" > <uses-sdk android:minSdkVersion="26" android:targetSdkVersion="32" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-feature android:glEsVersion="0x00030000" /> <uses-feature android:name="android.hardware.camera" android:required="false" /> <uses-feature android:name="android.hardware.camera.autofocus" android:required="false" /> <uses-feature android:name="android.hardware.camera.front" android:required="false" /> <uses-feature android:name="android.hardware.touchscreen" android:required="false" /> <uses-feature android:name="android.hardware.touchscreen.multitouch" android:required="false" /> <uses-feature android:name="android.hardware.touchscreen.multitouch.distinct" android:required="false" /> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <application android:extractNativeLibs="true" > <meta-data android:name="unity.splash-mode" android:value="0" /> <meta-data android:name="unity.splash-enable" android:value="True" /> <meta-data android:name="unity.launch-fullscreen" android:value="True" /> <meta-data android:name="unity.allow-resizable-window" android:value="False" /> <meta-data android:name="notch.config" android:value="portrait|landscape" /> <activity android:name="com.unity3d.player.UnityPlayerActivity" android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize|fontScale|layoutDirection|density" android:exported="true" android:hardwareAccelerated="false" android:launchMode="singleTask" android:resizeableActivity="false" android:screenOrientation="portrait" android:theme="@style/UnityThemeSelector" > <intent-filter> <category android:name="android.intent.category.LAUNCHER" /> <action android:name="android.intent.action.MAIN" /> </intent-filter> <meta-data android:name="unityplayer.UnityActivity" android:value="true" /> <meta-data android:name="notch_support" android:value="true" /> </activity> <receiver android:name="com.unity.androidnotifications.UnityNotificationManager" android:exported="false" /> <receiver android:name="com.unity.androidnotifications.UnityNotificationRestartOnBootReceiver" android:enabled="false" android:exported="false" > <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter> </receiver> <meta-data android:name="com.unity.androidnotifications.exact_scheduling" android:value="0" /> <meta-data android:name="com.google.ar.core" android:value="optional" /> </application> </manifest>
解决方案
1. 补充闪光灯权限
Android 12及以上版本控制闪光灯需要单独声明android.permission.FLASHLIGHT权限,同时建议添加闪光灯硬件特性声明。在Manifest的<uses-permission>区域添加:
<uses-permission android:name="android.permission.FLASHLIGHT" /> <uses-feature android:name="android.hardware.camera.flash" android:required="false" />
2. 动态申请权限
Android 6.0+需要动态申请危险权限,修改代码,在调用手电筒前检查并申请权限:
using UnityEngine; using Vuforia; using UnityEngine.Android; public class FlashlightController : MonoBehaviour { private bool isFlashLightOn = false; public void ToggleFlashLight() { // 检查相机和闪光灯权限 if (!Permission.HasUserAuthorizedPermission(Permission.Camera) || !Permission.HasUserAuthorizedPermission("android.permission.FLASHLIGHT")) { Permission.RequestUserPermissions(new string[]{Permission.Camera, "android.permission.FLASHLIGHT"}); Debug.Log("请授予相机和闪光灯权限"); return; } isFlashLightOn = !isFlashLightOn; bool wasFlashActivated = VuforiaBehaviour.Instance.CameraDevice.SetFlash(isFlashLightOn); Debug.Log("手电筒状态: " + wasFlashActivated); } }
3. 确认使用后置相机
前置相机通常没有闪光灯,确保Vuforia使用后置相机:
- 在Vuforia Configuration面板中,将Default Camera设置为Back Camera;
- 或通过代码强制切换:
VuforiaBehaviour.Instance.CameraDevice.SelectCamera(CameraDevice.CameraDirection.BACK);
4. 备选方案:使用Android原生API控制
如果Vuforia API仍无法生效,可直接调用Android原生API控制闪光灯:
#if UNITY_ANDROID && !UNITY_EDITOR using UnityEngine; using UnityEngine.Android; public class NativeFlashlight : MonoBehaviour { private bool isFlashOn = false; private AndroidJavaObject cameraManager; private AndroidJavaObject currentActivity; void Start() { currentActivity = new AndroidJavaClass("com.unity3d.player.UnityPlayer").GetStatic<AndroidJavaObject>("currentActivity"); cameraManager = currentActivity.Call<AndroidJavaObject>("getSystemService", "camera"); } public void ToggleNativeFlash() { if (!Permission.HasUserAuthorizedPermission(Permission.Camera) || !Permission.HasUserAuthorizedPermission("android.permission.FLASHLIGHT")) { Permission.RequestUserPermissions(new string[]{Permission.Camera, "android.permission.FLASHLIGHT"}); return; } string backCameraId = GetBackCameraId(); if (string.IsNullOrEmpty(backCameraId)) { Debug.Log("未找到后置相机"); return; } isFlashOn = !isFlashOn; AndroidJavaObject cameraControl = cameraManager.Call<AndroidJavaObject>("createCameraControl", backCameraId); cameraControl.Call("setTorchMode", isFlashOn); Debug.Log("原生手电筒状态: " + isFlashOn); } private string GetBackCameraId() { AndroidJavaObject cameraIds = cameraManager.Call<AndroidJavaObject>("getCameraIdList"); int count = cameraIds.Call<int>("length"); for (int i = 0; i < count; i++) { string id = cameraIds.Call<string>("get", i); AndroidJavaObject characteristics = cameraManager.Call<AndroidJavaObject>("getCameraCharacteristics", id); int lensFacing = characteristics.Get<int>("LENS_FACING"); if (lensFacing == 0) // 0代表后置相机 return id; } return null; } } #endif
内容的提问来源于stack exchange,提问作者Szasz Robert
相关产品推荐
相关产品推荐

