You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 23:04:56