如何在 React Native 中管理测试环境和生产环境
import "GeneratedDotEnv.m" // 由 BuildDotenvConfig.ruby 在构建过程中写入
作为一名 React Native 开发者,你的生活即将变得更加轻松。至少我的生活是这样,自从我学会了如何在 React Native 中管理测试环境和生产环境之后,一切都变得简单多了。这并不会改变你的 React Native 应用的外观、体验或销售方式,但它能为你省去大量的开发工作。
我最初将这篇文章发布在around25 的博客上。
如果只需要修改一两项配置,那修改起来简直轻而易举。切换API host到生产环境配置,搞定!但如果需要修改很多东西API host,比如设置支付网关key、host设置通知.plist文件、更新崩溃日志key和分析数据key,事情就会变得复杂得多,也更容易出错。每次构建都要手动完成这些操作,我敢保证你肯定会漏掉一些东西。
为了避免麻烦,我们将使用环境变量。
为了将环境变量暴露给React Native react-native,我将使用react-native-config库。这样做可以将配置变量与代码隔离开来。这些变量在不同环境下很可能不同,而代码本身则保持不变。
首先,我要把这个库添加到项目中。在我写这篇文章的时候,最新版本react-native-config是0.11.7。然后,我需要在root项目的 `<path>` 目录下创建 3 个环境变量文件:一个用于本地环境,简单地命名为 `<local_environment_name>` .env,另外两个分别命名为 `<local_environment_name>` 和 ` .env.staging<local_environment_name> .env.production`。
// .env
IS_PRODUCTION=false
API_HOST=https://api.staging.foobar.com
// .env.staging
IS_PRODUCTION=false
API_HOST=https://api.staging.foobar.com
// .env.production
IS_PRODUCTION=true
API_HOST=https://api.foobar.com
目前,我只API host在配置中保留了它,以及一个IS_PRODUCTION标志。我们稍后会用到它。显然,两者https://api.staging.foobar.com都是https://api.foobar.com虚构的🙂。
现在,为了在我的 React Native 应用中使用这些变量,我的配置文件通常是这样的:
// src/config/index.js
import env from 'react-native-config'
const config = {
api: {
host: env.API_HOST,
timeout: 20000
}
};
const API_HOST = config.api.host;
export {
API_HOST
}
export default config
就这些。默认情况下,react-native-config程序会从.env文件中读取数据,但也可以通过以下命令从任何文件读取数据并运行项目:
$ ENVFILE=.env.staging react-native run-ios
目前一切顺利,但我希望构建过程尽可能自动化。因此,手动指定.env文件是不可接受的。接下来,我们将着手避免这种情况。
iOS 设置
在 iOS 平台上,我将利用Scheme的概念。Xcode Scheme 定义了一组要构建的目标以及构建时要使用的配置。默认 Scheme 可以在 Xcode 的菜单栏中找到:
Product -> Scheme -> FooBar
其中FooBar是我的应用程序的名称。
我打算复制默认方案,并创建两个新的方案:一个用于测试环境,一个用于生产环境。我们将使用默认方案作为本地环境。您可以通过以下步骤操作:
Product -> Scheme -> Edit Scheme -> Duplicate Scheme
我打算把它们分别命名为FooBar.staging和FooBar.production。命名在我们稍后编写自动构建脚本时非常重要。
我将选中FooBar.staging并返回Edit Scheme,以确保我的方案加载了.env我想要的文件。在这里,Build -> Pre-actions我添加了一个执行此操作的脚本。
我正在经历完全相同的过程FooBar.production。
现在,iOS 的配置都搞定了。每次构建应用时,只要选择一个 scheme,就能加载正确的环境变量。搞定!接下来我们来看看 Android。
Android 设置
对于 Android,我们有构建类型。在android/app/build.gradle`<build-type>` 标签下,buildTypes我们有两种默认构建类型:发布版和调试版。
buildTypes {
release {
minifyEnabled enableProguardInReleaseBuilds
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
signingConfig signingConfigs.release
}
debug {
debuggable true
}
}
与之前一样,默认情况下将使用本地环境变量。
对于新的构建类型,请添加以下代码行:
stagingrelease {
initWith release
}
productionrelease {
initWith release
}
这些都将用于创建发布版本,因此请务必在继续操作之前生成签名密钥。
命名在这一步非常重要。首先,构建变体名称中必须包含“release”标记,才能应用常规的发布构建行为,详情请参见此处。其次,我最初将名称设置为releaseStaging和releaseProduction.env时遇到了问题,因为没有加载正确的文件。我在网上搜索后找到了问题和解决方案,请参见此处。
现在,在同一个文件的最顶部android/app/build.gradle,添加以下内容:
project.ext.envConfigFiles = [
debug: ".env",
release: ".env",
stagingrelease: ".env.staging",
productionrelease: ".env.production"
]
使用 Proguard 构建发布版本时可能会遇到问题。解决方案在这里。
要使用上述定义的构建类型之一运行应用程序,请View -> Tool Windows -> Build Variants在构建之前转到并选择变体(在新显示的窗口中):
Android 部分也到此为止。接下来,我们将通过创建fastlane脚本进一步自动化构建流程。
我的目标是为这两个平台分别编写一行构建脚本。
额外内容:快速通道脚本
首先,我们将安装 fastlane并进行设置。fastlane init它必须在 iOS 或 Android 项目中运行,所以我们将在 ios 文件夹中运行它,然后将整个fastlane文件夹移动到项目的根目录。
在 Fastlane中fastlane/Fastfile,我正在 iOS 平台下创建一个 lane,用于将构建版本上传到 TestFlight。Fastlane 会自动加载我们在运行脚本时传递的 .env 文件。如果我们这样做:
$ fastlane ios beta --env=production
它会加载.env.production文件。一切就绪。为了测试这一点,我将添加几行代码,只打印出环境变量和已加载的文件。
// fastlane/Fastfile
platform :ios do
desc "Submit a new build to TestFlight"
lane :beta do
app_identifier = "com.app.identifier"
api_environment = "staging"
if ENV["IS_PRODUCTION"] == "true"
api_environment = "production"
end
ENV["ENVFILE"]=".env.#{api_environment}"
puts "API_HOST: #{ENV['API_HOST']}"
puts "IS_PRODUCTION: #{ENV['IS_PRODUCTION']}"
puts "ENVFILE: #{ENV['ENVFILE']}"
end
end
如果一切正常,我们应该看到打印出来的结果:
[18:16:52]: Loading from './/../.env.production'
[18:16:52]: Driving the lane 'ios beta' 🚀
[18:16:52]: API_HOST: https://api.foobar.com
[18:16:52]: IS_PRODUCTION: true
[18:16:52]: ENVFILE: .env.production
在创建新版本之前,我们可能需要增加版本号和/或版本号。请将以下几行添加到文件中:
increment_version_number(
xcodeproj: './ios/FooBar.xcodeproj',
bump_type: "patch",
# bump_type: "minor",
# bump_type: "major",
# version_number: "1.0.0"
)
increment_build_number(
xcodeproj: './ios/FooBar.xcodeproj',
# build_number: '74'
)
现在,要创建一个构建版本,请添加以下几行代码。请记住,我在文章开头提到过,方案的命名在后面会很重要。原因如下:
gym(
xcodeproj: './ios/FooBar.xcodeproj',
scheme: "FooBar.#{api_environment}"
)
最后,我希望我的脚本也能将构建结果上传到指定位置TestFlight,所以我这样做:
pilot(
app_identifier: app_identifier,
email: "itunesconnect_email",
first_name: "itunesconnect_first_name",
last_name: "itunesconnect_last_name",
ipa: "./FooBar.ipa",
distribute_external: true,
skip_submission: true,
skip_waiting_for_build_processing: false
)
Android 的流程几乎相同,只是将 ` gymand`pilot操作替换为gradle`and` supply。流程大致如下:
platform :android do
desc "Submit a new build to Google Play Console"
lane :beta do
app_identifier = "com.app.identifier"
api_environment = "staging"
if ENV["IS_PRODUCTION"] == "true"
api_environment = "production"
end
ENV["ENVFILE"]=".env.#{api_environment}"
puts "API_HOST: #{ENV['API_HOST']}"
puts "IS_PRODUCTION: #{ENV['IS_PRODUCTION']}"
puts "ENVFILE: #{ENV['ENVFILE']}"
gradle_file = "./android/app/build.gradle"
android_set_version_name(
version_name: "1.0.0",
gradle_file: gradle_file
)
android_set_version_code(
gradle_file: gradle_file
)
gradle(
project_dir: './android',
task: 'assemble',
build_type: 'release'
)
supply(
json_key: 'google_play_console_key',
track: 'beta',
apk: './android/app/build/outputs/apk/release/app-release.apk',
package_name: app_identifier
)
end
end
关于 React Native 应用中的预发布环境和生产环境的最后思考
在离开之前,我想表达一下我对源代码控制最佳实践的看法。
我建议将真实值提交到.env(本地环境),但保留.env.staging虚拟.env.production/非敏感值,这些值仅在构建时在构建机器上替换。
因此,这三个文件在代码仓库中看起来会像这样:
// .env
IS_PRODUCTION=false
API_HOST=https://api.staging.foobar.com
// .env.staging
IS_PRODUCTION=false
API_HOST=api_host
// .env.production
IS_PRODUCTION=true
API_HOST=api_host
完整的源代码可以在Github上找到。
欢迎您告诉我您的想法,或者如果您对我上面提出的解决方案有任何建议,也请随时告诉我。
谢谢,
文章来源:https://dev.to/calintamas/how-to-manage-staging-and-production-environments-in-a-react-native-app-4naa




