Remote Config 模板和版本控制

Remote Config 模板位于服务器端,是您为 Firebase 项目创建的一组 JSON 格式的参数和条件。在 Firebase 控制台的参数条件标签页中,您可以看到以图表形式显示的模板内容,并对该模板进行修改和管理。 您还可以使用 Remote Config REST API 和 Admin SDKFirebase CLI 来修改和管理配置。

以下是模板文件的示例:

  {
    "conditions": [
      {
        "name": "ios",
        "expression": "device.os == 'ios'"
      }
    ],
    "parameters": {
      "welcome_message": {
        "defaultValue": {
          "value": "Welcome to this sample app"
        },
        "conditionalValues": {
          "ios": {
            "value": "Welcome to this sample iOS app"
          }
        }
      },
      "welcome_message_caps": {
        "defaultValue": {
          "value": "false"
        }
      },
      "header_text": {
        "defaultValue": {
          "useInAppDefault": true
        }
      }
    },
    "version": {
      "versionNumber": "28",
      "updateTime": "2020-05-14T18:39:38.994Z",
      "updateUser": {
        "email": "user@google.com"
      },
      "updateOrigin": "CONSOLE",
      "updateType": "INCREMENTAL_UPDATE"
    }
  }

每当您更新参数时,Remote Config 都会创建一个新版 Remote Config 模板,并将旧模板存储为旧版本,供您在需要时检索或回滚到此版本。第一个版本号是 Remote Config 存储的初始值,后续的版本号依序递增。如上例所示,所有模板都有一个 version 字段,其中包含相应版本的元数据。

您可以通过 Firebase 控制台、Firebase CLI 或 Remote Config 后端 API 执行以下版本管理任务:

  • 列出存储的所有模板版本
  • 检索特定版本
  • 回滚到特定版本

您可以根据需要从 Remote Config 控制台的更改历史记录页面中删除 Remote Config 模板。生命周期存储版本的总数限制为 300 个,其中包括已删除模板的存储版本号。如果您在项目生命周期内发布的模板版本超过 300 个,则最早的版本会被删除,最多保留 300 个版本。

管理 Remote Config 模板版本

本部分介绍如何管理 Remote Config 模板版本。如需详细了解如何以编程方式创建、修改和保存模板,请参阅以编程方式修改 Remote Config

列出所有已存储的 Remote Config 模板版本

您可以检索所有已存储的 Remote Config 模板版本列表。例如:

Node.js

function listAllVersions() {
  admin.remoteConfig().listVersions()
    .then((listVersionsResult) => {
      console.log("Successfully fetched the list of versions");
      listVersionsResult.versions.forEach((version) => {
        console.log('version', JSON.stringify(version));
      });
    })
    .catch((error) => {
      console.log(error);
    });
}

Java

ListVersionsPage page = FirebaseRemoteConfig.getInstance().listVersionsAsync().get();
while (page != null) {
  for (Version version : page.getValues()) {
    System.out.println("Version: " + version.getVersionNumber());
  }
  page = page.getNextPage();
}

// Iterate through all versions. This will still retrieve versions in batches.
page = FirebaseRemoteConfig.getInstance().listVersionsAsync().get();
for (Version version : page.iterateAll()) {
  System.out.println("Version: " + version.getVersionNumber());
}

REST

curl --compressed -D headers -H "Authorization: Bearer <var>token</var>" -X GET https://firebaseremoteconfig.googleapis.com/v1/projects/<var>my-project-id</var>/remoteConfig:listVersions

Firebase 控制台

参数标签页中,选择右上角显示的时钟图标。这会打开更改历史记录页面,右侧的列表菜单中会列出存储的所有模板版本。

为存储的每个版本显示的详细信息都包含更改来源的相关信息(源自控制台、REST API、回滚,还是来自强制保存模板的增量更改)。

Firebase CLI

firebase remoteconfig:versions:list

使用 --limit 选项可限制返回的版本数。传递“0”可获取所有版本。

模板列表会包含所有已存储版本的元数据,包括更新时间、进行更新的用户,以及更新是通过控制台还是 REST API 进行。下面是一个版本元素的示例:

{
  "versions": [{
    "version_number": "6",
    "update_time": "2022-05-12T02:38:54Z",
    "update_user": {
      "name": "Jane Smith",
      "email": "jane@developer.org",
      "imageUrl": "https://lh3.googleusercontent.com/a-/..."
    },
    "description": "One small change on the console",
    "origin": "CONSOLE",
    "update_type": "INCREMENTAL_UPDATE"
  }]

检索特定的 Remote Config 模板版本

您可以检索任何特定已存储的 Remote Config 模板版本。例如:

Node.js

传递不带任何参数的 getTemplate() 可检索最新版本的模板。如需检索特定版本,请使用 getTemplateAtVersion()

// Get template version: 6
admin.remoteConfig().getTemplateAtVersion('6')
  .then((template) => {
    console.log("Successfully fetched the template with ETag: " + template.etag);
  })
  .catch((error) => {
    console.log(error);
  });

Java

Template template = FirebaseRemoteConfig.getInstance().getTemplateAtVersionAsync(versionNumber).get();
// See the ETag of the fetched template.
System.out.println("Successfully fetched the template with ETag: " + template.getETag());

REST

curl --compressed -D headers -H "Authorization: Bearer <var>token</var>" -X GET https://firebaseremoteconfig.googleapis.com/v1/projects/<var>my-project-id</var>/remoteConfig?version_number=6

网址参数 ?version_number 仅对 GET 操作有效;您不能使用它为更新内容指定版本号。类似的不含 ?version_number 参数的 get 请求会检索当前的活跃模板。

Firebase 控制台

默认情况下,更改历史记录标签页中的“详细信息”窗格会显示当前活跃模板。如需查看列表中其他版本的详细信息,请从右侧菜单中将其选中。

您可以将鼠标悬停在任一未选版本的上下文菜单上并选择与选定版本进行比较,来查看当前所选版本与任何其他已存储版本之间的详细差异。

Firebase CLI

firebase remoteconfig:get -v VERSION_NUMBER

您可以选择使用 -o, FILENAME 将输出写入指定文件。

回滚到特定已存储版本的 Remote Config 模板

您可以回滚到任何已存储的模板版本。例如:

Node.js

// Roll back to template version: 6
admin.remoteConfig().rollback('6')
  .then((template) => {
    console.log("Successfully rolled back to template version 6.");
    console.log("New ETag: " + template.etag);
  })
  .catch((error) => {
    console.log('Error trying to rollback:', e);
  })

Java

try {
  Template template = FirebaseRemoteConfig.getInstance().rollbackAsync(versionNumber).get();
  System.out.println("Successfully rolled back to template version: " + versionNumber);
  System.out.println("New ETag: " + template.getETag());
} catch (ExecutionException e) {
  if (e.getCause() instanceof FirebaseRemoteConfigException) {
    FirebaseRemoteConfigException rcError = (FirebaseRemoteConfigException) e.getCause();
    System.out.println("Error trying to rollback template.");
    System.out.println(rcError.getMessage());
  }
}

REST

要回滚到已存储的 Remote Config 模板,请使用自定义方法 :rollback 发出一个 HTTP POST 请求,并在请求正文中指明要应用的具体版本。例如:

curl --compressed -D headers -H "Authorization: Bearer <var>token</var>" -H "Content-Type: application/json" -X POST https://firebaseremoteconfig.googleapis.com/v1/projects/<var>my-project-id</var>/remoteConfig:rollback -d '{"version_number": 6}'

结果会包含当前活跃的已存储模板的内容,及其新版本的元数据。

Firebase 控制台

对于支持回滚的先前模板版本,更改历史记录页面右上角会显示一个用于回滚到该版本的选项按钮。仅当您确认要回滚到该版本并立即为所有应用和用户使用这些值时,才能点击确认。

Firebase CLI

firebase remoteconfig:rollback -v VERSION_NUMBER

请注意,此回滚操作实际上会创建一个使用新版本号的版本。例如,从版本 10 回滚到版本 6 实际上会创建版本 6 的新副本,它与原版本(即版本 6)的唯一区别就是其版本号为 11。原来的版本 6 如果尚未到期,仍会存储在系统中。版本 11 会成为活跃版本。

删除 Remote Config 模板

您可以从 Firebase 控制台删除 Remote Config 模板。如需删除 Remote Config 模板,请执行以下操作:

  1. 在 Remote Config 的参数页面中,点击 更改历史记录

  2. 切换到要删除的模板,点击更多,然后选择删除

  3. 当系统提示您确认删除时,点击删除

下载和发布 Remote Config 模板

下载并发布 Remote Config 模板,以将其集成到您的源代码控制和构建系统中、自动执行配置更新,并使多个项目中的参数和值保持同步。

您可以通过编程方式或从 Firebase 控制台下载当前活跃的 Remote Config 模板。然后,您可以更新导出的 JSON 文件并将其发布到同一项目中,您也可以将其发布到新项目或其他现有项目中。

假设您有多个项目,分别代表软件开发生命周期的各个不同阶段(例如开发、测试、预演和生产环境)。在这种情况下,您可以将预演环境中经过全面测试的模板提升到生产环境中,只需从预演项目下载该模板并将其发布到生产项目中即可。

您还可以使用此方法将一个项目中的配置迁移到另一个项目,或使用某个现有项目中的参数和值来填充一个新项目。

专门作为 A/B Testing 实验中的变体而创建的参数及参数值不包含在导出的模板中。

如需导出和导入 Remote Config 模板,请执行以下操作:

  1. 下载当前的 Remote Config 配置模板
  2. 验证 Remote Config 模板
  3. 发布 Remote Config 模板

下载当前的 Remote Config 模板

您可以通过编程方式或使用 Firebase 控制台下载当前活跃的 Remote Config 模板。

使用以下命令以 JSON 格式下载活跃的 Remote Config 模板:

Node.js

function getTemplate() {
  var config = admin.remoteConfig();
  config.getTemplate()
      .then(function (template) {
        console.log('ETag from server: ' + template.etag);
        var templateStr = JSON.stringify(template);
        fs.writeFileSync('config.json', templateStr);
      })
      .catch(function (err) {
        console.error('Unable to get template');
        console.error(err);
      });
}

Java

Template template = FirebaseRemoteConfig.getInstance().getTemplateAsync().get();
// See the ETag of the fetched template.
System.out.println("ETag from server: " + template.getETag());

REST

curl --compressed -D headers -H "Authorization: Bearer token" -X GET https://firebaseremoteconfig.googleapis.com/v1/projects/my-project-id/remoteConfig -o filename

此命令会将 JSON 载荷输出到一个文件中,并将标头(包括 ETag)输出到一个单独的 headers 文件中。

Firebase 控制台

  1. Remote Config 的“参数”或“条件”标签页中,打开 菜单,然后选择下载当前配置文件
  2. 出现提示时,点击下载配置文件,选择保存该文件的位置,然后点击保存

Firebase CLI

firebase remoteconfig:get -o filename

验证 Remote Config 模板

您可以使用 Firebase Admin SDK 或 REST API 在发布模板更新之前对其进行验证。在您通过 Firebase CLI 或 Firebase 控制台尝试发布模板时,系统也会对这些模板进行验证。

此验证过程会检查错误,例如重复的参数和条件键、无效的条件名称、不存在的条件或格式错误的 ETag。例如,如果请求包含的键数超过允许的数量(2000 个),则会返回错误消息 Param count too large

Node.js

function validateTemplate(template) {
  admin.remoteConfig().validateTemplate(template)
      .then(function (validatedTemplate) {
        // The template is valid and safe to use.
        console.log('Template was valid and safe to use');
      })
      .catch(function (err) {
        console.error('Template is invalid and cannot be published');
        console.error(err);
      });
}

Java

try {
  Template validatedTemplate = FirebaseRemoteConfig.getInstance()
          .validateTemplateAsync(template).get();
  System.out.println("Template was valid and safe to use");
} catch (ExecutionException e) {
  if (e.getCause() instanceof FirebaseRemoteConfigException) {
    FirebaseRemoteConfigException rcError = (FirebaseRemoteConfigException) e.getCause();
    System.out.println("Template is invalid and cannot be published");
    System.out.println(rcError.getMessage());
  }
}

REST

将网址参数 ?validate_only=true 附加到您的发布请求,以验证模板更新:

curl --compressed -H "Content-Type: application/json; UTF8" -H "If-Match: last-returned-etag" -H "Authorization: Bearer token" -X PUT https://firebaseremoteconfig.googleapis.com/v1/projects/my-project-id/remoteConfig?validate_only=true -d @filename

如果您的模板已成功通过验证,curl 命令将返回您提交的 JSON 模板,并且在保存的 headers 文件中,您会看到一个 HTTP/2 状态 200 以及一个已更新的 ETag(带有 -0 后缀)。如果您的模板未通过验证,您将会在 JSON 响应中收到验证错误,并且您的 headers 文件将包含非 200 响应(且没有 ETag)。

发布 Remote Config 模板

下载模板后,您可以对 JSON 内容进行必要的更改并对所做更改进行验证,之后便可将模板发布到项目中。

发布模板后,现有的整个配置模板会替换为更新的文件,并且模板版本会递增 1。由于整个配置会被替换,因此,如果您在 JSON 文件中删除某个参数并发布该文件,系统会从服务器中删除该参数,并且客户端将无法再使用该参数。

发布模板后,对参数和值所做的更改会立即体现在应用中并向用户呈现。如有必要,您可以回滚到先前的版本

使用以下命令可发布模板:

Node.js

function publishTemplate() {
  var config = admin.remoteConfig();
  var template = config.createTemplateFromJSON(
      fs.readFileSync('config.json', 'UTF8'));
  config.publishTemplate(template)
      .then(function (updatedTemplate) {
        console.log('Template has been published');
        console.log('ETag from server: ' + updatedTemplate.etag);
      })
      .catch(function (err) {
        console.error('Unable to publish template.');
        console.error(err);
      });
}

Java

try {
  Template publishedTemplate = FirebaseRemoteConfig.getInstance()
          .publishTemplateAsync(template).get();
  System.out.println("Template has been published");
  // See the ETag of the published template.
  System.out.println("ETag from server: " + publishedTemplate.getETag());
} catch (ExecutionException e) {
  if (e.getCause() instanceof FirebaseRemoteConfigException) {
    FirebaseRemoteConfigException rcError = (FirebaseRemoteConfigException) e.getCause();
    System.out.println("Unable to publish template.");
    System.out.println(rcError.getMessage());
  }
}

REST

curl --compressed -H "Content-Type: application/json; UTF8" -H "If-Match: last-returned-etag" -H "Authorization: Bearer token" -X PUT https://firebaseremoteconfig.googleapis.com/v1/projects/my-project-id/remoteConfig -d @filename

对于 curl 命令,您可以使用“@”字符后跟文件名来指定相应的内容。

Firebase 控制台

  1. Remote Config 的“参数”或“条件”标签页中,打开 菜单,然后选择通过文件发布
  2. 出现提示时,点击浏览,找到并选择要发布的 Remote Config 文件,然后点击选择
  3. 系统会验证该文件,如果成功通过验证,您可以点击发布,立即将相应配置提供给您的应用和用户。

下载的模板中包含 Remote Config 个性化设置和条件,因此在尝试将模板发布到其他项目中时,务必注意以下限制:

  • 无法在不同的项目之间导入个性化设置。

    例如,如果您在项目中启用了个性化设置,之后下载并修改了一个模板,那么您可以将该模板发布到同一项目中,但不能将其发布到其他项目中,除非您删除该模板中的个性化设置。

  • 您可以在不同的项目之间导入条件,但请注意,在发布模板之前,任何特定的条件值(如应用 ID 或受众群体)必须已存在于目标项目中。

    例如,如果您的 Remote Config 参数使用了指定平台值 iOS 的条件,那么您可以将模板发布到其他项目,因为所有项目的平台值都是相同的。但是,如果其中包含的条件依赖于目标项目中不存在的特定条件值(如某个特定应用 ID 或某一特定受众群体),则验证将失败。

  • 如果您计划发布的模板包含依赖于 Google Analytics(分析)的条件,则必须在目标项目中启用 Google Analytics(分析)。

下载 Remote Config 模板默认值

由于您的应用可能有时不连网,因此您应该为所有 Remote Config 参数配置客户端应用默认值。您还应定期同步应用客户端默认值与 Remote Config 后端默认参数值,因为它们可能会随时间而变化。

如本部分末尾针对特定平台的链接中所述,您可以在应用中手动设置这些默认值,也可以下载仅包含活跃 Remote Config 模板中所有参数及其默认值的键值对的文件,来简化此流程。然后,您可以将此文件包括在项目中,并配置应用以导入这些值。

您可以下载以下格式的文件:XML 格式(对于 Android 应用)、属性列表 (plist) 格式(对于 iOS 应用)以及 JSON 格式(对于 Web 应用)。

我们建议在发布任何新的应用版本之前定期下载 Remote Config 默认值,以确保应用与 Remote Config 后端保持同步。

要下载包含模板默认值的文件,请执行以下操作:

REST

curl --compressed -D headers -H "Authorization: Bearer token -X GET https://firebaseremoteconfig.googleapis.com/v1/projects/my-project-id/remoteConfig:downloadDefaults?format=file_format'

根据您要下载的文件格式,使用 XMLPLISTJSON 作为 format 值。

Firebase 控制台

  1. 参数标签页中,打开菜单,然后选择下载默认值
  2. 收到提示时,点击与您要下载的文件格式对应的单选按钮,然后点击下载文件

如需详细了解如何将 Remote Config 默认值导入应用,请参阅以下内容: