在适用于iOS和Android的React Native上设置多个环境

While working on Peel, we quickly realized we needed to be able to set up multiple targets for the same React Native project. There’s several big advantages to doing that:

在研究Peel时 ,我们很快意识到我们需要能够为同一个React Native项目设置多个目标。 这样做有很多好处:

  • Store your environment variables in separate files

    将环境变量存储在单独的文件中
  • Multiple instances of your app with different environments can be installed on the same phone (with different bundle identifiers)

    您可以将具有不同环境的应用程序的多个实例安装在同一部手机上(具有不同的捆绑包标识符)
  • No need to add extra-logic to swap between API urls, constants, keys etc.

    无需添加额外的逻辑即可在API网址,常量,键等之间进行交换。

There’s some great articles describing how to do that on React Native, but all the ones I could find were written a few years back and things have changed a bit since then. So I’ve decided to give an up-to-date tutorial on the matter.

有一些很棒的文章描述了如何在React Native上实现该功能,但是我能找到的所有内容都是几年前写的,自那以后,情况有所变化。 因此,我决定提供有关此问题的最新教程。

开始之前 (Before we start)

The goal of this tutorial is for you to set up multiple environments on your own React Native app. However, if you want to follow along for the sake of learning I’ve created this repository which you can clone on your machine.

本教程的目标是让您在自己的React Native应用程序上设置多个环境。 但是,如果您想继续学习,我已经创建了该存储库 ,可以在您的计算机上对其进行克隆。

安装react-native-config (Install react-native-config)

We are going to use the package react-native-config to handle our environment variables. In your repo, run:

我们将使用包react-native-config来处理环境变量。 在您的仓库中,运行:

npm install react-native-config --save

You then need to link the library, even if you using Cocoapods:

然后, 即使您使用Cocoapods需要链接库:

npx react-native link react-native-config

If you’re using Cocoapods, you also need to run a pod install:

如果您使用的是Cocoapods,则还需要运行pod安装:

cd ios
pod install
cd ../

We will then create the files that will store our environment variables. We’ll set two environments: development and production, so we create two files at the root of our project: .env.development and .env.production.

然后,我们将创建用于存储环境变量的文件。 我们将设置两个环境: developmentproduction ,因此我们在项目的根目录创建两个文件: .env.development.env.production

For the sake of this tutorial, we’ll only store one variable in each file in order to know in what environment our app is running.

在本教程中,我们仅在每个文件中存储一个变量,以便了解我们的应用程序在哪种环境下运行。

In .env.development:

.env.development

ENVIRONMENT=development

And in .env.production:

.env.production

ENVIRONMENT=production

In a real app, these files would contain all your API urls, constants, API keys… anything that is specific to each environment.

在真实的应用程序中,这些文件将包含您所有的API URL,常量,API密钥……任何特定于每种环境的内容。

在Android上设置构建类型 (Setting up build types on Android)

We will be using build types with suffixes to create different versions of our app on Android.

我们将使用带有后缀的构建类型在Android上创建应用程序的不同版本。

  • Open android/app/build.gradle

    打开android/app/build.gradle

  • At the very top of the file, we’ll assign an environment file to each build type:

    在文件的最顶部,我们将为每个构建类型分配一个环境文件:
project.ext.envConfigFiles = [
release: ".env.production",
debug: ".env.development",
developmentrelease: ".env.development",
]

The naming of your build types is important! Make sure to use only lowercase letters with no special characters and append “release” at the end of the name of your custom build types, or they might not work.

构建类型的命名很重要! 确保仅使用不带特殊字符的小写字母,并在自定义构建类型名称的末尾附加“ release”,否则它们可能不起作用。

  • Add this line after apply plugin:

    apply plugin之后添加以下行:

apply from: project(":react-native-config").projectDir.getPath() + "/dotenv.gradle"
  • Since we’ll use suffixes, we need to edit our default config:

    由于我们将使用后缀,因此我们需要编辑默认配置:
defaultConfig {
...
resValue "string", "build_config_package", "com.myapp"
}

Replace "com.myapp" with the bundle identifier of your app.

用您的应用程序的捆绑标识符替换"com.myapp"

  • Add developmentrelease build type with the ".development" suffix:

    添加带有".development"后缀的developmentrelease构建类型:

buildTypes {
...
developmentrelease {
initWith debug
applicationIdSuffix ".development"
}
}
  • Add matching fallbacks to debug build type:

    添加匹配的后备以debug构建类型:

debug {
...
matchingFallbacks = ['debug', 'release']
}

That’s it! Your environment variables are now available to your native code, as well as your Javascript code:

而已! 现在,您的本机代码和Javascript代码都可以使用您的环境变量:

import Config from 'react-native-config';Config.ENVIRONMENT; // "development" or "production"

If you are following this tutorial using the repository I gave earlier, add this line at the top of the App.js file:

如果您使用我之前提供的存储库来学习本教程,请在App.js文件顶部添加以下行:

import Config from 'react-native-config';

And change line 21 to:

并将第21行更改为:

const environment = Config.ENVIRONMENT;

You can now run both versions of the app on your device.Development:

现在,您可以在设备上运行两个版本的应用程序。

npx react-native run-android --variant=developmentrelease

Production:

生产:

npx react-native run-android --variant=release
Image for post

在iOS上添加目标 (Adding a target on iOS)

We will be using targets to handle our environments on iOS. The configuration is a bit more daunting than for Android, so hold tight!

我们将使用目标来处理iOS上的环境。 该配置比Android的配置更令人生畏,因此请紧紧使用!

  • Open the .xcworkspace file of your app in Xcode, then right click on your project > New Group

    在Xcode中打开应用程序的.xcworkspace文件,然后右键单击您的项目> New Group

Image for post
  • Rename this group to MyAppDevelopment (replacing “MyApp” with the name of your app)

    将该组重命名为MyAppDevelopment (用您的应用名称替换“ MyApp”)

  • Right click on your main target ( MyApp for me) > Duplicate > Duplicate Only

    右键单击您的主要目标(对我来说是MyApp )> Duplicate > Duplicate Only

Image for post
  • Rename the duplicated target to MyAppDevelopment

    将重复的目标重命名为MyAppDevelopment

  • In the General, set the Bundle Identifier to com.myapp.development. By having a different bundle identifier, we’ll be able to install the two versions of our app (development and production) on the same device.

    在“ General ,将“ Bundle Identifier设置为com.myapp.development 。 通过使用不同的捆绑包标识符,我们将能够在同一设备上安装应用程序的两个版本(开发和生产)。

Image for post
  • Move the new Info.plist file that got automatically created when you duplicated the target into MyAppDevelopment group, then rename it to Info.plist. Note that you’ll need to actually copy and paste the file into MyAppDevelopment group, if you just slide it from Xcode only the reference will be moved, not the actual file!

    将复制目标时自动创建的新Info.plist文件移动到MyAppDevelopment组中,然后将其重命名为Info.plist 。 请注意,您实际上需要将文件复制并粘贴到MyAppDevelopment组中,如果仅从Xcode滑动文件,则仅引用将被移动,而不是实际文件!

  • If your main target contains a .entitlements file (MyApp.entitlements), duplicate it and move it inside MyAppDevelopment group, then rename it to MyAppDevelopment.entitlements. This will permit you to support different capabilities for each target (remote notifications, app groups…).

    如果您的主要目标包含一个 .entitlements 文件 ( MyApp.entitlements ),请复制该 文件 MyApp.entitlements 其移至 MyAppDevelopment 组内,然后将其重命名为 MyAppDevelopment.entitlements 这将允许您为每个目标(远程通知,应用程序组…)支持不同的功能。

  • In the Build Settings tab of MyAppDevelopment target, search for the Packaging section then set Info.plist File to the path of the Info.plist we just moved; MyAppDevelopment/Info.plist in our case.

    MyAppDevelopment目标的Build Settings选项卡中,搜索Packaging部分,然后将Info.plist File设置为我们刚刚移动的Info.plist的路径。 在我们的案例中为MyAppDevelopment/Info.plist

