Unity调用已部署Firebase Cloud Functions触发INTERNAL错误排查
我开发了一款集成Firebase Auth与Firebase Functions SDK的Unity C#应用,编写了三个Callable函数,在Firebase模拟器测试功能完全正常,但部署后在Unity Editor中调用任意函数都会触发INTERNAL错误。查看Google Cloud控制台日志发现函数根本未运行,断点调试仅能获取到“One or more errors occurred”与“INTERNAL”的提示信息。
已排查的情况
- SDK版本问题:重新下载最新SDK并重新导入Firebase Auth与Firebase Functions组件,问题依旧;
- 区域指定问题:Google控制台显示函数部署在
us-central1区域,尝试指定该区域后无效;后续发现Firebase项目实际位于europe-west3,指定该区域后问题仍未解决; - 注释
UseFunctionsEmulator()代码后,模拟器测试依然可以正常运行。
相关代码
FirebaseManager.cs
public class FirebaseManager : MonoBehaviour { private static bool gameQuitting = false; private static readonly object Lock = new object(); private static FirebaseManager _instance; public static FirebaseManager Instance { get { // [check if instance exists etc..] } } private FirebaseApp _app; private FirebaseAuth _auth; public FirebaseAuth Auth { get { if (_auth == null) { _auth = FirebaseAuth.GetAuth(_app); } return _auth; } } private FirebaseUser _user; public FirebaseUser User { get { return _user; } set { _user = value; } } private FirebaseFunctions _func; public FirebaseFunctions Func { get { if (_func == null) { _func = FirebaseFunctions.DefaultInstance; } return _func; } } // Events to subscribe to for this service public delegate void FirebaseInitialized(); public static event FirebaseInitialized OnFirebaseInitialized; public static bool IsInitialized = false; private void Awake() { if (_instance == null) { DontDestroyOnLoad(this.gameObject); _instance = this; } else { Destroy(this.gameObject); } } private void Start() { InitializeFirebase(); } private void InitializeFirebase() { Debug.Log($"FirebaseManager.cs > INITIALIZING FIREBASE"); Firebase.FirebaseApp.CheckAndFixDependenciesAsync().ContinueWithOnMainThread(task => { var dependencyStatus = task.Result; if (dependencyStatus == Firebase.DependencyStatus.Available) { // Create and hold a reference to your FirebaseApp, // where app is a Firebase.FirebaseApp property of your application class. _app = FirebaseApp.DefaultInstance; // _app = FirebaseApp.GetInstance("europe-west3"); // Create and hold a reference to FirebaseAuth _auth = FirebaseAuth.DefaultInstance; // Create and hold a reference to already logged in user (if any) _user = _auth.CurrentUser; // Create and hold a reference to Functions _func = FirebaseFunctions.DefaultInstance; // _func = FirebaseFunctions.GetInstance(FirebaseApp.DefaultInstance, "europe-west3"); // _func = FirebaseFunctions.GetInstance("europe-west3"); // #if UNITY_EDITOR // _func.UseFunctionsEmulator("http://localhost:5001"); // LOCAL FUNCS // #endif // Subscribing to AuthStateChanged FirebaseManager.Instance.Auth.StateChanged += AuthService.AuthStateChanged; Debug.Log($"FirebaseManager.cs > INITIALIZED"); IsInitialized = true; if (OnFirebaseInitialized != null) OnFirebaseInitialized.Invoke(); } else { UnityEngine.Debug.LogError(System.String.Format( "FirebaseManager.cs > Could not resolve all Firebase dependencies: {0}", dependencyStatus)); // Firebase Unity SDK is not safe to use here. } }); } private void OnDestroy() { if (_auth != null) _auth = null; } private void OnApplicationQuit() { FirebaseManager.Instance.Auth.StateChanged -= AuthService.AuthStateChanged; gameQuitting = true; } }
函数调用代码
HttpsCallableReference function = FirebaseManager.Instance.Func.GetHttpsCallable("GetAllCharacters"); // Call the function and extract the operation from the result. function.CallAsync().ContinueWithOnMainThread((task) => { if (task.IsFaulted) { // this foreach is a debug attempt foreach (var e in task.Exception.Flatten().InnerExceptions) { Debug.LogWarning($"Received Exception: {e.Message}"); } foreach (var inner in task.Exception.InnerExceptions) { if (inner is FunctionsException) { var e = (FunctionsException)inner; // Function error code, will be INTERNAL if the failure // was not handled properly in the function call. var code = e.ErrorCode; var message = e.Message; Debug.LogError($"Code: {code} // Message: {message}"); // [Handle error] } } } else { // [Handle data returned by the function] } });
Firebase Functions代码
index.ts
import * as Characters from "./Characters/Characters"; // CHARACTERS export const CreateNewCharacter = Characters.CreateNewCharacter; export const GetAllCharacters = Characters.GetAllCharacters; export const DeleteCharacterByID = Characters.DeleteCharacterByID;
Characters.ts
import * as functions from "firebase-functions"; import { initializeApp } from "firebase-admin/app"; // [custom classes imports] // DATABASE INITIALIZATION initializeApp(); const db = getFirestore(); // CREATE NEW CHARACTER export const CreateNewCharacter = functions.https.onCall(async (data, context) => { ... }); // GET ALL CHARACTERS export const GetAllCharacters = functions.https.onCall(async (data, context) => { ... }); // DELETE CHARACTER BY ID export const DeleteCharacterByID = functions.https.onCall(async (data, context) => { ... });
调试StackTrace
at Firebase.Functions.HttpsCallableReference.b__9_0 (System.Threading.Tasks.Task'1[TResult] task) [0x00063] in <9b40ff23f61a4fcf97a5710997860279>:0 at System.Threading.Tasks.ContinuationResultTaskFromResultTask`2[TAntecedentResult,TResult].InnerInvoke () [0x00024] in <4ba27aa039714eafa1e8892e51af2932>:0 at System.Threading.Tasks.Task.Execute () [0x00000] in <4ba27aa039714eafa1e8892e51af2932>:0
可能的问题原因
区域匹配完全错误:必须确保Unity中初始化FirebaseFunctions时指定的区域,与Google Cloud控制台中函数实际部署的区域完全一致。可以在Cloud Functions页面查看函数触发器的完整URL(如
https://us-central1-xxx.cloudfunctions.net/GetAllCharacters),提取域名中的区域部分,然后在Unity中明确指定:_func = FirebaseFunctions.GetInstance(FirebaseApp.DefaultInstance, "实际区域");注意:Firebase项目的区域和函数部署区域可能不同,以函数实际部署的区域为准。
函数部署存在隐性错误:部署过程中可能存在依赖安装失败、代码语法错误等问题,导致函数未正确上线。可以重新执行本地部署命令
firebase deploy --only functions,查看终端输出的详细错误;或在Google Cloud控制台的函数日志中搜索部署阶段的报错信息。用户认证未正确处理:Callable函数默认会校验用户身份,如果Unity调用时用户未登录,或Auth令牌无效,函数可能因未捕获异常返回INTERNAL错误。可以在函数代码开头添加日志调试:
console.log("函数触发,用户身份:", context.auth);或暂时跳过认证逻辑进行测试,确认是否是认证问题导致。
Unity网络访问限制:Unity Editor可能因代理、防火墙限制无法连接Firebase服务端。可以尝试关闭代理,或在
Edit > Project Settings > Player > Other Settings > Configuration中,确认Internet Access设置为Require。FirebaseApp初始化异常:FirebaseManager中
_app使用DefaultInstance,但如果项目存在多App实例或初始化顺序问题,可能导致Functions关联的App不正确。可以明确使用DefaultInstance初始化Functions,或检查CheckAndFixDependenciesAsync是否完成了所有依赖加载。
内容的提问来源于stack exchange,提问作者Hellcat8

