一般,App 开发、部署会涉及多个环境,譬如开发、测试、预发布、生产等环境。为了不打错包,咱们须要使用科学的方法来切换环境。java
按照下图指引,分别 Duplicate "Debug" Configuration 和 Duplicate "Release" Configuration,建立 Debug production 和 Release production 两个 configuration。react
以下图所示,点击 + 按钮,添加用户定义设置android
咱们添加 BUILD_TYPE 和 ENVIRONMENT 这两个自定义设置,结果如图所示:ios
打开 Info 选项卡git
添加一个名为 AppSettings 的字典,它有两个字段:BUILD_TYPE
和 ENVIRONMENT
,它们的值分别为 $(BUILD_TYPE)
和 $(ENVIRONMENT)
github
点击 Scheme 按钮,建立新的 scheme,命名为 MyApp qa,中间有个空格,这个 scheme 纯粹是对 MyApp 的复制shell
点击 Scheme 按钮,建立新的 scheme,命名为 MyApp production,中间有个空格。react-native
编辑 MyApp production, 把左边 Run Test Profile Analyze Archiv 每一个选项卡中的 Build Configuration 设置为对应的 production 版本。app
如今,咱们经过切换 scheme,就能切换 BUILD_TYPE 和 ENVIRONMENT 这些变量的值。为了让 RN 可以知道这些值,咱们须要借助原生模块。ide
选中 MyApp 目录,右键打开菜单,选择 New File...
在弹出的界面中,肯定 Cocoa Touch Classs 处于选中状态,点击 Next
建立一个名为 AppIno(名字随意) 的类,而后 Next
选择类文件要存放的目录,在这个示例工程里,咱们把它放在 MyApp 目录下
点击 Create 完成建立
编辑 AppInfo.h 文件
#import <React/RCTBridge.h>
NS_ASSUME_NONNULL_BEGIN
@interface AppInfo : NSObject <RCTBridgeModule>
@end
NS_ASSUME_NONNULL_END
复制代码
编辑 AppInfo.m 文件
#import "AppInfo.h"
@implementation AppInfo
RCT_EXPORT_MODULE(AppInfo)
+ (BOOL)requiresMainQueueSetup {
return YES;
}
- (dispatch_queue_t)methodQueue {
return dispatch_get_main_queue();
}
- (NSDictionary *)constantsToExport {
NSDictionary *info = [[NSBundle mainBundle] infoDictionary];
NSMutableDictionary *settings = [[info objectForKey:@"AppSettings"] mutableCopy];
NSString *versionName = [info objectForKey:@"CFBundleShortVersionString"];
NSNumber *versionCode = [info objectForKey:@"CFBundleVersion"];
NSString *bundleId = [info objectForKey:@"CFBundleIdentifier"];
[settings setObject:versionName forKey:@"VERSION_NAME"];
[settings setObject:versionCode forKey:@"VERSION_CODE"];
[settings setObject:bundleId forKey:@"APPLICATION_ID"];
return settings;
}
@end
复制代码
在上面这个原生模块中,咱们导出了 BUILD_TYPE
ENVIRONMENT
VERSION_NAME
VERSION_CODE
APPLICATION_ID
等变量,这些变量,咱们稍后能够在 RN 模块中读取。
编辑 android/app/build.gradle 文件,添加 flavor
android{
flavorDimensions "default"
productFlavors {
qa {
}
production {
}
}
}
复制代码
就这样,咱们建立了 qa 和 production 两个环境,咱们经过原生模块将相关环境变量导出。
打开 AndroidStudio,如图所示,建立一个名为 AppInfo 的 java 文件
编辑该文件
package com.myapp;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class AppInfo extends ReactContextBaseJavaModule {
public AppInfo(@Nonnull ReactApplicationContext reactContext) {
super(reactContext);
}
@Nonnull
@Override
public String getName() {
return "AppInfo";
}
@Nullable
@Override
public Map<String, Object> getConstants() {
HashMap<String, Object> constants = new HashMap<>();
constants.put("ENVIRONMENT", BuildConfig.FLAVOR);
constants.put("VERSION_NAME", BuildConfig.VERSION_NAME);
constants.put("VERSION_CODE", BuildConfig.VERSION_CODE);
constants.put("APPLICATION_ID", BuildConfig.APPLICATION_ID);
constants.put("BUILD_TYPE", BuildConfig.BUILD_TYPE);
return constants;
}
}
复制代码
在上面的文件中,咱们经过名为 AppInfo 的模块,导出了 BUILD_TYPE
ENVIRONMENT
VERSION_NAME
VERSION_CODE
APPLICATION_ID
等变量。
如图,建立一个叫 AppPackage 的文件
编辑以下:
package com.myapp;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.annotation.Nonnull;
public class AppPackage implements ReactPackage {
@Nonnull
@Override
public List<NativeModule> createNativeModules(@Nonnull ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new AppInfo(reactContext));
return modules;
}
@Nonnull
@Override
public List<ViewManager> createViewManagers(@Nonnull ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}
复制代码
修改 MainApplication.java 文件
package com.myapp;
import android.app.Application;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;
import com.facebook.soloader.SoLoader;
import java.util.Arrays;
import java.util.List;
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
// 添加本项目须要导出的 package
new AppPackage()
);
}
@Override
protected String getJSMainModuleName() {
return "index";
}
};
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
@Override
public void onCreate() {
super.onCreate();
SoLoader.init(this, /* native exopackage */ false);
}
}
复制代码
到目前为止,咱们就已经建立了原生模块,并导出了相关变量。
在项目根目录下建立名为 app 的文件夹,在里面建立名为 AppInfo.ts 的文件,编辑以下
// AppInfo.ts
import { NativeModules } from 'react-native'
const AppInfo = NativeModules.AppInfo
export const ENVIRONMENT: string = AppInfo.ENVIRONMENT
export const VERSION_NAME: string = AppInfo.VERSION_NAME
export const VERSION_CODE: number = AppInfo.VERSION_CODE
export const APPLICATION_ID: string = AppInfo.APPLICATION_ID
export const BUILD_TYPE_DEBUG = 'debug'
export const BUILD_TYPE_RELEASE = 'release'
export type BUILD_TYPE_DEBUG = typeof BUILD_TYPE_DEBUG
export type BUILD_TYPE_RELEASE = typeof BUILD_TYPE_RELEASE
export const BUILD_TYPE: BUILD_TYPE_DEBUG | BUILD_TYPE_RELEASE = AppInfo.BUILD_TYPE
复制代码
就这样,咱们读取到了原生模块导出的变量,能够在有须要的地方使用这些变量
如今,咱们有了 qa 和 production 两个环境,那么如何切换环境呢?
iOS 在点击 Run 按钮以前,选择对应环境的 scheme 便可,譬如选择 MyApp qa 就是选择了 qa 环境。
Android 则经过 ./gradlew assembleQaRelease
和 ./gradlew assembleProductionRelease
分别能够打 qa 和 production 环境的包。
不一样环境还能够配置不一样的 App icon 和 App name,有兴趣的同窗能够去研究下。
切换环境如此容易,还担忧打错包吗?
本文是 React Native 工程化实践 系列文章中的一篇