使用 Firebase Remote Config 检测您的 Unity 游戏

一、简介

您可以使用 Firebase Remote Config 在您的应用程序中定义键值对(也称为参数)并在云端更新它们的值,这样您就可以在不分发应用程序更新的情况下修改应用程序的外观和行为

您将把这个新功能添加到示例游戏MechaHamster: Level Up with Firebase Edition中。此示例游戏是经典 Firebase 游戏 MechaHamster 的新版本,删除了大部分内置 Firebase 功能,让您有机会在其位置实现 Firebase 的新用途。

为确保您的应用按预期运行,您将为示例游戏代码中的值设置默认配置,并且这些值可以被您在 Firebase 控制台的远程配置中设置的值覆盖。

你会学到什么

  • 如何在云中设置远程配置值并检索它们
  • 如何检测您的 Unity C# 代码以自动使用检索到的值
  • 如何将复合值/对象存储、检测和覆盖为 JSON 值
  • 如何使用 Remote Config 条件为不同的用户组提供不同的值变体

你需要什么

  • Unity 2019.1.0f1 或更高版本,支持 iOS 和/或 Android 构建
  • 用于构建和运行游戏的物理Android/iOS设备或模拟器/仿真器

2.设置你的开发环境

以下部分介绍如何下载Level Up with Firebase代码、在 Unity 中打开它以及添加 Firebase 项目。这个 Level Up with Firebase 示例游戏被其他几个 Firebase + Unity 代码实验室使用,因此您可能已经完成了本节中的任务。如果是这样,您可以跳过这些步骤并继续为 Unity 添加 Firebase SDK 以将远程配置添加到示例游戏代码。

下载代码

从命令行克隆此代码实验室的GitHub 存储库

git clone https://github.com/firebase/level-up-with-firebase

或者,如果您没有安装 git,您可以将存储库下载为 ZIP 文件

在 Unity 编辑器中打开Level Up with Firebase

  1. 启动 Unity Hub,然后从“项目”选项卡中单击“打开”旁边的下拉箭头
  2. 单击从磁盘添加项目
  3. 导航到包含代码的目录,然后单击“确定”
  4. 如果出现提示,请选择要使用的 Unity 编辑器版本和您的目标平台(Android 或 iOS)。
  5. 单击项目名称level-up-with-firebase ,项目将在 Unity 编辑器中打开。
  6. 如果您的编辑器没有自动打开它,请在 Unity 编辑器的项目选项卡中的Assets > Hamster中打开MainGameScene

有关安装和使用 Unity 的更多信息,请参阅在 Unity 中工作

3. 将 Firebase 添加到您的 Unity 项目

创建一个 Firebase 项目

  1. Firebase 控制台中,单击添加项目
  2. 要创建新项目,请输入所需的项目名称。
    这也会将项目 ID(显示在项目名称下方)设置为基于项目名称的内容。您可以选择单击项目 ID 上的编辑图标以进一步自定义它。
  3. 如果出现提示,请查看并接受Firebase 条款
  4. 单击继续
  5. 选择为此项目启用 Google Analytics选项,然后单击继续
  6. 选择要使用的现有 Google Analytics 帐户或选择创建新帐户以创建新帐户。
  7. 单击创建项目
  8. 创建项目后,单击继续

向 Firebase 注册您的应用

  1. 打开Firebase 控制台,然后从项目概览页面的中心单击 Unity 图标以启动设置工作流程,或者,如果您已将应用程序添加到 Firebase 项目,请单击添加应用程序以显示平台选项。
  2. 选择注册 Apple (iOS) 和 Android 构建目标。
  3. 输入您的 Unity 项目的平台特定 ID。对于此 Codelab,输入以下内容:
    • 对于 Apple (iOS) - 在iOS 包 ID字段中输入com.google.firebase.level-up
    • 对于 Android - 在Android 包名称字段中输入com.google.firebase.level_up
  4. 或者,输入您的 Unity 项目的平台特定昵称。
  5. 单击注册应用程序并继续下载配置文件部分。
  6. 对您第一次没有执行的任何构建目标重复该过程。

添加 Firebase 配置文件