Image for post

If in the previous step you duplicated a .entitlements file, you’ll also need to search for the section Signing and set Code Signing Entitlements to the path of the .entitlements file (MyAppDevelopment/MyAppDevelopment.entitlements).

如果在上一步中你复制一个.entitlements文件,你还需要搜索的部分Signing ,并设置Code Signing Entitlements的路径.entitlements file ( MyAppDevelopment/MyAppDevelopment.entitlements )。

  • Click on MyApp in the left corner of the top bar > Manage Schemes and scroll down to find the newly created scheme MyApp copy. Rename it to MyAppDevelopment, then click on Edit in the bottom left corner.

    单击顶部栏左上角的MyApp > Manage Schemes然后向下滚动以查找新创建的方案MyApp copy 。 将其重命名为MyAppDevelopment ,然后单击左下角的“ Edit ”。

  • Click on Build accordion (without expanding it), then on the + in the bottom left corner. Search for “React” and add the item named React (dah). Make sure to untick Parallelize build.

    单击“ Build手风琴”(不展开它),然后单击左下角的+ 。 搜索“React”并添加名为React (dah)的项目。 确保取消选中Parallelize build

Image for post

Our new target should now be able to run, but we need to configure react-native-config.

现在我们的新目标应该可以运行了,但是我们需要配置react-native-config

  • Expand Build accordion, click on Pre-actions then on the + in the bottom left corner > New Run Script Action.

    展开Build手风琴,单击Pre-actions然后单击左下角的+ > New Run Script Action

  • Replace the content of the script with:

    将脚本的内容替换为:
echo ".env.development" > /tmp/envfile
  • Repeat the same action for the main target, this time replacing the content of the script with:

    对主要目标重复相同的操作,这次将脚本的内容替换为:
echo ".env.production" > /tmp/envfile

We’re done playing with Xcode! We’ll now edit the Podfile of the project (ios/Podfile).

Xcode玩完了! 现在,我们将编辑项目的Podfile ( ios/Podfile )。

  • Since you’re reading this tutorial, chances are your project is articulated around one main target. We’ll first need to set an abstract target, so multiple targets can use the same pods and also use their own pods. In the Podfile, replace the line:

    由于您正在阅读本教程,因此您的项目很有可能围绕一个主要目标进行阐述。 我们首先需要设置一个抽象目标,以便多个目标可以使用相同的容器,也可以使用自己的容器。 在Podfile ,替换以下行:

target 'MyApp' do

With:

带有:

abstract_target 'App' do

App can be replaced with anything you want, but shouldn’t be the same as any of your targets’ names!

App可以替换为您想要的任何名称,但不应与您的目标名称相同!

  • We now need to define our targets, that will inherit from our abstract target. Right bellow the last pod ‘SOME_PLUGIN’, :path => ‘../node_modules/SOME_PLUGIN’ (were SOME_PLUGIN will probably be react-native-config since that’s the last plugin we installed), add our two targets:

    现在,我们需要定义目标,该目标将从抽象目标中继承。 在最后一个pod 'SOME_PLUGIN', :path => '../node_modules/SOME_PLUGIN' (在SOME_PLUGIN情况下, SOME_PLUGIN可能是react-native-config因为这是我们安装的最后一个插件),添加两个目标:

target 'MyApp' do
#Production-specific pods target 'MyAppTests' do
inherit! :complete
# Pods for testing
end
endtarget 'MyAppDevelopment' do
#Development-specific pods
end

Note: we moved the default test target MyAppTests inside MyApp to respect the original architecture.

注意:我们将默认的测试目标MyAppTests MyApp以尊重原始体系结构。

If you used the repository I linked at the beginning of this tutorial, your Podfile should look like this:

如果您使用的是我在本教程开始时链接的存储库,则Podfile应该如下所示:

platform :ios, '9.0'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'


def add_flipper_pods!(versions = {})
  versions['Flipper'] ||= '~> 0.33.1'
  versions['DoubleConversion'] ||= '1.1.7'
  versions['Flipper-Folly'] ||= '~> 2.1'
  versions['Flipper-Glog'] ||= '0.3.6'
  versions['Flipper-PeerTalk'] ||= '~> 0.0.4'
  versions['Flipper-RSocket'] ||= '~> 1.0'


  pod 'FlipperKit', versions['Flipper'], :configuration => 'Debug'
  pod 'FlipperKit/FlipperKitLayoutPlugin', versions['Flipper'], :configuration => 'Debug'
  pod 'FlipperKit/SKIOSNetworkPlugin', versions['Flipper'], :configuration => 'Debug'
  pod 'FlipperKit/FlipperKitUserDefaultsPlugin', versions['Flipper'], :configuration => 'Debug'
  pod 'FlipperKit/FlipperKitReactPlugin', versions['Flipper'], :configuration => 'Debug'


  # List all transitive dependencies for FlipperKit pods
  # to avoid them being linked in Release builds
  pod 'Flipper', versions['Flipper'], :configuration => 'Debug'
  pod 'Flipper-DoubleConversion', versions['DoubleConversion'], :configuration => 'Debug'
  pod 'Flipper-Folly', versions['Flipper-Folly'], :configuration => 'Debug'
  pod 'Flipper-Glog', versions['Flipper-Glog'], :configuration => 'Debug'
  pod 'Flipper-PeerTalk', versions['Flipper-PeerTalk'], :configuration => 'Debug'
  pod 'Flipper-RSocket', versions['Flipper-RSocket'], :configuration => 'Debug'
  pod 'FlipperKit/Core', versions['Flipper'], :configuration => 'Debug'
  pod 'FlipperKit/CppBridge', versions['Flipper'], :configuration => 'Debug'
  pod 'FlipperKit/FBCxxFollyDynamicConvert', versions['Flipper'], :configuration => 'Debug'
  pod 'FlipperKit/FBDefines', versions['Flipper'], :configuration => 'Debug'
  pod 'FlipperKit/FKPortForwarding', versions['Flipper'], :configuration => 'Debug'
  pod 'FlipperKit/FlipperKitHighlightOverlay', versions['Flipper'], :configuration => 'Debug'
  pod 'FlipperKit/FlipperKitLayoutTextSearchable', versions['Flipper'], :configuration => 'Debug'
  pod 'FlipperKit/FlipperKitNetworkPlugin', versions['Flipper'], :configuration => 'Debug'
end


# Post Install processing for Flipper
def flipper_post_install(installer)
  installer.pods_project.targets.each do |target|
    if target.name == 'YogaKit'
      target.build_configurations.each do |config|
        config.build_settings['SWIFT_VERSION'] = '4.1'
      end
    end
  end
end


