独立的开发和生产 Firebase 环境

Separate dev and prod Firebase environment

我正在考虑使用 Firebase 作为 MBaaS,但是我找不到任何可靠的解决方案来解决以下问题:

我想设置两个独立的 Firebase 环境,一个用于开发,一个用于生产,但我不想手动复制功能(例如远程配置设置、通知规则等)在开发和生产环境之间。

有没有我可以依赖的工具或方法?从头开始设置远程配置或通知规则可能是一项艰巨的任务,而且风险太大。

有什么建议吗?有没有比拥有两个独立环境更好的方法?

在你之前 post 另一个解释如何设置单独的 Firebase 帐户的问题的答案:这不是问题,再读一遍。问题是:如何在单独的开发帐户和生产帐户之间传输更改,或者比在它们之间手动复制更好的解决方案。

我目前没有使用 Firebase,但像您一样在考虑。看起来要走的路是在控制台上创建一个完全独立的项目。在旧的 Firebase 网站上有一篇博文推荐这个,不过现在看起来要删除了。 https://web.archive.org/web/20160310115701/https://www.firebase.com/blog/2015-10-29-managing-development-environments.html

这个讨论也推荐相同的: https://groups.google.com/forum/#!msg/firebase-talk/L7ajIJoHPcA/7dsNUTDlyRYJ

如果您使用的是 firebase-tools,则可以使用命令 firebase use 设置要用于 firebase deploy

的项目

firebase use --add 将显示您的项目列表,select 一个,它会要求您提供别名。从那里你可以 firebase use alias 并且 firebase deploy 将推送到那个项目。

在我个人使用中,我将 my-app 和 my-app-dev 作为 Firebase 控制台中的项目。

This blogpost 描述了一种非常简单的调试和发布构建类型的方法。

简而言之:

  • Create a new App on Firebase for each build type using different application id suffix.
  • Configure your Android project with the latest JSON file.
  • Using applicationIdSuffix, change the Application Id to match the different Apps on Firebase depending on the build type.

=> 请参阅博文了解详细说明。

如果您想使用不同的构建风格,请阅读来自官方 firebase 博客的内容广泛的 blogpost。它包含很多有价值的信息。

希望对您有所帮助!

您将需要管理不同的构建类型

关注这个

  1. 首先在Firebase控制台新建一个项目,id命名为YOURAPPNAME-DEV

  2. 单击 "Add android app" 按钮并创建一个新应用。例如,将其命名为 com.yourapp.debug。新 google-services.json 文件将 自动下载

  3. 在您的项目 src 目录下创建名称为 "debug" 的新目录并在此处复制新的 google-services.json 文件

  4. 在你的模块级别build.gradle添加这个

    debug {
            applicationIdSuffix ".debug"
        }
    

现在,当您构建调试版本时,将使用 "debug" 文件夹中的 google-services.json,当您以发布模式构建时 google-services.json 来自模块根目录的将被考虑。

我的做法:

  1. 我在 firebase 上有 2 个项目——一个用于 DEV,另一个用于 PROD
  2. 我的应用程序在本地也有 2 个分支 - 一个名为 DEV,另一个名为 PROD
  3. 在我的 DEV 分支中,我总是有 JSON DEV firebase 项目的文件,同样适用于 PROD

这样我就不需要维护我的 JSONs。

我们的做法是为不同的环境创建不同的 json 密钥文件。我们使用了 google 推荐的服务帐户功能,并且有一个开发文件和另一个用于生产的文件

Firebase 有一个关于此的页面,其中介绍了如何为开发和生产进行设置

https://firebase.google.com/docs/functions/config-env

Set environment configuration for your project To store environment data, you can use the firebase functions:config:set command in the Firebase CLI. Each key can be namespaced using periods to group related configuration together. Keep in mind that only lowercase characters are accepted in keys; uppercase characters are not allowed.

For instance, to store the Client ID and API key for "Some Service", you might run:

firebase functions:config:set someservice.key="THE API KEY" someservice.id="THE CLIENT ID"

Retrieve current environment configuration To inspect what's currently stored in environment config for your project, you can use firebase functions:config:get. It will output JSON something like this:

{
  "someservice": {
    "key":"THE API KEY",
    "id":"THE CLIENT ID"
  }
}

正如大家指出的那样 - 你需要不止一个 project/database。

但要回答您关于需要能够将 settings/data 等从开发复制到生产的问题。我有完全相同的需求。几个月的开发测试,不想手动copy数据

我的结果是将数据备份到存储桶中,然后从那里将其恢复到另一个数据库中。这是一种非常粗略的方法 - 我做了整个数据库 backup/restore - 但你可以朝那个方向寻找一种更可控的方式。我没用过它 - 它很新 - 但这可能是一个解决方案:NPM Module firestore-export-import