单击Register app后,系统会提示您下载两个配置文件(每个构建目标一个配置文件)。您的 Unity 项目需要这些文件中的 Firebase 元数据才能与 Firebase 连接。

  1. 下载两个可用的配置文件:
    • 对于 Apple (iOS) :下载GoogleService-Info.plist
    • 对于 Android :下载google-services.json
  2. 打开 Unity 项目的项目窗口,然后将两个配置文件移动到Assets文件夹中。
  3. 返回 Firebase 控制台,在设置工作流程中,单击下一步并继续为 Unity 添加 Firebase SDK。

注意:您始终可以在以后重新下载这些文件,方法是打开项目的常规设置,向下滚动到您的应用程序部分,然后单击所需配置文件的下载按钮。

为 Unity 添加 Firebase SDK

  1. 单击 Firebase 控制台中的下载 Firebase Unity SDK
  2. 将 SDK 解压到方便的地方。
  3. 在您打开的 Unity 项目中,导航到Assets > Import Package > Custom Package
  4. Import package对话框中,导航到包含解压缩的 SDK 的目录,选择FirebaseAnalytics.unitypackage ,然后单击Open
  5. 在出现的“导入 Unity 包”对话框中,单击“导入”
  6. 重复前面的步骤以导入FirebaseRemoteConfig.unitypackage
  7. 返回到 Firebase 控制台,然后在设置工作流中单击下一步

有关将 Firebase SDK 添加到 Unity 项目的更多信息,请参阅其他 Unity 安装选项

4. 设置远程配置默认值并获取新值

在此 Codelab 中,您将更新使用代码中定义的值或在 Unity 编辑器中序列化的对象,以使用通过 Remote Config 检测的值。您将使用SetDefaultsAsync为每个参数配置默认值,以便您的应用在连接到远程配置后端之前按预期运行。您的应用程序将通过从 Remote Config 获取新值并激活它们以使其在代码中可用来保持最新。

要从 Remote Config 获取新值,必须完成Assets/Hamster/Scripts/MainGame.cs文件中已经存在的许多未实现的方法。

  1. 将以下using语句添加到MainGame.cs
    using Firebase.Extensions;
    using Firebase.RemoteConfig;
    
    Firebase.Extensions模块包含对C# 任务 API 的一些扩展,这将有助于简化使用回调管理初始化过程。
  2. 通过将现有的 InitializeCommonDataAndStartGame() 方法替换为当前未实现的方法InitializeFirebaseAndStartGame() ,将 Firebase 初始化添加到您的MainGame.cs Start() ) 方法:
    void Start()
    {
       Screen.SetResolution(Screen.width / 2, Screen.height / 2, true);
       InitializeFirebaseAndStartGame();
    }
    
  3. 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;
             SetRemoteConfigDefaults();
             } else {
             UnityEngine.Debug.LogError(
                $"Could not resolve all Firebase dependencies: {dependencyStatus}\n" +
                "Firebase Unity SDK is not safe to use here");
             }
          });
    }
    
  4. 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的回调参数链接调用 Remote Config 的方法FetchAsync (从 Remote Config 获取新值)和ActivateAsync (激活那些获得的值以使其在代码中可用)。

我们在上一步中添加的启动代码调用FetchRemoteConfig并将InitializeCommonDataAndStartGame作为其回调,以便在序列结束时启动游戏。您可以将替代回调传递给FetchRemoteConfig以调用具有不同结果的提取。一个示例(您将在稍后实现)传入一个打开新 UI 菜单的方法,这取决于远程配置值。这将导致菜单仅在获取并激活这些值后打开。

  1. 将下面的代码粘贴到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);
          });
    }
    
  2. 接下来,完成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加载策略

要在使用应用程序期间的其他时间获取和激活值,您需要再次调用这些函数,如果任何对象缓存了这些值,则必须通知它们执行更新。为了制定重新获取远程配置值的策略,请考虑何时需要新值以及何时启动新值的获取和激活以避免它们在使用时发生变化。

