单独的dev和prod Firebase环境

时间:2016-05-26 02:11:54

标签: firebase

我正在考虑将Firebase用作MBaaS,但我无法找到解决以下问题的可靠解决方案:

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

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

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

在您发布解释如何设置单独的Firebase帐户的问题的另一个答案之前:这不是问题,请再次阅读。问题是:如何在单独的开发和生产帐户之间转换更改或任何更好的解决方案,而不是在它们之间手动复制。

12 个答案:

答案 0 :(得分:34)

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

firebase use --add会显示您的项目列表,选择一个,它会询问您的别名。从那里,您可以firebase use aliasfirebase deploy推进该项目。

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

答案 1 :(得分:24)

我目前没有使用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

答案 2 :(得分:5)

This blogpost描述了一种使用调试和发布版本类型的非常简单的方法。

简而言之:

  
      
  • 使用不同的应用程序ID后缀为每个构建类型在Firebase上创建一个新的应用程序。
  •   
  • 使用最新的JSON文件配置您的Android项目。
  •   
  • 使用applicationIdSuffix,根据构建类型更改应用程序ID以匹配Firebase上的不同应用程序。
  •   

=>有关详细说明,请参阅博文。

如果您想使用不同的构建版本,请阅读官方firebase博客中的这篇广泛的blogpost。它包含许多有价值的信息。

希望有所帮助!

答案 3 :(得分:4)