编辑:Firestore backup/export/import 此处提供信息 Cloud Firestore Exporting and Importing Data

如果您使用的是 Firebase RTDB,而不是 Firestore - 此文档可能会有所帮助: Firebase Automated Backups

您需要正确设置权限,以允许您的生产数据库访问与您的开发相同的存储桶。 祝你好运。

我正在根据刚刚找到的信息更新此答案。

步骤 1

在 firebase.google.com 中,创建您的多个环境(即;开发、暂存、生产)


mysite-dev

mysite-staging

mysite-prod


步骤 2

一个。移动到您希望成为默认设置的直接位置(即;dev)

b。 运行firebase deploy

c。部署后,运行 firebase use --add

d。从您当前拥有的不同项目中,一个选项将达到 select。

滚动到您要添加的项目:mysite-staging,然后 select 它。

e。然后系统会要求您为该项目提供一个别名。输入 staging.

运行 项目 a-e 再次用于 prod 和 dev,这样每个环境都会有一个别名


了解您所处的环境

运行 firebase use default (mysite-dev)

* dev (mysite-dev)

staging (mysite-staging)

prod (mysite-dev)

(其中一个环境的左侧会有一个星号。这就是您当前所在的环境。它也将以蓝色突出显示)


在环境之间切换

运行 firebase use stagingfirebase use prod 在它们之间移动。

进入所需环境后,运行 firebase deploy 和您的项目将部署到那里。

这里有几个有用的链接...

CLI Reference

Deploying to multiple environments

希望这对您有所帮助。

为了针对我的情况解决这个问题,我创建了三个 Firebase 项目,每个项目都有相同的 Android 项目(即相同的 applicationId,但不使用其他人建议的 applicationIdSuffix)。这导致我存储在 Continuous Integration (CI) server as custom environment variables 中的三个 google-services.json 文件。对于构建的每个阶段 (dev/staging/prod),我使用了相应的 google-services.json 文件。

对于与dev关联的Firebase项目,在其Android项目中,我添加了调试SHA证书指纹。但是对于暂存和生产,我只需要 CI 签署 APK。

这是适用于此设置的精简 .gitlab-ci.yml

# This is a Gitlab Continuous Integration (CI) Pipeline definition
# Environment variables:
#   - variables prefixed CI_ are Gitlab predefined environment variables (https://docs.gitlab.com/ee/ci/variables/predefined_variables.html)
#   - variables prefixed GNDR_CI are Gitlab custom environment variables (https://docs.gitlab.com/ee/ci/variables/#creating-a-custom-environment-variable)
#
# We have three Firebase projects (dev, staging, prod) where the same package name is used across all of them but the
# debug signing certificate is only provided for the dev one (later if there are other developers, they can have their
# own Firebase project that's equivalent to the dev one).  The staging and prod Firebase projects use real certificate
# signing so we don't need to enter a Debug signing certificate for them.  We don't check the google-services.json into
# the repository.  Instead it's provided at build time either on the developer's machine or by the Gitlab CI server
# which injects it via custom environment variables.  That way the google-services.json can reside in the default
# location, the projects's app directory.  The .gitlab-ci.yml is configured to copy the dev, staging, and prod equivalents
# of the google-servies.json file into that default location.
#
# References:
# https://firebase.googleblog.com/2016/08/organizing-your-firebase-enabled-android-app-builds.html
# 

stages:
  - stg_build_dev
  - stg_build_staging
  - stg_build_prod

jb_build_dev:
  stage: stg_build_dev
  image: jangrewe/gitlab-ci-android
  cache:
    key: ${CI_PROJECT_ID}-android
    paths:
      - .gradle/
  script:
    - cp ${GNDR_CI_GOOGLE_SERVICES_JSON_DEV_FILE} app/google-services.json
    - ./gradlew :app:assembleDebug
  artifacts:
    paths:
      - app/build/outputs/apk/

jb_build_staging:
  stage: stg_build_staging
  image: jangrewe/gitlab-ci-android
  cache:
    key: ${CI_PROJECT_ID}-android
    paths:
      - .gradle/
  dependencies: []
  script:
    - cp ${GNDR_CI_GOOGLE_SERVICES_JSON_STAGING_FILE} app/google-services.json
    - ./gradlew :app:assembleDebug
  artifacts:
    paths:
      - app/build/outputs/apk/

