一、简介
您可以使用 Firebase Remote Config 在应用中定义键值对(也称为参数)并在云中更新其值,从而允许您修改应用的外观和行为,而无需分发应用更新。
您将将此新功能添加到示例游戏MechaHamster: Level Up with Firebase Edition中。此示例游戏是经典 Firebase 游戏 MechaHamster 的新版本,删除了大部分内置 Firebase 功能,让您有机会在原来的位置实现 Firebase 的新用途。
为了确保您的应用按预期运行,您将为示例游戏代码中的值设置默认配置,并且这些值可以被您在 Firebase 控制台 的 Remote Config 中设置的值覆盖。
你将学到什么
- 如何在云中设置远程配置值并检索它们
- 如何检测 Unity C# 代码以自动使用检索到的值
- 如何将复合值/对象存储、检测和覆盖为 JSON 值
- 如何使用远程配置条件为不同的用户组提供不同的值变体
你需要什么
- Unity 2019.1.0f1 或更高版本,支持 iOS 和/或 Android 构建
- 用于构建和运行游戏的物理Android/iOS设备或模拟器/仿真器
2. 设置您的开发环境
以下部分介绍如何下载Level Up with Firebase代码、在 Unity 中打开它并添加 Firebase 项目。此 Level Up with Firebase 示例游戏已被其他几个 Firebase + Unity Codelab 使用,因此您可能已经完成了本部分中的任务。如果是这样,您可以跳过这些步骤并继续添加适用于 Unity 的 Firebase SDK 以将远程配置添加到示例游戏代码中。
下载代码
从命令行克隆此 Codelab 的GitHub 存储库:
git clone https://github.com/firebase/level-up-with-firebase
或者,如果您没有安装 git,则可以将存储库下载为 ZIP 文件。
在 Unity 编辑器中使用 Firebase 打开 Level Up
- 启动 Unity Hub,然后从“项目”选项卡中单击“打开”旁边的下拉箭头。
- 单击从磁盘添加项目。
- 导航到包含代码的目录,然后单击“确定” 。
- 如果出现提示,请选择要使用的 Unity 编辑器版本以及您的目标平台(Android 或 iOS)。
- 单击项目名称level-up-with-firebase ,该项目将在 Unity 编辑器中打开。
- 如果您的编辑器没有自动打开它,请在 Unity 编辑器的“项目”选项卡中的“资源” > “Hamster”中打开
MainGameScene
。
有关安装和使用 Unity 的更多信息,请参阅在 Unity 中工作。
3. 将 Firebase 添加到您的 Unity 项目
创建 Firebase 项目
- 在Firebase 控制台中,单击添加项目。
- 要创建新项目,请输入所需的项目名称。
这还将根据项目名称将项目 ID(显示在项目名称下方)设置为某些内容。您可以选择单击项目 ID 上的编辑图标以进一步自定义它。 - 如果出现提示,请查看并接受Firebase 条款。
- 单击继续。
- 选择为此项目启用 Google Analytics选项,然后单击继续。
- 选择要使用的现有 Google Analytics 帐户,或选择创建新帐户来创建新帐户。
- 单击创建项目。
- 创建项目后,单击“继续” 。
向 Firebase 注册您的应用
- 打开Firebase 控制台,然后从项目概述页面的中心单击 Unity 图标以启动设置工作流程,或者,如果您已将应用添加到 Firebase 项目,请单击添加应用以显示平台选项。
- 选择注册 Apple (iOS) 和 Android 构建目标。
- 输入 Unity 项目的平台特定 ID。对于此 Codelab,请输入以下内容:
- 对于 Apple (iOS) - 在iOS 捆绑包 ID字段中输入
com.google.firebase.level-up
。 - 对于 Android - 在Android 包名称字段中输入
com.google.firebase.level_up
。
- 对于 Apple (iOS) - 在iOS 捆绑包 ID字段中输入
- (可选)输入 Unity 项目的平台特定昵称。
- 单击注册应用程序并继续下载配置文件部分。
- 对第一次未执行的构建目标重复此过程。
添加 Firebase 配置文件
单击Register app后,系统将提示您下载两个配置文件(每个构建目标一个配置文件)。您的 Unity 项目需要这些文件中的 Firebase 元数据才能与 Firebase 连接。
- 下载两个可用的配置文件:
- 对于 Apple (iOS) :下载GoogleService-Info.plist 。
- 对于 Android :下载google-services.json 。
- 打开 Unity 项目的“项目”窗口,然后将两个配置文件移动到Assets文件夹中。
- 返回 Firebase 控制台的设置工作流程中,单击下一步并继续添加适用于 Unity 的 Firebase SDK。
注意:您可以随时重新下载这些文件,方法是打开项目的常规设置,向下滚动到您的应用程序部分,然后单击所需配置文件的下载按钮。
添加适用于 Unity 的 Firebase SDK
- 单击 Firebase 控制台中的“下载 Firebase Unity SDK” 。
- 将 SDK 解压到方便的地方。
- 在打开的 Unity 项目中,导航至Assets > Import Package > Custom Package 。
- 在“导入包”对话框中,导航到包含解压缩的 SDK 的目录,选择
FirebaseAnalytics.unitypackage
,然后单击“打开” 。 - 在出现的“导入 Unity 包”对话框中,单击“导入” 。
- 重复前面的步骤导入以下两个包:
-
FirebaseRemoteConfig.unitypackage
-
FirebaseCrashlytics.unitypackage
Crashlytics 是一款轻量级的实时崩溃报告程序,可帮助您跟踪、确定优先级并修复影响应用程序质量的稳定性问题。如果您以前没有使用过它,请考虑完成Unity 的 Crashlytics 学习路径。
-
- 返回 Firebase 控制台,然后在设置工作流程中单击“下一步” 。
有关将 Firebase SDK 添加到 Unity 项目的更多信息,请参阅其他 Unity 安装选项。
4. 设置远程配置默认值并获取新值
在此 Codelab 中,您将更新使用代码中定义的值或在 Unity 编辑器中序列化的对象,以使用通过 Remote Config 检测的值。您将使用SetDefaultsAsync
配置每个参数的默认值,以便您的应用在连接到远程配置后端之前按预期运行。您的应用程序将通过从远程配置获取新值并激活它们以使其可在代码中使用来保持最新状态。
要从远程配置获取新值, Assets/Hamster/Scripts/MainGame.cs
文件中已存在许多未实现的方法,必须完成这些方法。
- 将以下
using
语句添加到MainGame.cs
:using Firebase.Crashlytics; using Firebase.Extensions; using Firebase.RemoteConfig;
Firebase.Extensions
模块包含对C# 任务 API 的一些扩展,这将有助于简化使用回调管理初始化过程。 - 将 Firebase 初始化添加到
MainGame.cs
Start()
方法中,方法是将现有的 InitializeCommonDataAndStartGame() 方法替换为当前未实现的方法InitializeFirebaseAndStartGame()
:void Start() { Screen.SetResolution(Screen.width / 2, Screen.height / 2, true); InitializeFirebaseAndStartGame(); }
- 在
MainGame.cs
中,找到InitializeFirebaseAndStartGame()
。声明一个 app 变量并覆盖该方法的实现,如下所示:public Firebase.FirebaseApp app = null; // Begins the firebase initialization process and afterwards, opens the main menu. private void InitializeFirebaseAndStartGame() { Firebase.FirebaseApp.CheckAndFixDependenciesAsync() .ContinueWithOnMainThread( previousTask => { var dependencyStatus = previousTask.Result; if (dependencyStatus == Firebase.DependencyStatus.Available) { // Create and hold a reference to your FirebaseApp, app = Firebase.FirebaseApp.DefaultInstance; // Set the recommended Crashlytics uncaught exception behavior. Crashlytics.ReportUncaughtExceptionsAsFatal = true; SetRemoteConfigDefaults(); } else { UnityEngine.Debug.LogError( $"Could not resolve all Firebase dependencies: {dependencyStatus}\n" + "Firebase Unity SDK is not safe to use here"); } }); }
- Firebase 初始化在成功时调用
SetRemoteConfigDefaults
以设置应用内默认值。将未实现的 SetRemoteConfigDefaults 方法替换为以下内容:private void SetRemoteConfigDefaults() { var defaults = new System.Collections.Generic.Dictionary < string, object > (); defaults.Add( Hamster.MapObjects.AccelerationTile.AccelerationTileForceKey, Hamster.MapObjects.AccelerationTile.AccelerationTileForceDefault); defaults.Add( Hamster.States.MainMenu.SubtitleOverrideKey, Hamster.States.MainMenu.SubtitleOverrideDefault); var remoteConfig = FirebaseRemoteConfig.DefaultInstance; remoteConfig.SetDefaultsAsync(defaults).ContinueWithOnMainThread( previousTask => { FetchRemoteConfig(InitializeCommonDataAndStartGame); } ); }
5. 获取并激活新值(根据需要)
我们现在需要完成现有的FetchRemoteConfig
方法。这将使用名为onFetchAndActivateSuccessful
的回调参数链接调用远程配置的方法FetchAsync
(从远程配置获取新值)和ActivateAsync
(激活这些获取的值以使其在代码中可用)。
我们在上一步中添加的启动代码调用FetchRemoteConfig
并使用InitializeCommonDataAndStartGame
作为其回调,以便在序列末尾启动游戏。您可以将替代回调传递给FetchRemoteConfig
,以便调用具有不同结果的提取。一个示例(您将在稍后实现)是传入一个打开新 UI 菜单的方法,该菜单取决于远程配置值。这将导致菜单仅在获取并激活这些值后打开。
- 将以下代码粘贴到
FetchRemoteConfig
中:public void FetchRemoteConfig(System.Action onFetchAndActivateSuccessful) { if(app==null) { Debug.LogError($"Do not use Firebase until it is properly initialized by calling {nameof(InitializeFirebaseAndStartGame)}."); return; } Debug.Log("Fetching data..."); var remoteConfig = FirebaseRemoteConfig.DefaultInstance; remoteConfig.FetchAsync(System.TimeSpan.Zero).ContinueWithOnMainThread( previousTask=> { if (!previousTask.IsCompleted) { Debug.LogError($"{nameof(remoteConfig.FetchAsync)} incomplete: Status '{previousTask.Status}'"); return; } ActivateRetrievedRemoteConfigValues(onFetchAndActivateSuccessful); }); }
- 接下来,完成
ActivateRetrievedRemoteConfigValues
方法,该方法接收传入的回调onFetchAndActivateSuccessful
。激活完成后,将调用指定的回调:private void ActivateRetrievedRemoteConfigValues(System.Action onFetchAndActivateSuccessful) { var remoteConfig = FirebaseRemoteConfig.DefaultInstance; var info = remoteConfig.Info; if(info.LastFetchStatus == LastFetchStatus.Success) { remoteConfig.ActivateAsync().ContinueWithOnMainThread( previousTask => { Debug.Log($"Remote data loaded and ready (last fetch time {info.FetchTime})."); onFetchAndActivateSuccessful(); }); } }
当SetRemoteConfigDefaults
从初始化上下文向下游调用时, ActivateRetrievedRemoteConfigValues
会调用之前的起点InitializeCommonDataAndStartGame
来通过打开主菜单来启动游戏。
6. 设置Remote Config加载策略
要在使用应用程序期间的其他时间获取并激活值,您需要再次调用这些函数,并且如果任何对象已缓存这些值,则必须通知它们执行更新。为了制定重新获取远程配置值的策略,请考虑何时需要新值以及何时启动新值的获取和激活,以避免它们在使用时发生更改。
按照目前的实施方式,当应用程序启动时,将获取并激活远程配置值。可以在菜单更改期间隐藏获取,同时还可以在转换期间阻止交互。此外,这通常是获取新值的最相关时间,因为菜单状态的变化通常可用于了解玩家要去“哪里”并预测将使用某个值。
纵观 Mechahamster 的菜单系统,添加 UI 阻止菜单刷新的最简单方法是在主菜单恢复之前调用它(特别是当通过退出另一个菜单来访问它时),并将 UI 显示方法作为onFetchAndActivateSuccessful
回调传递。对于“级别选择”菜单也可以执行相同的操作。
将初始加载作为应用程序启动的一部分,任何经过主菜单的菜单导航都将由第一个菜单处理,而任何重新进入级别选择菜单也将导致刷新。最初进入关卡选择菜单并不重要,因为它只能从主菜单访问,因此已经被覆盖。
要在应用程序中启用此功能,请完成主菜单和级别选择文件中的相关方法,这将阻止 UI 显示,直到FetchAsync
和ActivateAsync
完成:
- 打开
Assets/Hamster/Scripts/States/MainMenu.cs
并将现有的Resume
方法替换为以下内容:public override void Resume(StateExitValue results) { CommonData.mainGame.SelectAndPlayMusic(CommonData.prefabs.menuMusic, true); CommonData.mainGame.FetchRemoteConfig(InitializeUI); }
- 保存文件。
- 打开
Assets/Hamster/Scripts/States/BaseLevelSelect.cs
,将现有的Resume
方法替换为以下内容:public override void Resume(StateExitValue results) { CommonData.mainGame.FetchRemoteConfig(ShowUI); }
- 保存文件。
7. 调试/验证获取行为
此时,进行诊断/验证检查是有益的。以下过程将允许您手动测试您的应用程序以及它如何/是否获取和激活远程配置值。
该信息将作为模拟器、设备或编辑器日志的一部分打印。对于 iOS,您可以在 Xcode 中查看设备和模拟器日志。对于 Android,通过运行adb logcat
查看日志。如果您通过在编辑器中按 Play 来运行 Unity 中的代码,日志将显示在“控制台”选项卡中。
- 重建并运行应用程序(在编辑器中,使用设备或模拟器)。
- 游戏的主菜单出现后,查看游戏的日志输出,其中应包含
FetchRemoteConfig
和ActivateRetrievedRemoteConfigValues
中的Debug.Log
生成的日志。这些应该显示“正在获取数据...”和“远程数据已加载并准备就绪”消息。请注意这些消息开头的时间戳。 - 在游戏中,按许可证。
- 按确定。
- 等待游戏的主菜单出现。
- 检查游戏的日志输出,它应该与之前步骤中的日志输出类似,并带有新的时间戳(与运行游戏的系统时钟上设置的时间相匹配)。
- 在游戏中,按“开始” 。
- 按“开始吧” 。
- 使用键盘箭头将球引导至球门,这将打开“关卡完成”菜单。
- 按级别。
- 等待级别选择菜单加载。
- 再次查看游戏的日志输出。它应该与之前步骤中的日志消息和较新的时间戳相匹配(与运行游戏的系统时钟上设置的时间相匹配)。
如果其中任何一个没有出现在您的应用程序中,则提取和激活流程(或您的设备)的某些部分可能配置错误。如果第一个日志没有出现,您的游戏可能无法启动。查看编辑器控制台或设备/模拟器日志中有关您的项目/环境的警告和错误并进行调查 - 问题可能就像连接到互联网一样简单。
如果加载菜单的初始日志出现,但后续日志之一没有出现,请调查/重新实现Assets/Hamster/Scripts/States/MainMenu.cs
和Assets/Hamster/Scripts/States/BaseLevelSelect.cs
中的Resume
方法。
8. 检测你的代码
现在,您已在SetDefaultsAsync()
中配置了应用内参数值,并通过FetchAsync()
和ActivateAsync()
提供了最新版本,您将在代码中引用和使用这些值。
在远程配置后端设置值、获取它们并激活它们(或同时执行这两项操作)后,这些值可供您的应用程序使用。要使用这些值,请调用GetValue(string key )
,并选择参数键作为参数。这会返回一个ConfigValue
,它具有用于访问各种受支持类型的值的属性: string
、 bool
、 long
、 double
。在此项目和大多数游戏用例中,您必须将最后两种类型转换为更惯用的int
和float
。为了确保这些转换不会导致问题,请确保远程配置中设置的初始值位于您将在应用代码中使用的类型的有效范围内。
- 通过
using Firebase.RemoteConfig;
到以下文件的顶部:-
Assets/Hamster/Scripts/States/MainMenu.cs
-
Assets/Hamster/Scripts/MapObjects/AccelerationTile.cs
-
- 替换
AccelerationTile.cs
的Start
方法:
通过此更改,加速图块施加的力值将更改为从远程配置接收的力值。private void Start() { var remoteConfig = FirebaseRemoteConfig.DefaultInstance; Acceleration = (float)remoteConfig.GetValue(AccelerationTileForceKey).DoubleValue; }
- 编辑
MainMenu.cs
的InitializeUI
方法的主体:
此处,private void InitializeUI() { if (menuComponent == null) { menuComponent = SpawnUI<Menus.MainMenuGUI>(StringConstants.PrefabMainMenu); } var remoteConfig = FirebaseRemoteConfig.DefaultInstance; var subtitleOverride = JsonUtility.FromJson<Menus.MainMenuGUI.SubtitleOverride>( remoteConfig.GetValue(SubtitleOverrideKey).StringValue); // Only sets values if all fields of the override are non-default. if(subtitleOverride != null && subtitleOverride.IsValidOverride()) { menuComponent.MenuSubtitleText.text = subtitleOverride.text; menuComponent.MenuSubtitleText.fontSize = subtitleOverride.fontSize; menuComponent.MenuSubtitleText.color = subtitleOverride.textColor; } ShowUI(); }
subtitleOverride
设置为更改主菜单屏幕上的副标题(如果其在云中的所有字段都设置为其类型的默认值以外的值)。
9. 远程设置参数值
现在您的应用程序已完全安装完毕,您可以在远程配置服务器上配置参数和值。在此 Codelab 中,我们将使用 Firebase 控制台进行设置。
- 在Firebase 控制台中,打开您的项目。
- 从菜单中选择远程配置以查看远程配置仪表板。
- 对于您在应用程序中定义并在下表中列出的每个参数,单击添加参数,粘贴参数名称(键),选择表中列出的数据类型,禁用使用应用程序内默认值并粘贴新的默认值:
参数名称(键)
数据类型
默认值
加速度瓦力
数字
100
字幕覆盖
JSON
{"text":"We overwrote the subtitle","fontSize":8,"textColor":{"r":0.0,"g":255.0,"b":0.0,"a":255.0}}
- 单击“保存”以保存您的更改。
- 单击“发布”以发布新配置并使新值可用于您的游戏。
- 设置这些远程参数后再次运行您的应用程序,并观察它们如何覆盖原始默认值。
10.使用远程配置条件来服务变体
您可能希望根据用户使用的语言、所在位置、一天中的时间或使用的平台来满足用户的应用体验。远程配置条件使您能够单独或组合使用这些属性和其他属性,为用户提供不同的值(称为变体)。
条件的一种常见用途是在 iOS 和 Android 平台之间更改内容。请按照以下步骤实施一个条件,根据所使用的平台为subtitle_override
提供不同的值。
- 在Firebase 控制台中打开项目的“远程配置”选项卡。
- 单击
subtitle_override.
- 在左下角,单击添加新的。
- 在出现的下拉列表中,将鼠标悬停在条件值上,然后单击创建新条件。
- 出现提示时,如果您的目标是 iOS,则将条件命名为“is iOS”;如果您的目标是 Android,则将条件命名为“is Android”。如果您的目标是两者,只需在此处选择一个并将其用于 Codelab 的其余部分。
- 在“适用于...”下,单击“选择...”下拉列表并选择“平台” 。然后,选择合适的平台。
- 单击创建条件以创建条件。编辑参数对话框再次出现,您现在可以设置一个值:
- 如果您面向 Android,请将值设置为:
{"text":"Level Up Android Version","fontSize":8,"textColor":{"r":0.0,"g":255.0,"b":0.0,"a":255.0}}
- 如果您的目标是 iOS,请将值设置为:
{"text":"Level Up iOS Version","fontSize":8,"textColor":{"r":0.0,"g":255.0,"b":0.0,"a":255.0}}
- 如果您面向 Android,请将值设置为:
- 单击“保存”以保存您的更改。
- 单击“发布”以发布新配置并使新值可用于您的游戏。
如果您再次构建并运行游戏,您应该会看到游戏的副标题被替换为特定于平台的变体。
11. 配置 Remote Config 以接收实时更新
远程配置现在可以实时监听并处理远程配置模板的更新。应用程序可以订阅新的实时远程配置 API 以侦听配置更改和更新值。
怎么运行的
要侦听更新,您的应用程序必须实现订阅OnConfigUpdateListener
事件的方法。当订阅一个或多个配置更新侦听器时,将自动获取新的远程配置模板,调用订阅的处理程序并可用于执行响应逻辑,例如激活新值并使它们可供应用程序的其余部分使用。
实施实时远程配置
为了说明其在游戏中的工作原理,请对您的代码进行以下更改。
创建配置更新处理程序
使用配置更新事件的第一步是创建一个能够侦听该事件的方法。将以下方法放入Assets/Hamster/Scripts/MainGame.cs
中:
void ActivateValuesOnConfigUpdate( object sender, ConfigUpdateEventArgs args)
{
if (args.Error != RemoteConfigError.None) {
Debug.Log($"Error occurred while listening: {args.Error}");
return;
}
Debug.Log("Updated keys: " + string.Join(", ", args.UpdatedKeys));
// Activate all fetched values and then logs.
var remoteConfig = FirebaseRemoteConfig.DefaultInstance;
remoteConfig.ActivateAsync().ContinueWithOnMainThread(
task => {
Debug.Log($"Keys from {nameof(ActivateValuesOnConfigUpdate)} activated.");
});
}
当激活新值时,此方法将在日志中打印更新的键列表和成功消息。
订阅更新事件
为了在调用该事件时激活ActivateValuesOnConfigUpdate
,请订阅该事件。将Assets/Hamster/Scripts/MainGame.cs
中的InitializeCommonDataAndStartGame()
方法替换为以下内容:
void InitializeCommonDataAndStartGame()
{
CommonData.prefabs = FindObjectOfType<PrefabList>();
CommonData.mainCamera = FindObjectOfType<CameraController>();
CommonData.mainGame = this;
Screen.orientation = ScreenOrientation.LandscapeLeft;
musicPlayer = CommonData.mainCamera.GetComponentInChildren<AudioSource>();
CommonData.gameWorld = FindObjectOfType<GameWorld>();
// Set up volume settings.
MusicVolume = PlayerPrefs.GetInt(StringConstants.MusicVolume, MaxVolumeValue);
// Set the music to ignore the listeners volume, which is used for sound effects.
CommonData.mainCamera.GetComponentInChildren<AudioSource>().ignoreListenerVolume = true;
SoundFxVolume = PlayerPrefs.GetInt(StringConstants.SoundFxVolume, MaxVolumeValue);
// Subscribes to on config update after first initial fetch and activate
FirebaseRemoteConfig.DefaultInstance.OnConfigUpdateListener += ActivateValuesOnConfigUpdate;
stateManager.PushState(new States.MainMenu());
}
新行(以+= ActivateValuesOnConfigUpdate;
结尾)将事件处理程序订阅到该事件。
当处理程序所属的对象被销毁时取消订阅
为了防止空引用错误,具有订阅事件方法的对象在销毁时必须取消订阅该方法。将以下方法添加到Assets/Hamster/Scripts/MainGame.cs
中:
private void OnDestroy()
{
FirebaseRemoteConfig.DefaultInstance.OnConfigUpdateListener -= ActivateValuesOnConfigUpdate;
}
测试新功能
要验证新功能,请尝试您构建的应用程序。以下过程要求您可以使用真实设备读取日志并进行调试。
改变acceleration_tile_force
并观察
启动应用程序后,在 Firebase 控制台的“远程配置”部分中:
- 按
acceleration_tile_force
旁边的编辑按钮。
- 将值更改为“120”并按“保存” 。
- 单击“发布更改”按钮。
- 检查日志。
- 如果您看到以“侦听时发生错误”开头的日志消息,请阅读其余部分并尝试使用它打印的错误消息进行调试。
- 如果您看到以“更新的密钥”开头的日志,则您的应用程序已收到更改的值。
- 如果您没有看到这些,请查看其余日志,然后重新查看创建配置更新处理程序中的说明,重新测试并重新检查日志以确定是否有任何问题。
12. 恭喜!
您已经使用远程配置来远程控制游戏中的值,方法是在您的应用程序中获取它们并使用条件来提供不同的变体!
我们涵盖的内容
- 如何设置和检索远程配置值
- 如何检测 Unity C# 代码以使用检索到的值
- 如何将复合值/对象存储、检测和覆盖为 JSON 值
- 如何使用远程配置条件来提供不同的值变体
下一步
阅读参数值优先级,以更好地了解当应用程序实例使用具有多个值的参数(由于条件或位置)时,应用程序实例获取哪些值的逻辑。