按照目前的实施,远程配置值是在应用程序启动时获取和激活的。 Fetches 可以在菜单更改期间隐藏,同时还可以在转换期间阻止交互。此外,这通常是获取新值的最相关时间,因为菜单状态的变化通常可用于了解玩家要去“哪里”并预测将使用的值。

查看 Mechahamster 的菜单系统,添加 UI 阻止菜单刷新的最简单方法是在主菜单恢复之前调用它(特别是当它通过退出另一个菜单访问时)并将 UI 显示方法作为onFetchAndActivateSuccessful回调传递。可以对Level Select菜单执行相同的操作。

将初始加载作为应用程序启动的一部分,通过主菜单的任何菜单导航都将由其中的第一个处理,而关卡选择菜单的任何重新进入也会导致刷新。最初进入关卡选择菜单并不重要,因为它只能从主菜单访问,因此已经被覆盖了。

要在应用中启用此功能,请完成主菜单和级别选择文件中的相关方法,这将阻止 UI 显示,直到FetchAsyncActivateAsync完成:

  1. 打开Assets/Hamster/Scripts/States/MainMenu.cs并将现有的Resume方法替换为以下内容:
    public override void Resume(StateExitValue results) {
       CommonData.mainGame.SelectAndPlayMusic(CommonData.prefabs.menuMusic, true);
       CommonData.mainGame.FetchRemoteConfig(InitializeUI);
    }
    
  2. 保存文件。
  3. 打开Assets/Hamster/Scripts/States/BaseLevelSelect.cs ,将现有的Resume方法替换为以下内容:
    public override void Resume(StateExitValue results) {
       CommonData.mainGame.FetchRemoteConfig(ShowUI);
    }
    
  4. 保存文件。

7.调试/验证获取行为

此时,进行诊断/验证检查是有益的。以下过程将允许您手动测试您的应用程序以及它如何/是否获取和激活远程配置值。

这些信息将作为模拟器、设备或编辑器日志的一部分打印出来。对于 iOS,您可以在 Xcode 中查看设备和模拟器日志。对于 Android,通过运行adb logcat查看日志。如果您通过在编辑器中按“播放”在 Unity 中运行代码,日志将显示在“控制台”选项卡中。

  1. 重建并运行应用程序(在编辑器中,使用设备或模拟器)。
  2. 游戏的主菜单出现后,查看游戏的日志输出,其中应包含FetchRemoteConfigActivateRetrievedRemoteConfigValues中的Debug.Log生成的日志。这些应该显示“获取数据...”和“远程数据已加载并准备就绪”消息。请注意这些消息开头的时间戳。
  3. 在游戏中,按License
  4. 确定
  5. 等待游戏的主菜单出现。
  6. 查看游戏的日志输出,它应该与前面步骤中的日志输出类似,带有新的时间戳(与运行游戏的系统时钟上设置的时间相匹配)。
  7. 在游戏中,按Play
  8. 按让我们滚动
  9. 使用键盘箭头将球导航到球门,这将打开关卡完成菜单。
  10. 级别
  11. 等待关卡选择菜单加载。
  12. 再次查看游戏的日志输出。它应该与前面步骤中的日志消息相匹配,具有较新的时间戳(与您运行游戏的系统时钟上设置的时间相匹配)。

如果其中任何一个没有出现在您的应用程序中,则可能是获取和激活流程(或您的设备)的某些部分配置错误。如果第一个日志没有出现,您的游戏可能无法启动。查看编辑器控制台或设备/模拟器日志,了解有关您的项目/环境的警告和错误,并进行调查——问题可能与连接到互联网一样简单。

如果加载菜单的初始日志出现,但后续日志之一没有出现,请调查/重新实现Assets/Hamster/Scripts/States/MainMenu.csAssets/Hamster/Scripts/States/BaseLevelSelect.cs中的Resume方法。

8.检测你的代码

现在您已经在SetDefaultsAsync()中配置了应用程序内参数值并使最新版本可用于FetchAsync()ActivateAsync() ,您将在代码中引用和使用这些值。