为解决这种情况,我创建了三个Firebase项目,每个项目都具有相同的Android项目(即,相同的applicationId,而未使用其他人建议的applicationIdSuffix)。这产生了三个google-services.json文件,它们存储在我的Continuous Integration (CI) server as custom environment variables中。对于构建的每个阶段(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
# https://stackoverflow.com/questions/57129588/how-to-setup-firebase-for-multi-stage-release

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的方法时,我发现当尝试使用testBuildType切换构建类型时,无法运行甚至无法编译测试化的测试。 Android似乎赋予了debug buildType特殊的属性,我无法检查了解。

以我的经验,CI笔录虽然很透明,但很容易维护。确实,我描述的方法行得通:当我在仿真器上运行CI生成的每个APK时,Firebase控制台的“运行您的应用程序以验证安装”步骤来自

  

检查应用程序是否已与我们的服务器通信。您可能需要卸载并重新安装您的应用。

收件人:

  

恭喜,您已成功将Firebase添加到应用中!

在模拟器中一个接一个地启动这三个应用程序时。

答案 4 :(得分:3)

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

关注此

  1. 首先,在Firebase控制台上创建一个新项目,名称ID为YOURAPPNAME-DEV

  2. 点击“添加Android应用”按钮,然后创建一个新应用。例如,将其命名为com.yourapp.debug。新的google-services.json文件会 可以自动下载

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

  4. 在您的模块级别build.gradle中添加此

    debug {
            applicationIdSuffix ".debug"
        }
    
  5. 现在,当您构建调试版本时,将使用“debug”文件夹中的google-services.json,当您构建发布模式时,将考虑模块根目录中的google-services.json。

答案 5 :(得分:3)

每个人都指出-您需要多个项目/数据库。

但是要回答有关从开发到生产中复制设置/数据等需求的问题。我有完全相同的需求。经过几个月的开发和测试,我不想手动复制数据。

我的结果是将数据备份到存储桶,然后从那里将其还原到另一个数据库。这是一种非常粗略的方法-我进行了整个数据库的备份/还原-但您也许可以朝着这个方向寻找一种更加受控的方法。我没有使用过-这是很新的-但这可能是一种解决方案:NPM Module firestore-export-import

编辑:此处Cloud Firestore Exporting and Importing Data

是Firestore备份/导出/导入信息

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

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

答案 6 :(得分:2)

我的操作方式:

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

通过这种方式,我不需要维护JSON。

答案 7 :(得分:2)

我们选择在本地开发服务器上为 Test 和 UAT 启动新的 Firebase 模拟器 实例,完全不考虑 GCP。它专为这个用例而设计。

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

答案 8 :(得分:1)

Firebase上有一个页面,其中介绍了如何针对开发人员和产品进行设置

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

  

设置项目的环境配置以存储环境   数据,您可以在以下位置使用firebase functions:config:set命令   Firebase CLI。可以使用句点对每个键进行命名空间分组   相关配置在一起。请记住,只有小写字母   键中接受字符;不允许使用大写字符。

     

例如,要存储“某些服务”的客户端ID和API密钥,   您可以运行:

from PyQt5 import QtCore, QtWidgets
import pyqtgraph as pg
import numpy as np

class TimeLine(QtCore.QObject):
    frameChanged = QtCore.pyqtSignal(int)

    def __init__(self, interval=60, loopCount=1, parent=None):
        super(TimeLine, self).__init__(parent)
        self._startFrame = 0
        self._endFrame = 0
        self._loopCount = loopCount
        self._timer = QtCore.QTimer(self, timeout=self.on_timeout)
        self._counter = 0
        self._loop_counter = 0
        self.setInterval(interval)

    def on_timeout(self):
        if self._startFrame <= self._counter < self._endFrame:
            self.frameChanged.emit(self._counter)
            self._counter += 1
        else:
            self._counter = 0
            self._loop_counter += 1

        if self._loopCount > 0: 
            if self._loop_counter >= self.loopCount():
                self._timer.stop() 

    def setLoopCount(self, loopCount):
        self._loopCount = loopCount

    def loopCount(self):
        return self._loopCount

    interval = QtCore.pyqtProperty(int, fget=loopCount, fset=setLoopCount)

    def setInterval(self, interval):
        self._timer.setInterval(interval)

    def interval(self):
        return self._timer.interval()

    interval = QtCore.pyqtProperty(int, fget=interval, fset=setInterval)

    def setFrameRange(self, startFrame, endFrame):
        self._startFrame = startFrame
        self._endFrame = endFrame

    @QtCore.pyqtSlot()
    def start(self):
        self._counter = 0
        self._loop_counter = 0
        self._timer.start()


class Gui(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        self.setupUI()

    def setupUI(self):
        pg.setConfigOption('background', 0.95)
        pg.setConfigOptions(antialias=True)
        self.plot = pg.PlotWidget()
        self.plot.setAspectLocked(lock=True, ratio=0.01)
        self.plot.setYRange(-3, 3)
        widget_layout = QtWidgets.QVBoxLayout(self)
        widget_layout.addWidget(self.plot)

        self._plots = [self.plot.plot([], [], pen=pg.mkPen(color=color, width=2)) for color in ("g", "r", "y")]
        self._timeline = TimeLine(loopCount=0, interval=10)
        self._timeline.setFrameRange(0, 720)
        self._timeline.frameChanged.connect(self.generate_data)
        self._timeline.start()

    def plot_data(self, data):
        for plt, val in zip(self._plots, data):
            plt.setData(range(len(val)), val)

    @QtCore.pyqtSlot(int)
    def generate_data(self, i):
        ang = np.arange(i, i + 720)
        cos_func = np.cos(np.radians(ang)) 
        sin_func = np.sin(np.radians(ang))
        tan_func = sin_func/cos_func
        tan_func[(tan_func < -3) | (tan_func > 3)] = np.NaN
        self.plot_data([sin_func, cos_func, tan_func])

if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    gui = Gui()
    gui.show()
    sys.exit(app.exec_())
     

检索当前环境配置以检查当前内容   存储在项目的环境配置中,可以使用firebase   功能:配置:获取。它将输出类似以下内容的JSON:

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

答案 9 :(得分:0)

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

enter image description here

答案 10 :(得分:0)

我正在根据刚刚发现的信息更新此答案。

第1步

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


mysite-dev

mysite-staging

mysite-prod


第2步

a。直接移至您想要成为默认值的位置(即dev)

b。运行firebase deploy

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

d。将显示一个选项,从您当前拥有的不同项目中进行选择。

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

e。然后将要求您为该项目提供别名。输入登台

再次为prod和dev运行项a-e,以便每个环境都有一个别名


了解您所处的环境

运行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

希望这会有所帮助。

答案 11 :(得分:0)

在Firebase上使用开发环境和生产环境创建Tow项目 从thre下载json文件

并根据https://firebase.google.com/docs/android/setup或对于Crashlytics:https://firebase.google.com/docs/crashlytics/get-started?platform=android

设置SDK。

首先,将每个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

将其复制到应用程序/ 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附件。

将其复制到应用程序/ Gradle文件中

afterEvaluate {
processDebugGoogleServices.dependsOn switchToDebug
processReleaseGoogleServices.dependsOn switchToRelease
}

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