Skip to main content

기존 앱과의 통합

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 사용하기를 참고한다. 이 가이드는 또한 액티비티 생성이나 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 폴더가 생성된다. 이 폴더는 프로젝트를 빌드하는 데 필요한 모든 자바스크립트 의존성을 저장한다.

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

3. 앱에 React Native 추가하기

Gradle 설정

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

먼저, 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 Plugin(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 컴포넌트를 담고 있다(참조 링크):

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 클래스 업데이트

먼저, React Native를 올바르게 초기화하기 위해 Application 클래스를 다음과 같이 업데이트한다.

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를 확장하는 새로운 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);

참고를 위해 Community 템플릿 파일에서 metro.config.js 파일을 확인할 수 있다.

설정 파일을 준비한 후 번들러를 실행한다. 프로젝트 루트 디렉토리에서 다음 명령을 실행한다:

shell
npm start

이제 평소처럼 Android 앱을 빌드하고 실행한다.

앱 내부에서 React로 구동되는 Activity에 도달하면, 개발 서버에서 JavaScript 코드를 로드하고 다음과 같이 표시된다:

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

Android Studio를 사용해도 릴리스 빌드를 쉽게 만들 수 있다. 기존의 네이티브 Android 앱을 빌드하는 것과 동일한 과정으로 진행된다.

React Native Gradle Plugin이 APK나 App Bundle 내부에 JS 코드를 번들링하는 작업을 자동으로 처리해준다.

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

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

이 시점에서 여러분은 평소처럼 앱 개발을 계속할 수 있다. React Native 작업에 대해 더 알고 싶다면 디버깅배포 문서를 참고한다.