在远程配置后端设置值、获取它们并激活它们(或同时执行这两项操作)后,这些值便可用于您的应用程序。要使用这些值,请调用GetValue(string key )并选择参数键作为参数。这将返回一个ConfigValue ,它具有访问各种支持类型的值的属性: stringboollongdouble 。在这个项目和大多数游戏用例中,您必须将最后两种类型转换为更惯用的intfloat 。为确保这些转换不会导致问题,请确保远程配置中设置的初始值在您将在应用代码中使用的类型的有效范围内。

  1. 通过添加using Firebase.RemoteConfig;到以下文件的顶部:
    • Assets/Hamster/Scripts/States/MainMenu.cs
    • Assets/Hamster/Scripts/MapObjects/AccelerationTile.cs
  2. 替换AccelerationTile.csStart方法:
    private void Start() {
       var remoteConfig = FirebaseRemoteConfig.DefaultInstance;
       Acceleration = (float)remoteConfig.GetValue(AccelerationTileForceKey).DoubleValue;
    }
    
    通过此更改,加速瓦片施加的力的大小将更改为从远程配置接收的力。
  3. 编辑MainMenu.csInitializeUI方法的主体:
    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 控制台进行设置。

  1. Firebase 控制台中,打开您的项目。
  2. 从菜单中选择远程配置以查看远程配置仪表板。
  3. 对于您在应用中定义并在下表中列出的每个参数,单击添加参数,粘贴参数名称(键),选择表中列出的数据类型,禁用使用应用内默认值并粘贴新的默认值:

    参数名称(键)

    数据类型

    默认值

    acceleration_tile_force

    数字

    100

    字幕覆盖

    JSON

    {"text":"We overwrote the subtitle","fontSize":8,"textColor":{"r":0.0,"g":255.0,"b":0.0,"a":255.0}}

    Remote Config Parameter editor with\nacceleration_tile_force populated
  4. 单击保存以保存您的更改。
  5. 单击发布以发布新配置并使新值可用于您的游戏。
  6. 设置这些远程参数后再次运行您的应用程序,并观察它们如何覆盖原始默认值。 Mechahamster main screen with Debug\nMenu enabled

10.使用远程配置条件服务变体

您可能希望根据用户使用的语言、他们所在的位置、一天中的时间或他们使用的平台来满足用户的应用体验。远程配置条件使您能够单独或组合使用这些和其他属性来为用户提供不同的值(称为变体)。

条件的一种常见用途是在 iOS 和 Android 平台之间更改内容。按照以下步骤实现一个条件,该条件根据使用的平台为subtitle_override提供不同的值。

  1. Firebase 控制台中打开项目的远程配置选项卡。
  2. 单击subtitle_override.
  3. 在左下角,单击添加新的
  4. 在出现的下拉菜单中,将鼠标悬停在条件值上,然后单击创建新条件。 Remote Config parameter editor:\nConditional value option
  5. 出现提示时,如果您的目标是 iOS,则将条件命名为“is iOS”,如果您的目标是 Android,则命名为“is Android”。如果您的目标是两者,只需在此处选择一个并将其用于代码实验室的其余部分。 Using the Define a new condition\ndialog to define an iOS-specific condition
  6. Applys if...下,单击Select...下拉菜单并选择Platform 。然后,选择合适的平台。 Using the Define a new condition\neditor to select the iOS platform
  7. 单击创建条件以创建条件。编辑参数对话框再次出现,您现在可以设置一个值:
    • 如果您的目标是 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}}
      
  8. 单击保存以保存您的更改。
  9. 单击发布以发布新配置并使新值可用于您的游戏。

如果您再次构建并运行游戏,您应该会看到游戏的副标题被其平台特定的变体所取代。

11. 恭喜!

您已经使用 Remote Config 来远程控制游戏中的值,方法是在您的应用中获取它们并使用条件来提供不同的变体!

我们涵盖的内容

  • 如何设置和检索远程配置值
  • 如何检测您的 Unity C# 代码以使用检索到的值
  • 如何将复合值/对象存储、检测和覆盖为 JSON 值
  • 如何使用 Remote Config 条件来服务不同的值变体

下一步

阅读参数值优先级,以更好地理解应用程序实例在使用具有多个值的参数(由于条件或位置)时获取哪些值的逻辑。