최근 유지 보수 관리하고 있는 앱에 코드푸쉬 설정이 필요해서 세팅하는 김에 가이드 글을 작성하게 됐습니다.
자세한 설명 없이 과정만 작성했습니다.
감사합미다.
npm install -g appcenter-cli
appcenter login
appcenter apps create -d {Apps 이름} -o {iOS/Android} -p React-Native
appcenter codepush deployment add -a {User Name}/{Apps 이름} {Deployment Name}
appcenter codepush deployment add -a user/myApp_android Staging
appcenter codepush deployment add -a user/myApp_android Production
appcenter codepush deployment add -a user/myApp_ios Staging
appcenter codepush deployment add -a user/myApp_ios Production
yarn add react-native-code-push
cd ios && pod install
pod 설치
/ios/{your project name}/Info.plist
열어서 해당 내용 추가
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
...
<key>CodePushDeploymentKey</key>
<string>${CODEPUSH_KEY}</string>
...
</dict>
</plist>
// 최상단에 추가
#import <CodePush/CodePush.h>
return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
파일 안에서 해당 라인을
return [CodePush bundleURL];
로 수정한다.
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
#if DEBUG
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
#else
return [CodePush bundleURL];
#endif
}
xCode로 project를 열고, PROJECT/Info/Duplicate Release Configuration을 선택한다.
생성된 Configuration의 이름을 Staging으로 설정해준다.
같은 PROJECT 탭에서 Build Settings로 이동
Add User-Defined Setting 선택해서
MULTI_DEPLOYMENT_CONFIG 설정을 만든다.
Release에는 $(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
Staging에는 $(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)
(xCode 버전이 10 이하인 경우)
똑같이 Add User-Defined Setting 선택 후
이번에는 CODEPUSH_KEY 설정을 만든다.
appcenter codepush deployment list -a user/yourApp_ios -k
명령어를 사용해
Staging -> Staging / Production -> Release 각각 기입해서 설정해 준다.
include ':app', ':react-native-code-push'
project(':react-native-code-push').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-code-push/android/app')
// debug는 빈 값을 넣어야 한다.
CODEPUSH_DEPLOYMENT_KEY_DEBUG=
CODEPUSH_DEPLOYMENT_KEY_STAGING={Staging deployment key}
CODEPUSH_DEPLOYMENT_KEY_PRODUCTION={Production deployment key}
apply from: "../../node_modules/react-native-code-push/android/codepush.gradle"
추가로 buildTypes 블록을 찾아 각 build type에 맞게 resValue를 설정한다.
android {
...
buildTypes {
debug {
...
// Note: CodePush updates shouldn't be tested in Debug mode as they're overriden by the RN packager. However, because CodePush checks for updates in all modes, we must supply a key.
resValue "string", "CodePushDeploymentKey", CODEPUSH_DEPLOYMENT_KEY_DEBUG
...
}
releaseStaging {
...
initWith release // release build type 설정을 상속
resValue "string", "CodePushDeploymentKey", CODEPUSH_DEPLOYMENT_KEY_STAGING
// Note: It's a good idea to provide matchingFallbacks for the new buildType you create to prevent build issues
// Add the following line if not already there
matchingFallbacks = ['release']
...
}
release {
...
resValue "string", "CodePushDeploymentKey", CODEPUSH_DEPLOYMENT_KEY_PRODUCTION
...
}
}
...
}
// 최상단
import com.microsoft.codepush.react.CodePush;
...
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
...
// 이 블록 최하단에 getJSBundleFile() 메서드를 추가한다.
@Override
protected String getJSBundleFile() {
return CodePush.getJSBundleFile();
}
};
}
// Wrapper function
codePush(rootComponent: React.Component): React.Component;
codePush(options: CodePushOptions)(rootComponent: React.Component): React.Component;
// Decorator; Requires ES7 support
@codePush
@codePush(options: CodePushOptions)
예시처럼 codePush는 options를 옵셔널 하게 넣어서 사용할 수 있다.
공식 문서에서 소개되는 예시를 확인해 보면
// Fully silent update which keeps the app in
// sync with the server, without ever
// interrupting the end user
class MyApp extends Component<{}> {}
MyApp = codePush(MyApp);
export default MyApp;
// functional
const MyApp = () => {};
export default codePush(MyApp);
기본 syncOptions
는 이렇게 설정돼있다.
각 옵션은 react-native-code-push/docs/api-js.md에서 더 자세히 확인할 수 있다.
// Sync for updates every time the app resumes.
const codePushOptions = {
checkFrequency: codePush.CheckFrequency.ON_APP_RESUME,
installMode: codePush.InstallMode.ON_NEXT_RESUM,
};
class MyApp extends Component<{}> {}
MyApp = codePush(codePushOptions)(MyApp);
export default MyApp;
// functional
const MyApp = () => {};
export default codePush(codePushOptions)(MyApp);
// Active update, which lets the end user know
// about each update, and displays it to them
// immediately after downloading it
const codePushOptions = {
updateDialog: true,
installMode: codePush.InstallMode.IMMEDIATE,
};
class MyApp extends Component<{}> {}
MyApp = codePush(codePushOptions)(MyApp);
export default MyApp;
// functional
const MyApp = () => {};
export default codePush(codePushOptions)(MyApp);
updateDialog
는 여러 옵션을 사용해서 커스터마이징이 가능하다.
// Make use of the event hooks to keep track of
// the different stages of the sync process.
class MyApp extends Component<{}> {
codePushStatusDidChange(status) {
switch(status) {
case codePush.SyncStatus.CHECKING_FOR_UPDATE:
console.log("Checking for updates.");
break;
case codePush.SyncStatus.DOWNLOADING_PACKAGE:
console.log("Downloading package.");
break;
case codePush.SyncStatus.INSTALLING_UPDATE:
console.log("Installing update.");
break;
case codePush.SyncStatus.UP_TO_DATE:
console.log("Up-to-date.");
break;
case codePush.SyncStatus.UPDATE_INSTALLED:
console.log("Update installed.");
break;
}
}
codePushDownloadDidProgress(progress) {
console.log(progress.receivedBytes + " of " + progress.totalBytes + " received.");
}
}
MyApp = codePush(MyApp);
export default MyApp;
제공하는 api 중 하나인 sync()
메서드를 사용해도 해당 기능을 사용할 수 있다.
// Prompt the user when an update is available
// and then display a "downloading" modal
codePush.sync({ updateDialog: true },
(status) => {
switch (status) {
case codePush.SyncStatus.DOWNLOADING_PACKAGE:
// Show "downloading" modal
break;
case codePush.SyncStatus.INSTALLING_UPDATE:
// Hide "downloading" modal
break;
}
},
({ receivedBytes, totalBytes, }) => {
/* Update download modal progress */
}
);
실제 CodePush.js
코드를 확인해 보면 checkFrequency가 MANUAL인지 아닌지에 따라 분기가 갈린다.
MANUAL이 아닌 경우 자체적으로 sync()
함수를 실행하기 때문에 코드푸쉬 로직을 재정의 하려면
가장 먼저 설정하는 codePush 옵션에 checkFrequency를 무조건 MANUAL로 설정해 줘야 한다.
그래야 기존 codePush 옵션과 충돌하지 않는다.