abstract_target 'App' do
  # Pods for MyApp
  pod 'FBLazyVector', :path => "../node_modules/react-native/Libraries/FBLazyVector"
  pod 'FBReactNativeSpec', :path => "../node_modules/react-native/Libraries/FBReactNativeSpec"
  pod 'RCTRequired', :path => "../node_modules/react-native/Libraries/RCTRequired"
  pod 'RCTTypeSafety', :path => "../node_modules/react-native/Libraries/TypeSafety"
  pod 'React', :path => '../node_modules/react-native/'
  pod 'React-Core', :path => '../node_modules/react-native/'
  pod 'React-CoreModules', :path => '../node_modules/react-native/React/CoreModules'
  pod 'React-Core/DevSupport', :path => '../node_modules/react-native/'
  pod 'React-RCTActionSheet', :path => '../node_modules/react-native/Libraries/ActionSheetIOS'
  pod 'React-RCTAnimation', :path => '../node_modules/react-native/Libraries/NativeAnimation'
  pod 'React-RCTBlob', :path => '../node_modules/react-native/Libraries/Blob'
  pod 'React-RCTImage', :path => '../node_modules/react-native/Libraries/Image'
  pod 'React-RCTLinking', :path => '../node_modules/react-native/Libraries/LinkingIOS'
  pod 'React-RCTNetwork', :path => '../node_modules/react-native/Libraries/Network'
  pod 'React-RCTSettings', :path => '../node_modules/react-native/Libraries/Settings'
  pod 'React-RCTText', :path => '../node_modules/react-native/Libraries/Text'
  pod 'React-RCTVibration', :path => '../node_modules/react-native/Libraries/Vibration'
  pod 'React-Core/RCTWebSocket', :path => '../node_modules/react-native/'


  pod 'React-cxxreact', :path => '../node_modules/react-native/ReactCommon/cxxreact'
  pod 'React-jsi', :path => '../node_modules/react-native/ReactCommon/jsi'
  pod 'React-jsiexecutor', :path => '../node_modules/react-native/ReactCommon/jsiexecutor'
  pod 'React-jsinspector', :path => '../node_modules/react-native/ReactCommon/jsinspector'
  pod 'ReactCommon/callinvoker', :path => "../node_modules/react-native/ReactCommon"
  pod 'ReactCommon/turbomodule/core', :path => "../node_modules/react-native/ReactCommon"
  pod 'Yoga', :path => '../node_modules/react-native/ReactCommon/yoga', :modular_headers => true


  pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec'
  pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec'
  pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec'
  pod 'react-native-config', :path => '../node_modules/react-native-config'


  target 'MyApp' do
    #Production-specific pods


    target 'MyAppTests' do
      inherit! :complete
      # Pods for testing
    end
  end


  target 'MyAppDevelopment' do
    #Development-specific pods
  end


  use_native_modules!


  # Enables Flipper.
  #
  # Note that if you have use_frameworks! enabled, Flipper will not work and
  # you should disable these next few lines.
  add_flipper_pods!
  post_install do |installer|
    flipper_post_install(installer)
  end
end


target 'MyApp-tvOS' do
  # Pods for MyApp-tvOS


  target 'MyApp-tvOSTests' do
    inherit! :search_paths
    # Pods for testing
  end
end
  • Finally, if you use Cocoapods you’ll need to run pod install again:

    最后,如果您使用Cocoapods,则需要再次运行pod install:
cd ios
pod install
cd ../

That’s it! Your environment variables are now available to your native code, as well as your Javascript code.

而已! 现在,您的本机代码以及Javascript代码都可以使用您的环境变量。

If you want to access your environment variables from your Info.plist files, follow these extra steps for each scheme.

如果要从Info.plist文件访问环境变量,请为每个方案执行以下额外步骤

You can now run both versions of the app on your device.Development:

现在,您可以在设备上运行两个版本的应用程序。

npx react-native run-ios --scheme "MyAppDevelopment"

Production:

生产:

npx react-native run-ios
Image for post

I hope this tutorial was helpful to you. If you’d like to see the codebase on Github with all the environments set up, here it is.

希望本教程对您有所帮助。 如果您想在Github上查看所有设置环境的代码库, 这里就是

Feel free to ask me any questions you have by commenting on this post. Have fun!

对此评论发表评论,随时问我任何问题。 玩得开心!

P.S.: My best friend and I just released Peel; our own dating app for serious relationships, available on both iOS and Android! It’s built on React Native and it’s awesome; check it out! 😁

PS:我最好的朋友,我刚刚放开了 Peel 我们自己的约会应用程序,用于建立认真的关系,可在 iOS Android上使用 它建立在React Native之上,很棒。 看看这个! 😁

翻译自: https://medium.com/swlh/setting-up-multiple-environments-on-react-native-for-ios-and-android-c43f3128754f

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值