以编程方式修改 Remote Config

本文档介绍如何以编程方式读取和修改一组 JSON 格式的参数和条件(称为 Remote Config 模板)。这样您就可以在后端更改模板(客户端应用可以使用客户端库获取这些更改)。

借助此指南中所述的 Remote Config REST APIAdmin SDK,您可以绕过在 Firebase 控制台中管理模板这种方式,直接将 Remote Config 更改集成到您自己的流程中。例如,使用 Remote Config 后端 API,您可以:

  • 安排 Remote Config 更新。通过将 API 调用与 Cron 作业结合使用,您可以定期更改 Remote Config 的值。
  • 批量导入配置值,从而高效地从您自己的专有系统过渡到 Firebase Remote Config。
  • 将 Remote Config 与 Cloud Functions for Firebase 搭配使用,根据服务器端发生的事件更改应用中的值。例如,您可以使用 Remote Config 在应用中推广某项新功能,然后在检测到有足够多的用户与这项新功能进行交互后,自动关停该推广。

本指南的以下部分介绍了使用 Remote Config 后端 API 可以执行的操作。要查看通过 REST API 执行这些任务的某些代码,请参阅以下示例应用之一:

使用 Firebase Admin SDK 修改 Remote Config

Admin SDK 是一组服务器库,让您可以从特权环境与 Firebase 进行交互。除了对 Remote Config 执行更新之外,Admin SDK 还支持生成和验证 Firebase 身份验证令牌,在 Realtime Database 中进行读取和写入等。 如需详细了解 Admin SDK 的使用要求和设置,请参阅将 Firebase Admin SDK 添加到您的服务器

在典型的 Remote Config 流程中,您可能会获取当前模板,修改一些参数或参数组和条件,验证该模板,然后发布该模板。在发出这些 API 调用之前,您必须先对 SDK 发出的请求进行授权。

初始化 SDK 并授权 API 请求

如果在初始化 Admin SDK 时未提供任何参数,该 SDK 使用 Google 应用默认凭据并从 FIREBASE_CONFIG 环境变量中读取选项。如果 FIREBASE_CONFIG 变量的内容以一个 { 开头,则会被解析为一个 JSON 对象。如果不是以该字符开头,则 SDK 会假定该字符串是包含选项的 JSON 文件的名称。

例如:

const admin = require('firebase-admin');
admin.initializeApp();

获取当前的 Remote Config 模板

使用 Remote Config 模板时,请注意以下几点:这些模板受版本控制,每个版本的有效期均为 90 天(从创建之日起到使用更新版本将其替换为止),而存储的版本总数不能超过 300 个。如需了解详情,请参阅模板和版本控制

您可以使用后端 API 获取 JSON 格式的 Remote Config 模板的当前活跃版本。 要获取模板,请按以下步骤操作:

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);
      });
}

修改 Remote Config 参数

您可以通过编程方式修改和添加 Remote Config 参数和参数组。例如,向名为“new_menu”的现有参数组添加一个参数,以控制季节性信息的显示:

function addParameterToGroup(template) {
  template.parameterGroups['new_menu'].parameters['spring_season'] = {
    defaultValue: {
      useInAppDefault: true
    },
    description: 'spring season menu visibility.',
  };
}

该 API 可让您创建新参数和参数组,或修改默认值、条件值和说明。 在任何情况下,您都必须在修改后明确发布模板。

修改 Remote Config 条件

您可以通过编程方式修改和添加 Remote Config 条件和条件值。例如,要添加新条件:

function addNewCondition(template) {
  template.conditions.push({
    name: 'android_en',
    expression: 'device.os == \'android\' && device.country in [\'us\', \'uk\']',
    tagColor: 'BLUE',
  });
}

在任何情况下,您都必须在修改后明确发布模板。

Remote Config 后端 API 提供了多个条件和比较运算符,可供您更改应用的行为和外观。如需详细了解条件以及这些条件支持的运算符,请参阅条件表达式参考文档

验证 Remote Config 模板

您也可以选择在发布更新之前对其进行验证,如下所示:

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);
      });
}

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

发布 Remote Config 模板

检索到模板并使用所需更新对其进行了修改后,您就可以发布该模板了。按照本部分中的说明发布模板,将整个现有配置模板替换为更新的文件,系统会为新的活跃模板分配一个版本号,该版本号会比替换的模板大一个数字。

如有必要,可以使用 REST API 回滚到先前版本。 为了减轻更新出错的风险,您可以在发布之前先进行验证

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);
      });
}

使用 REST API 修改 Remote Config

本部分介绍 https://firebaseremoteconfig.googleapis.com 上 Remote Config REST API 的主要功能。 如需了解完整详情,请参阅 API 参考

