[RN Library ๐Ÿ“š] codepush ๋„์ž…ํ•˜๊ธฐ - 2. react-native-code-push ์„ธํŒ…

๋„๋””ยท2020๋…„ 11์›” 12์ผ
3

RN Library ๐Ÿ“š

๋ชฉ๋ก ๋ณด๊ธฐ
7/12

์ด์ „ ๊ธ€์ธ [RN Library ๐Ÿ“š] codepush ๋„์ž…ํ•˜๊ธฐ - 1. app center ์…‹ํŒ…์— ์ด์–ด์„œ
codepush๋ฅผ ๋„์ž…ํ•˜๊ธฐ ์œ„ํ•ด ํ”„๋กœ์ ํŠธ์— react-native-code-push SDK๋ฅผ ์‹ฌ์–ด๋ณด์ž.


react-native-code-push ์…‹ํŒ…

ํ”„๋กœ์ ํŠธ์— react-native-code-push๋ฅผ ์„ค์น˜ํ•˜๊ณ  ios/android ๊ฐ๊ฐ setupํ•ด์ค˜์•ผ ํ•œ๋‹ค.
๋ฒ„์ „๋งˆ๋‹ค ์„ค์น˜ ๋ฐฉ๋ฒ•์ด ์ƒ์ดํ•˜๊ฒŒ ๋‹ค๋ฅด๋‹ค๊ณ  ํ•˜๋‹ˆ ๊ผญ ๊ณต์‹๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•ด์„œ ์…‹ํŒ…ํ•˜์‹œ๊ธธ..

npm install --save react-native-code-push

Android ์…‹์—…

android ์…‹์—…

  1. android/settings.gradle ํŒŒ์ผ ๋์— ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.
include ':app', ':react-native-code-push'
project(':react-native-code-push').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-code-push/android/app')
  1. android/app/build.gradle ํŒŒ์ผ์— codepush.gradle๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.
// apply from: "../../node_modules/react-native/react.gradle"
apply from: "../../node_modules/react-native-code-push/android/codepush.gradle"

๐Ÿš’ ๋นŒ๋“œํ•  ๋•Œ ์˜ค๋ฅ˜ ๋ฐœ์ƒ
Cannot add task 'bundleDebugJsAndAssets' as a task with that name already exists. 
๋ผ๋Š” ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ๊ณ  ์ฒซ๋ฒˆ์งธ ์ค„์„ ์ฃผ์„ ์ฒ˜๋ฆฌํ•˜๋ฉด ํ•ด๊ฒฐ๋œ๋‹ค๋Š” ๊ธ€์„ ๋ฐœ๊ฒฌํ–ˆ๋‹ค. 
  1. MainApplication.java๋ฅผ ๊ณต์‹๋ฌธ์„œ ๋‚ด์šฉ๋Œ€๋กœ ์ˆ˜์ •ํ•œ๋‹ค.
...
// 1. codepush ํŒจํ‚ค์ง€๋ฅผ importํ•œ๋‹ค. 
import com.microsoft.codepush.react.CodePush;

public class MainApplication extends Application implements ReactApplication {

    private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
        ...

        // 2. getJSBundleFile ๋ฉ”์†Œ๋“œ๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋“œ ํ•œ๋‹ค.
        @Override
        protected String getJSBundleFile() {
            return CodePush.getJSBundleFile();
        }
    };
}
  1. ๋ฐฐํฌํ‚ค๋ฅผ strings.xml์— ์ถ”๊ฐ€ํ•œ๋‹ค. staging, production ๋‘๊ฐ€์ง€ key ์ค‘์— ์‚ฌ์šฉํ•  ํ™˜๊ฒฝ์˜ key๋ฅผ ๋„ฃ์–ด์ฃผ๋ฉด ๋œ๋‹ค.
    ๋งŒ์•ฝ staging, production ๋‘ ํ™˜๊ฒฝ์„ ๋ชจ๋‘ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด, 5.๋กœ ๋„˜์–ด๊ฐ€์ž
// ๋ฐฐํฌํ‚ค ์•Œ์•„๋‚ด๊ธฐ
appcenter codepush deployment list -a <ownerName>/<appname> -k
// strings.xml
<resources>
     <string name="app_name">AppName</string>
     <string moduleConfig="true" name="CodePushDeploymentKey">Staging deploymentkey</string>
 </resources>
  1. multi deployment ํ™˜๊ฒฝ ์„ธํŒ…ํ•˜๊ธฐ (๋ฌธ์„œ)
    staging, production ๋‘ ํ™˜๊ฒฝ์„ ๋ชจ๋‘ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด, android/app/build.gradle์— ๋‘ ํ™˜๊ฒฝ์˜ ๋ฐฐํฌํ‚ค๋ฅผ ์ถ”๊ฐ€ํ•ด์ค˜์•ผ ํ•œ๋‹ค.
android {
    ...
    buildTypes {
        debug {
            ...
            resValue "string", "CodePushDeploymentKey", '""'
            ...
        }

        releaseStaging {
            ...
            resValue "string", "CodePushDeploymentKey", '"<INSERT_STAGING_KEY>"'

            // Note: It is 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", '"<INSERT_PRODUCTION_KEY>"'
            ...
        }
    }
    ...
}

iOS ์…‹์—…

ios ์…‹์—…

  1. cd ios && pod install && cd ..
  2. AppDelegate.m ํŒŒ์ผ ์ƒ๋‹จ์— #import <CodePush/CodePush.h>๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.
    ์•„๋ž˜ before ์ฝ”๋“œ๋ฅผ ์ฐพ์•„ after ์ฝ”๋“œ๋กœ ๋ฐ”๊ฟ”์ค€๋‹ค.
