我正在考虑将Firebase用作MBaaS,但我无法找到解决以下问题的可靠解决方案:
我想设置两个单独的Firebase环境,一个用于开发,一个用于生产,但我不想手动复制功能(例如远程配置设置,通知规则等)开发和生产环境。
我可以依赖任何工具或方法吗?从头开始设置远程配置或通知规则可能是一项艰巨的任务,而且风险太大。
有什么建议吗?有没有比拥有两个独立环境更好的方法?
在您发布解释如何设置单独的Firebase帐户的问题的另一个答案之前:这不是问题,请再次阅读。问题是:如何在单独的开发和生产帐户之间转换更改或任何更好的解决方案,而不是在它们之间手动复制。
答案 0 :(得分:34)
如果您使用的是firebase-tools,则可以使用命令firebase use
来设置您用于firebase deploy
的项目
firebase use --add
会显示您的项目列表,选择一个,它会询问您的别名。从那里,您可以firebase use alias
和firebase 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)
您需要管理不同的构建类型
关注此
首先,在Firebase控制台上创建一个新项目,名称ID为YOURAPPNAME-DEV
点击“添加Android应用”按钮,然后创建一个新应用。例如,将其命名为com.yourapp.debug。新的google-services.json文件会 可以自动下载
在您的项目src目录下创建名为“debug”的新目录并在此处复制新的google-services.json文件
在您的模块级别build.gradle中添加此
debug {
applicationIdSuffix ".debug"
}
现在,当您构建调试版本时,将使用“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)
我的操作方式:
通过这种方式,我不需要维护JSON。
答案 7 :(得分:2)
我们选择在本地开发服务器上为 Test 和 UAT 启动新的 Firebase 模拟器 实例,完全不考虑 GCP。它专为这个用例而设计。
答案 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)
答案 10 :(得分:0)
我正在根据刚刚发现的信息更新此答案。
第1步
在firebase.google.com中,创建您的多个环境(即;开发,登台,生产)
mysite-dev
mysite-staging
mysite-prod
第2步
a。直接移至您想要成为默认值的位置(即dev)
b。运行firebase deploy
c。部署后,运行firebase use --add
滚动到要添加的项目: mysite-staging ,然后选择它。
e。然后将要求您为该项目提供别名。输入登台。
再次为prod和dev运行项a-e,以便每个环境都有一个别名
了解您所处的环境
运行firebase use
default (mysite-dev)
* dev (mysite-dev)
staging (mysite-staging)
prod (mysite-dev)
(其中一种环境在其左侧会带有一个星号。这就是您当前所处的环境。它还会以蓝色突出显示)
在环境之间切换
运行firebase use staging
或firebase use prod
在它们之间移动。
一旦您处于所需的环境中,请运行firebase deploy
,您的项目将在那里部署。
这里有几个有用的链接...
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将自动复制到您应用模块的根文件夹中。