Skip to main content
Version: Next

기존 애플리케이션과의 통합

React Native는 새로운 모바일 앱을 처음부터 개발할 때 유용하다. 하지만 기존 네이티브 애플리케이션에 단일 뷰나 사용자 흐름을 추가하는 데도 잘 작동한다. 몇 가지 단계를 거치면 React Native 기반의 새로운 기능, 화면, 뷰 등을 추가할 수 있다.

구체적인 단계는 대상 플랫폼에 따라 다르다.

주요 개념

React Native 컴포넌트를 안드로이드 애플리케이션에 통합하기 위한 핵심 단계는 다음과 같다:

  1. 올바른 디렉토리 구조를 설정한다.
  2. 필요한 NPM 의존성을 설치한다.
  3. Gradle 설정에 React Native를 추가한다.
  4. 첫 번째 React Native 화면을 위한 TypeScript 코드를 작성한다.
  5. ReactActivity를 사용해 React Native를 안드로이드 코드와 통합한다.
  6. 번들러를 실행하고 애플리케이션이 동작하는 모습을 확인하며 통합을 테스트한다.

커뮤니티 템플릿 사용하기

이 가이드를 따라가는 동안 React Native 커뮤니티 템플릿을 참고 자료로 사용하는 것을 권장한다. 이 템플릿은 최소한의 안드로이드 앱을 포함하고 있어, 기존 안드로이드 앱에 React Native를 통합하는 방법을 이해하는 데 도움이 될 것이다.

사전 준비 사항

개발 환경 설정 가이드를 참고하여 React Native 앱을 개발할 환경을 준비한다. 또한 프레임워크 없이 React Native 사용하기 문서를 통해 React Native 앱을 빌드할 기본 설정을 마친다. 이 가이드는 Android 개발의 기본 개념, 예를 들어 Activity 생성이나 AndroidManifest.xml 파일 수정 등에 익숙하다고 가정한다.

1. 디렉터리 구조 설정

원활한 작업 환경을 위해 새로운 폴더를 만들어 통합 React Native 프로젝트를 구성한다. 기존 Android 프로젝트는 /android 하위 폴더로 이동시킨다.

2. NPM 의존성 설치

루트 디렉터리로 이동한 후 다음 명령어를 실행한다:

shell
curl -O https://raw.githubusercontent.com/react-native-community/template/refs/heads/0.75-stable/template/package.json

이 명령어는 커뮤니티 템플릿의 package.json 파일을 프로젝트로 복사한다.

다음으로, NPM 패키지를 설치한다:

shell
npm install

설치 과정에서 새로운 node_modules 폴더가 생성된다. 이 폴더는 프로젝트를 빌드하는 데 필요한 모든 자바스크립트 의존성을 저장한다.

node_modules/.gitignore 파일에 추가한다. (커뮤니티 기본 설정 참고)

3. 앱에 React Native 추가하기

Gradle 설정

React Native는 React Native Gradle 플러그인을 사용해 의존성과 프로젝트 설정을 구성한다.

먼저, settings.gradle 파일을 다음과 같이 수정한다 (커뮤니티 템플릿 참고):

groovy
// 자동 링크를 위한 React Native Gradle Settings 플러그인 설정
pluginManagement { includeBuild("../node_modules/@react-native/gradle-plugin") }
plugins { id("com.facebook.react.settings") }
extensions.configure(com.facebook.react.ReactSettingsExtension){ ex -> ex.autolinkLibrariesFromCommand() }
// .gradle.kts 파일을 사용하는 경우:
// extensions.configure<com.facebook.react.ReactSettingsExtension> { autolinkLibrariesFromCommand() }
includeBuild("../node_modules/@react-native/gradle-plugin")

// 기존 Gradle 모듈을 여기에 포함한다.
// include(":app")

그런 다음 최상위 build.gradle 파일을 열고 다음 줄을 추가한다 (커뮤니티 템플릿 참고):

diff
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath("com.android.tools.build:gradle:7.3.1")
+ classpath("com.facebook.react:react-native-gradle-plugin")
}
}

이렇게 하면 프로젝트 내에서 React Native Gradle 플러그인(RNGP)을 사용할 수 있다.
마지막으로, 앱의 build.gradle 파일에 다음 줄을 추가한다 (이 파일은 보통 app 폴더 안에 있으며, 커뮤니티 템플릿 파일을 참고할 수 있다):

diff
apply plugin: "com.android.application"
+apply plugin: "com.facebook.react"

repositories {
mavenCentral()
}

dependencies {
// 기존 의존성
+ // 주의: RNGP가 버전 관리를 하므로 여기서 버전을 지정하지 않는다.
+ // RNGP를 사용하지 않으면 수동으로 버전을 지정해야 한다.
+ implementation("com.facebook.react:react-android")
+ implementation("com.facebook.react:hermes-android")
}