获取访问令牌以对 API 请求进行身份验证和授权

Firebase 项目支持 Google 服务帐号,您可以使用这些帐号从应用服务器或受信任环境调用 Firebase 服务器 API。如果您在本地开发代码,或在本地部署您的应用,则可以使用通过此服务帐号获取的凭据来向服务器请求授权。

如需对服务帐号进行身份验证并授权其访问 Firebase 服务,您必须生成 JSON 格式的私钥文件。

如需为您的服务帐号生成私钥文件,请执行以下操作:

  1. 在 Firebase 控制台中,打开设置 > 服务帐号

  2. 点击生成新的私钥,然后点击生成密钥进行确认。

  3. 妥善存储包含密钥的 JSON 文件。

通过服务帐号进行授权时,有两种方式可为您的应用提供凭据。您可以设置 GOOGLE_APPLICATION_CREDENTIALS 环境变量,也可以在代码中明确传递指向服务帐号密钥的路径。第一种方式更为安全,因此我们强烈推荐。

如需设置环境变量,请执行以下操作

将环境变量 GOOGLE_APPLICATION_CREDENTIALS 设置为包含服务帐号密钥的 JSON 文件的文件路径:此变量仅适用于当前的 Shell 会话,因此请在开始新的会话时重新设置该变量。

Linux 或 macOS

export GOOGLE_APPLICATION_CREDENTIALS="/home/user/Downloads/service-account-file.json"

Windows

使用 PowerShell:

$env:GOOGLE_APPLICATION_CREDENTIALS="C:\Users\username\Downloads\service-account-file.json"

完成上述步骤后,应用默认凭据 (ADC) 能够隐式确定您的凭据,如此您便能在非 Google 环境中测试或运行时使用服务帐号凭据。

将您的 Firebase 凭据与 Google API 客户端库一起用于首选语言,以检索短期有效的 OAuth 2.0 访问令牌:

node.js

 function getAccessToken() {
  return admin.credential.applicationDefault().getAccessToken()
      .then(accessToken => {
        return accessToken.access_token;
      })
      .catch(err => {
        console.error('Unable to get access token');
        console.error(err);
      });
}

在此示例中,Google API 客户端库使用 JSON Web 令牌(JWT)对请求进行身份验证。有关详情,请参阅 JSON Web 令牌

Python

def _get_access_token():
  """Retrieve a valid access token that can be used to authorize requests.

  :return: Access token.
  """
  credentials = ServiceAccountCredentials.from_json_keyfile_name(
      'service-account.json', SCOPES)
  access_token_info = credentials.get_access_token()
  return access_token_info.access_token

Java

private static String getAccessToken() throws IOException {
  GoogleCredential googleCredential = GoogleCredential
      .fromStream(new FileInputStream("service-account.json"))
      .createScoped(Arrays.asList(SCOPES));
  googleCredential.refreshToken();
  return googleCredential.getAccessToken();
}

在您的访问令牌到期后,系统会自动调用令牌刷新方法以检索更新的访问令牌。

如需授予访问 Remote Config 的权限,应请求 https://www.googleapis.com/auth/firebase.remoteconfig 范围。

修改 Remote Config 模板

使用 Remote Config 模板时,请注意以下几点:这些模板受版本控制,每个版本的有效期均为 90 天(从创建之日起到使用更新版本将其替换为止),而存储的版本总数不能超过 300 个。如需了解详情,请参阅模板和版本控制

获取当前的 Remote Config 模板

您可以使用后端 API 获取 JSON 格式的 Remote Config 模板的当前活跃版本。 可执行以下命令:

cURL

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

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

原始 HTTP 请求

Host: firebaseremoteconfig.googleapis.com

GET /v1/projects/my-project-id/remoteConfig HTTP/1.1
Authorization: Bearer token
Accept-Encoding: gzip

此 API 调用会返回以下 JSON 以及一个单独的标头,其中包含用于后续请求的 ETag

验证 Remote Config 模板

您也可以选择在发布更新前先对其进行验证。 通过将网址参数 ?validate_only=true 附加到您的发布请求,来验证模板更新。 如果响应中包含状态代码 200 以及后缀为 -0 的更新后的 ETag,则表示您的更新已成功通过验证。如果响应中的状态代码不是 200,则表示 JSON 数据包含错误,您必须在发布前进行更正。

更新 Remote Config 模板

检索模板并使用所需更新修改 JSON 内容后,您就可以发布该模板了。按照本部分中的说明发布模板,将整个现有配置模板替换为更新的文件,系统会为新的活跃模板分配一个版本号,该版本号会比替换的模板大一个数字。