// before
return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
// after
return [CodePush bundleURL];
  1. Info.plistํŒŒ์ผ์— ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.
// ๋ฐฐํฌํ‚ค ์•Œ์•„๋‚ด๊ธฐ
appcenter codepush deployment list -a <ownerName>/<appname> -k
// Info.plist
<key>CodePushDeploymentKey</key>
<string>Staging deploymentkey</string>

ํ”„๋กœ์ ํŠธ์— codepush ์ ์šฉํ•˜๊ธฐ

์ตœ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ์— ์•„๋ž˜์™€ ๊ฐ™์€ ์ž‘์—…์„ ํ•ด์•ผ ํ•œ๋‹ค. ๊ด€๋ จ ์˜ต์…˜๋„ ์„ค์ •ํ•ด์ค„ ์ˆ˜ ์žˆ๋Š”๋ฐ ์•„๋ž˜ ๋งํฌ๋ฅผ ์ฐธ๊ณ ํ•˜์ž. '์•ฑ์ด ์‹œ์ž‘ํ• ๋•Œ ์—…๋ฐ์ดํŠธ๋ฅผ ํ•  ๊ฒƒ์ด๋ƒ' ๋“ฑ์˜ ์˜ต์…˜์ด ์žˆ๋‹ค.
codepush api ํ™•์ธํ•˜๊ธฐ

import React from 'react';
import codePush from 'react-native-code-push'; // here!


const App = () => (
   <SomeComponent />
)

// here! ๊ฐ์ข… codepush ๊ด€๋ จ ์˜ต์…˜์„ ์„ค์ •ํ•˜๊ณ 
const codePushOptions = {
  checkFrequency: codePush.CheckFrequency.ON_APP_START,
  installMode: codePush.InstallMode.IMMEDIATE,
}

// here! ์ตœ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ๋ฅผ codepush ๋ž˜ํผ๋กœ ๊ฐ์‹ธ์„œ export ์‹œํ‚ค๊ณ , ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ๋ฅผ ์•ฑ์— ๋“ฑ๋ก์‹œํ‚ต๋‹ˆ๋‹ค.
export default codepush(codePushOptions)(App)

๋ฆด๋ฆฌ์ฆˆ ํ•˜๊ธฐ

ํ”„๋กœ์ ํŠธ ๋ฃจํŠธ ๋””๋ ‰ํ† ๋ฆฌ์—์„œ ํ•œ๋‹ค.

// ๋ฆด๋ฆฌ์ฆˆ ํ•˜๊ธฐ
appcenter codepush release-react -a <ownerName>/<appname> -d Staging
or
appcenter codepush release-react -a <ownerName>/<appname> -d Production

// codepush์— ์ด๋ฆ„ ๋ถ™์ด๊ธฐ
appcenter codepush release-react -a <ownerName>/<appname>  -m --description "Modified the header color"

// ๋ฐฐํฌ ํ™•์ธํ•˜๊ธฐ
appcenter codepush deployment list -a <ownerName>/<appName>

Production์œผ๋กœ ๋ฐฐํฌํ•  ๊ฒฝ์šฐ ์‹ค ๋ฐฐํฌ ์•ฑ์— ์ ์šฉ๋œ๋‹ค.(?) ๋ฌด์Šจ ๋œป์ด์ง€?
staging๊ณผ production์˜ ์ฐจ์ด๋ฅผ ์ž˜ ๋ชจ๋ฅด๊ฒ ๋‹ค. ๊ฒฝํ—˜์„ ํ•ด๋ด์•ผ๊ฒ ๋‹ค.
์ผ๋‹จ ์ „๋ถ€ production key๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  production์œผ๋กœ ๋ฆด๋ฆฌ์ฆˆ ํ•ด๋ณธ์ž.

์ด๋ ‡๊ฒŒ ๋ฐฐํฌ๊ฐ€ ์„ฑ๊ณตํ–ˆ๋Š”๋ฐ ์‹ค ๋ฐฐํฌ ์•ฑ์— ์ ์šฉ๋˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ๋ฐฐํฌ๋œ ํŒŒ์ผ์˜ appcenter key ์™€ staging key์™€ ํ˜„์žฌ ์ ์šฉํ•˜๊ณ  ์žˆ๋Š” ํŒŒ์ผ์˜ appcenter key ์™€ staging key๊ฐ€ ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธํ•ด ๋ด์•ผ ํ•œ๋‹ค.

2021.08.02 ์ถ”๊ฐ€
staging, production์€ ๋ง๊ทธ๋Œ€๋กœ dev, prod ํ™˜๊ฒฝ์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค. ์‹ค์ œ ์œ ์ €์—๊ฒŒ ๋ณด์—ฌ์ง€๋Š” ์•ฑ์„ ๊ฐœ๋ฐœํ•˜๋Š” ๋ถ„๋“ค์ด๋ผ๋ฉด ๋‘ ํ™˜๊ฒฝ์„ ๋ชจ๋‘ ์‚ฌ์šฉํ•˜๋Š”๊ฒŒ ์ข‹์„๋“ฏํ•ด์„œ multi-deployment์„ ์„ธํŒ…ํ•ด์„œ ์‚ฌ์šฉํ•˜์‹œ๊ธธ ๊ถŒ์žฅ ๋“œํžŒ๋‹ค.

profile
์ถฉ์ „์ค‘..๐Ÿค”

0๊ฐœ์˜ ๋Œ“๊ธ€