+react {
+ // 자동 링크를 활성화하기 위해 필요 - https://github.com/react-native-community/cli/blob/master/docs/autolinking.md
+ autolinkLibrariesWithApp()
+}

마지막으로, 앱의 gradle.properties 파일을 열고 다음 줄을 추가한다 (커뮤니티 템플릿 파일 참고):

diff
+reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64
+newArchEnabled=true
+hermesEnabled=true

매니페스트 설정하기

먼저 AndroidManifest.xml에 인터넷 권한이 있는지 확인한다:

diff
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

+ <uses-permission android:name="android.permission.INTERNET" />

<application
android:name=".MainApplication">
</application>
</manifest>

그런 다음 디버그 AndroidManifest.xml에서 클리어텍스트 트래픽을 활성화해야 한다:

diff
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<application
+ android:usesCleartextTraffic="true"
+ tools:targetApi="28"
/>
</manifest>

참고로, Community 템플릿의 AndroidManifest.xml 파일을 사용할 수 있다: maindebug

이 설정은 애플리케이션이 로컬 번들러인 [Metro][https://metrobundler.dev/]와 HTTP를 통해 통신하기 위해 필요하다.

이 설정은 반드시 디버그 매니페스트에만 추가해야 한다.

4. 타입스크립트 코드 작성

이제 실제로 네이티브 안드로이드 애플리케이션을 수정하여 React Native를 통합할 차례다.

가장 먼저 작성할 코드는 애플리케이션에 통합될 새로운 화면을 위한 React Native 코드다.

index.js 파일 생성하기

먼저 React Native 프로젝트의 루트에 빈 index.js 파일을 생성한다.

index.js는 React Native 애플리케이션의 시작점이며, 항상 필요하다. 이 파일은 React Native 컴포넌트나 애플리케이션의 일부인 다른 파일을 import하는 간단한 파일이 될 수도 있고, 필요한 모든 코드를 포함할 수도 있다.

우리의 index.js 파일은 다음과 같이 작성한다 (여기서는 커뮤니티 템플릿 파일을 참고한다):

js
import {AppRegistry} from 'react-native';
import App from './App';

AppRegistry.registerComponent('HelloWorld', () => App);

App.tsx 파일을 생성한다. 이 파일은 TypeScript 파일로, JSX 표현식을 포함할 수 있다. 이 파일은 루트 React Native 컴포넌트를 담고 있으며, 이를 Android 애플리케이션에 통합할 것이다 (참고 링크):

tsx
import React from 'react';
import {
SafeAreaView,
ScrollView,
StatusBar,
StyleSheet,
Text,
useColorScheme,
View,
} from 'react-native';

import {
Colors,
DebugInstructions,
Header,
ReloadInstructions,
} from 'react-native/Libraries/NewAppScreen';

function App(): React.JSX.Element {
const isDarkMode = useColorScheme() === 'dark';

const backgroundStyle = {
backgroundColor: isDarkMode ? Colors.darker : Colors.lighter,
};

return (
<SafeAreaView style={backgroundStyle}>
<StatusBar
barStyle={isDarkMode ? 'light-content' : 'dark-content'}
backgroundColor={backgroundStyle.backgroundColor}
/>
<ScrollView
contentInsetAdjustmentBehavior="automatic"
style={backgroundStyle}>
<Header />
<View
style={{
backgroundColor: isDarkMode
? Colors.black
: Colors.white,
padding: 24,
}}>
<Text style={styles.title}>Step One</Text>
<Text>
Edit <Text style={styles.bold}>App.tsx</Text> to
change this screen and see your edits.
</Text>
<Text style={styles.title}>See your changes</Text>
<ReloadInstructions />
<Text style={styles.title}>Debug</Text>
<DebugInstructions />
</View>
</ScrollView>
</SafeAreaView>
);
}

const styles = StyleSheet.create({
title: {
fontSize: 24,
fontWeight: '600',
},
bold: {
fontWeight: '700',
},
});

export default App;

커뮤니티 템플릿 파일 참고

5. 안드로이드 코드와 통합

이제 React Native 런타임을 시작하고 React 컴포넌트를 렌더링하도록 지시하기 위해 네이티브 코드를 추가해야 한다.

Application 클래스 업데이트

먼저, Application 클래스를 업데이트하여 React Native를 올바르게 초기화한다. 아래와 같이 수정한다:

diff
package <your-package-here>;

import android.app.Application;
+import com.facebook.react.PackageList;
+import com.facebook.react.ReactApplication;
+import com.facebook.react.ReactHost;
+import com.facebook.react.ReactNativeHost;
+import com.facebook.react.ReactPackage;
+import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint;
+import com.facebook.react.defaults.DefaultReactHost;
+import com.facebook.react.defaults.DefaultReactNativeHost;
+import com.facebook.soloader.SoLoader;
+import com.facebook.react.soloader.OpenSourceMergedSoMapping
+import java.util.List;

-class MainApplication extends Application {
+class MainApplication extends Application implements ReactApplication {
+ @Override
+ public ReactNativeHost getReactNativeHost() {
+ return new DefaultReactNativeHost(this) {
+ @Override
+ protected List<ReactPackage> getPackages() { return new PackageList(this).getPackages(); }
+ @Override
+ protected String getJSMainModuleName() { return "index"; }
+ @Override
+ public boolean getUseDeveloperSupport() { return BuildConfig.DEBUG; }
+ @Override
+ protected boolean isNewArchEnabled() { return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; }
+ @Override
+ protected Boolean isHermesEnabled() { return BuildConfig.IS_HERMES_ENABLED; }
+ };
+ }

+ @Override
+ public ReactHost getReactHost() {
+ return DefaultReactHost.getDefaultReactHost(getApplicationContext(), getReactNativeHost());
+ }

@Override
public void onCreate() {
super.onCreate();
+ SoLoader.init(this, OpenSourceMergedSoMapping);
+ if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
+ DefaultNewArchitectureEntryPoint.load();
+ }
}
}

참고로, MainApplication.kt 커뮤니티 템플릿 파일을 확인할 수 있다.

ReactActivity 만들기

마지막으로, ReactActivity를 상속받아 React Native 코드를 호스팅할 새로운 Activity를 생성해야 한다. 이 액티비티는 React Native 런타임을 시작하고 React 컴포넌트를 렌더링하는 역할을 담당한다.

java
// package <your-package-here>;

import com.facebook.react.ReactActivity;
import com.facebook.react.ReactActivityDelegate;
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint;
import com.facebook.react.defaults.DefaultReactActivityDelegate;

public class MyReactActivity extends ReactActivity {

@Override
protected String getMainComponentName() {
return "HelloWorld";
}

@Override
protected ReactActivityDelegate createReactActivityDelegate() {
return new DefaultReactActivityDelegate(this, getMainComponentName(), DefaultNewArchitectureEntryPoint.getFabricEnabled());
}
}

참고로, MainActivity.kt 커뮤니티 템플릿 파일을 확인할 수 있다.

새로운 액티비티를 만들 때마다 AndroidManifest.xml 파일에 추가해야 한다. 또한 MyReactActivity의 테마를 Theme.AppCompat.Light.NoActionBar(또는 ActionBar가 없는 테마)로 설정해야 한다. 그렇지 않으면 React Native 화면 위에 ActionBar가 렌더링된다.

diff
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

<uses-permission android:name="android.permission.INTERNET" />

<application
android:name=".MainApplication">

+ <activity
+ android:name=".MyReactActivity"
+ android:label="@string/app_name"
+ android:theme="@style/Theme.AppCompat.Light.NoActionBar">
+ </activity>
</application>
</manifest>

이제 액티비티가 JavaScript 코드를 실행할 준비가 되었다.

6. 통합 테스트

React Native를 여러분의 애플리케이션에 통합하기 위한 기본 단계를 모두 마쳤다. 이제 Metro 번들러를 실행해 TypeScript 애플리케이션 코드를 번들로 빌드한다. Metro의 HTTP 서버는 localhost에서 개발 환경의 시뮬레이터나 기기로 번들을 공유한다. 이를 통해 핫 리로딩이 가능하다.

먼저, 프로젝트 루트에 metro.config.js 파일을 다음과 같이 생성한다:

js
const {getDefaultConfig} = require('@react-native/metro-config');
module.exports = getDefaultConfig(__dirname);

참고용으로 metro.config.js 파일을 커뮤니티 템플릿에서 확인할 수 있다.

설정 파일이 준비되면 번들러를 실행한다. 프로젝트 루트 디렉토리에서 다음 커맨드를 실행한다:

shell
npm start

이제 일반적인 방식으로 Android 앱을 빌드하고 실행한다.

앱 내부에서 React로 구동되는 Activity에 도달하면 개발 서버에서 JavaScript 코드를 로드하고 화면에 표시한다:

Android Studio에서 릴리스 빌드 생성하기

Android Studio를 사용해 릴리스 빌드를 생성할 수도 있다. 기존 네이티브 Android 앱의 릴리스 빌드를 생성하는 것만큼 간단하다.

React Native Gradle Plugin이 JS 코드를 APK/App Bundle 내부로 번들링하는 작업을 처리한다.

Android Studio를 사용하지 않는다면, 다음 명령어로 릴리스 빌드를 생성할 수 있다:

cd android
# 릴리스 APK 생성
./gradlew :app:assembleRelease
# 릴리스 AAB 생성
./gradlew :app:bundleRelease

다음 단계는?

이제 평소처럼 앱 개발을 계속 진행하면 된다. React Native 작업에 대한 더 많은 정보를 얻으려면 디버깅배포 문서를 참고한다.