jb_build_prod:
  stage: stg_build_prod
  image: jangrewe/gitlab-ci-android
  cache:
    key: ${CI_PROJECT_ID}-android
    paths:
      - .gradle/
  dependencies: []
  script:
    - cp ${GNDR_CI_GOOGLE_SERVICES_JSON_PROD_FILE} app/google-services.json

    # GNDR_CI_KEYSTORE_FILE_BASE64_ENCODED created on Mac via:
    # base64 --input ~/Desktop/gendr.keystore --output ~/Desktop/keystore_base64_encoded.txt
    # Then the contents of keystore_base64_encoded.txt were copied and pasted as a Gitlab custom environment variable
    # For more info see http://android.jlelse.eu/android-gitlab-ci-cd-sign-deploy-3ad66a8f24bf
    - cat ${GNDR_CI_KEYSTORE_FILE_BASE64_ENCODED} | base64 --decode > gendr.keystore

    - ./gradlew :app:assembleRelease
      -Pandroid.injected.signing.store.file=$(pwd)/gendr.keystore
      -Pandroid.injected.signing.store.password=${GNDR_CI_KEYSTORE_PASSWORD}
      -Pandroid.injected.signing.key.alias=${GNDR_CI_KEY_ALIAS}
      -Pandroid.injected.signing.key.password=${GNDR_CI_KEY_PASSWORD}
  artifacts:
    paths:
      - app/build/outputs/apk/

我对这个解决方案很满意,因为它不依赖 build.gradle 技巧,我认为这些技巧太不透明,因此难以维护。例如,当我尝试使用 applicationIdSuffix 和不同的 buildType 的方法时,我发现我无法对 运行 进行检测测试,甚至在我尝试使用 [ 切换构建类型时无法编译=16=]。 Android 似乎赋予了 debug buildType 特殊属性,我无法通过检查来理解。

说实话,根据我的经验,CI scrips 相当 t运行sparent 并且易于维护。事实上,我所描述的方法有效:当我 运行 在模拟器上由 CI 生成的每个 APK 时,Firebase 控制台的 "Run your app to verify installation" 步骤从

Checking if the app has communicated with our servers. You may need to uninstall and reinstall your app.

至:

Congratulations, you've successfully added Firebase to your app!

我在模拟器中一个一个地启动所有三个应用程序。

在 firebase 上使用开发和生产环境创建 Tow 项目 从

下载 json 文件

并按照以下方式设置 SDK:https://firebase.google.com/docs/android/setup Or for Crashlytics: https://firebase.google.com/docs/crashlytics/get-started?platform=android

首先,将每个 buildType 的相应 google_services.json 放置在以下位置:

app/src/debug/google_services.json
app/src/test/google_services.json
app/google_services.json

注意:根 app/google_services.json 根据构建变体,此文件应该存在 复制根 json 文件中的 json 代码

现在,让我们在您的应用程序 build.gradle 中启动一些 gradle 任务,以自动将适当的 google_services.json 移动到 app/google_services。json

将此复制到 app/Gradle 文件中

task switchToDebug(type: Copy) {
description = 'Switches to DEBUG google-services.json'
from "src/debug"
include "google-services.json"
into "."
}

task switchToRelease(type: Copy) {
description = 'Switches to RELEASE google-services.json'
from "src/release"
include "google-services.json"
into "."
}

很好 — 但是在构建应用程序之前必须手动 运行 这些任务很麻烦。我们希望之前某个时间 运行 上方的适当复制任务:assembleDebug 或 :assembleRelease 是 运行。让我们看看当 :assembleRelease 是 运行 时会发生什么:将这个复制到 /gradlew 文件

Zaks-MBP:my_awesome_application zak$ ./gradlew assembleRelease
Parallel execution is an incubating feature.
.... (other tasks)
:app:processReleaseGoogleServices
....
:app:assembleRelease

注意 :app:processReleaseGoogleServices 任务。该任务负责处理根 google_services.json 文件。我们想要处理正确的 google_services.json,所以我们必须立即 运行 我们的复制任务。 将此添加到您的 build.gradle。注意 afterEvaluate 封闭。

将此复制到 app/Gradle 文件中

afterEvaluate {
processDebugGoogleServices.dependsOn switchToDebug
processReleaseGoogleServices.dependsOn switchToRelease
}

现在,无论何时调用 :app:processReleaseGoogleServices,我们新定义的 :app:switchToRelease 都会被预先调用。调试 buildType 的逻辑相同。您可以 运行 :app:assembleRelease 并且发布版本 google_services.json 将自动复制到您的应用程序模块的根文件夹。

我们选择在本地开发服务器上启动新 Firebase 模拟器 的实例以进行测试和 UAT,而将 GCP 完全排除在外。它专为这种用例而设计。

https://firebase.google.com/docs/emulator-suite