如有必要,可以使用 REST API 回滚到先前版本。 为了减轻更新出错的风险,您可以在发布之前先进行验证

cURL

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 命令,您可以使用“@”字符后跟文件名来指定相应的内容。

原始 HTTP 请求

Host: firebaseremoteconfig.googleapis.com
PUT /v1/projects/my-project-id/remoteConfig HTTP/1.1
Content-Length: size
Content-Type: application/json; UTF8
Authorization: Bearer token
If-Match: expected ETag
Accept-Encoding: gzip
JSON_HERE

由于这是一个写入请求,因此该命令将修改 ETag,并将在下一个 PUT 命令的响应标头中提供更新后的 ETag。

修改 Remote Config 条件

您可以通过编程方式修改 Remote Config 条件和条件值。使用 REST API 时,必须直接编辑模板以修改条件,然后才能发布模板。

{
  "conditions": [{
    "name": "android_english",
    "expression": "device.os == 'android' && device.country in ['us', 'uk']",
    "tagColor": "BLUE"
  }, {
    "name": "tenPercent",
    "expression": "percent <= 10",
    "tagColor": "BROWN"
  }],
  "parameters": {
    "welcome_message": {
      "defaultValue": {
        "value": "Welcome to this sample app"
      },
      "conditionalValues": {
        "tenPercent": {
          "value": "Welcome to this new sample app"
        }
      },
      "description": "The sample app's welcome message"
    },
    "welcome_message_caps": {
      "defaultValue": {
        "value": "false"
      },
      "conditionalValues": {
        "android_english": {
          "value": "true"
        }
      },
      "description": "Whether the welcome message should be displayed in all capital letters."
    }
  }
}

上述修改首先定义了一组条件,然后为每个参数定义了默认值和基于条件的参数值(“条件值”)。它还为每个元素添加了说明(可选);像代码注释一样,这些是供开发者使用的,并不显示在应用中。另外,为便于版本控制,还提供了一个 ETag

Remote Config 后端 API 提供了多个条件和比较运算符,可供您更改应用的行为和外观。如需详细了解条件以及这些条件支持的运算符,请参阅条件表达式参考文档

HTTP 错误代码

状态代码 含义
200 已成功更新
400 发生验证错误。例如,如果某个请求包含的键数超过允许的数量(2000 个),则会返回 400(请求错误)错误,并显示错误消息 Param count too large。 另外,在以下两种情况下,也可能会出现此 HTTPS 状态代码:
  • 自您上次检索 ETag 值后一组值和条件进行了更新,导致发生版本不匹配错误。要解决此错误,您应该使用 GET 命令获取最新的模板和 ETag 值,更新模板后,使用该模板和最新 ETag 值进行提交。
  • 在未指定 If-Match 标头的情况下执行了 PUT 命令(更新 Remote Config 模板请求)。
401 发生授权错误(未提供访问令牌;或者 Firebase Remote Config REST API 尚未添加到您在 Cloud Developer Console 中的项目)
403 发生身份验证错误(提供的访问令牌有误)
500 发生内部错误。如果发生此错误,请提交 Firebase 支持服务工单

如果看到状态代码 200,则意味着 Remote Config 模板(项目的参数、值和条件)已更新,现已可用于使用此项目的应用。如果看到其他状态代码,则意味着以前存在的 Remote Config 模板仍然有效。

在您提交对模板的更新后,请转到 Firebase 控制台,以验证您所做的更改是否按预期显示。这一步至关重要,因为条件的排序会影响它们的求值方式(第一个求值为 true 的条件会生效)。

ETag 用法和强制更新

Remote Config REST API 使用了实体标记 (ETag) 来避免竞态条件和对资源的重叠更新。要详细了解 ETag,请参阅 ETag - HTTP

针对 REST API,Google 建议您缓存最新 GET 命令提供的 ETag,并在发出 PUT 命令时在 If-Match 请求标头中使用该 ETag 值。如果您的 PUT 命令导致出现 HTTPS 状态代码 409,您应该发出最新 GET 命令来获取新的 ETag 和模板,供您的下一个 PUT 命令使用。

通过强制 Remote Config 模板按如下方式进行更新,您可以不使用 ETag 及其提供的保护:If-Match: *。但是,我们不建议使用此方法,因为如果有多个客户端正在更新 Remote Config 模板,此方法可能会导致对 Remote Config 模板的更新丢失。如果多个客户端都在使用 API,或者来自 API 客户端和 Firebase 控制台用户的更新存在冲突,都可能会引发这种冲突。

如需如何管理 Remote Config 模板版本的指导,请参阅 Remote Config 模板和版本控制