๊ฐ๋ฐ/Zooda
React Native + Kotlin ๋ค์ดํฐ๋ธ ๋ชจ๋ ์ฑ ๊ฐ๋ฐ (Metro ์๋ฒ ํฌํจ ์ ์ฒด ๊ตฌ์กฐ ์ค๋ช )(chatgpt)
da
2025. 6. 29. 11:02
๐ React Native + Kotlin ๋ค์ดํฐ๋ธ ๋ชจ๋ ์ฑ ๊ฐ๋ฐ (Metro ์๋ฒ ํฌํจ ์ ์ฒด ๊ตฌ์กฐ ์ค๋ช )
React Native๋ ๋น ๋ฅธ UI ๊ฐ๋ฐ์ ์ต์ ํ๋ ํ๋ ์์ํฌ์ ๋๋ค. ํ์ง๋ง ๋ธ๋ฃจํฌ์ค, ์ผ์, GPS ๋ฑ Android ๊ณ ์ ๊ธฐ๋ฅ์ ์ฌ์ฉํ๋ ค๋ฉด Kotlin ๋๋ Java๋ก ๋ค์ดํฐ๋ธ ๋ชจ๋์ ๊ตฌํํด์ผ ํฉ๋๋ค. ์ด ๊ธ์์๋ React Native + Kotlin ์ฐ๋ ์์ ๋ฅผ ๊ธฐ์ค์ผ๋ก, ์ฑ์ด ์ด๋ป๊ฒ ๊ตฌ์ฑ๋๊ณ , ์ด๋ป๊ฒ ์คํ๋๋์ง, ๊ทธ๋ฆฌ๊ณ Metro ์๋ฒ์ ์ญํ ๊น์ง ์ ์ฒด ํ๋ฆ์ ์ ๋ฆฌํด๋ด ๋๋ค.
๐ ํ๋ก์ ํธ ๊ตฌ์กฐ ์์ฝ
test_project/
โโโ App.js
โโโ /screens
โ โโโ HomeScreen.js
โ โโโ SecondScreen.js
โโโ /android/app/src/main/java/com/test_project
โ โโโ MyNativeModule.kt โ ๋ค์ดํฐ๋ธ ๊ธฐ๋ฅ ์ ์
โ โโโ MyPackage.kt โ ํจํค์ง ๋ฑ๋ก
โโโ /android/app/src/main/java/com/test_project/MainApplication.kt
โ๏ธ ๊ตฌ์ฑ์์ ์ค๋ช (Metro ํฌํจ)
๊ตฌ์ฑ ์์ | ์ธ์ด | ์ญํ |
---|---|---|
App.js | JS | ์ฑ ์ง์ ์ , ํ๋ฉด ์ ํ ์ ์ |
HomeScreen.js | JS | ์ฒซ ํ๋ฉด, ๋ฒํผ ํด๋ฆญ์ผ๋ก ํ๋ฉด ์ ํ |
SecondScreen.js | JS | Kotlin ๋ค์ดํฐ๋ธ ๋ชจ๋ ํธ์ถ ๋ฐ ๊ฒฐ๊ณผ ํ์ |
MyNativeModule.kt | Kotlin | JS์์ ํธ์ถ ๊ฐ๋ฅํ ๋ค์ดํฐ๋ธ ํจ์ ์ ์ |
MyPackage.kt | Kotlin | Kotlin ๋ชจ๋์ RN์ ๋ฑ๋ก |
MainApplication.kt | Kotlin | ์ฑ ์ด๊ธฐํ ๋ฐ ํจํค์ง ์๋ ๋ฑ๋ก |
Metro Server | Node.js (CLI) | JS ๋ฒ๋ค ์์ฑ ๋ฐ ์ฑ์ ์ ์ก (๊ฐ๋ฐ ์ ํ์) |
๐ ์ฃผ์ ํ์ผ ์ฝ๋ ์์
1. App.js
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import HomeScreen from './screens/HomeScreen';
import SecondScreen from './screens/SecondScreen';
const Stack = createNativeStackNavigator();
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Second" component={SecondScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
2. HomeScreen.js
import React from 'react';
import { View, Button, StyleSheet } from 'react-native';
const HomeScreen = ({ navigation }) => {
return (
<View style={styles.container}>
<Button
title="๋ค์ดํฐ๋ธ ๋ฉ์์ง ๋ณด๊ธฐ"
onPress={() => navigation.navigate('Second')}
/>
</View>
);
};
export default HomeScreen;
const styles = StyleSheet.create({
container: { flex: 1, justifyContent: 'center', alignItems: 'center' },
});
3. SecondScreen.js
import React, { useEffect, useState } from 'react';
import { View, Text, StyleSheet, NativeModules } from 'react-native';
const { MyNativeModule } = NativeModules;
const SecondScreen = () => {
const [message, setMessage] = useState('...');
useEffect(() => {
MyNativeModule.getNativeMessage()
.then(result => setMessage(result))
.catch(error => setMessage(`Error: ${error.message}`));
}, []);
return (
<View style={styles.container}>
<Text style={styles.title}>Kotlin์์ ์จ ๋ฉ์์ง:</Text>
<Text style={styles.message}>{message}</Text>
</View>
);
};
export default SecondScreen;
const styles = StyleSheet.create({
container: { flex: 1, justifyContent: 'center', alignItems: 'center' },
title: { fontSize: 20, marginBottom: 10 },
message: { fontSize: 24, color: 'blue' },
});
4. MyNativeModule.kt
package com.test_project
import com.facebook.react.bridge.Promise
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ReactContextBaseJavaModule
import com.facebook.react.bridge.ReactMethod
class MyNativeModule(reactContext: ReactApplicationContext) :
ReactContextBaseJavaModule(reactContext) {
override fun getName(): String {
return "MyNativeModule"
}
@ReactMethod
fun getNativeMessage(promise: Promise) {
promise.resolve("์๋
ํ์ธ์! Kotlin์์ ์์ด์ ๐")
}
}
5. MyPackage.kt
package com.test_project
import com.facebook.react.ReactPackage
import com.facebook.react.bridge.NativeModule
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.uimanager.ViewManager
class MyPackage : ReactPackage {
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
return listOf(MyNativeModule(reactContext))
}
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
return emptyList()
}
}
6. MainApplication.kt
import com.test_project.MyPackage // ์๋จ import ์ถ๊ฐ
override fun getPackages(): List<ReactPackage> =
PackageList(this).packages.apply {
add(MyPackage()) // ๐ ๋ค์ดํฐ๋ธ ํจํค์ง ์๋ ๋ฑ๋ก
}
โ๏ธ ๋น๋ ๋ฐ ์คํ ๊ณผ์
- Metro ์๋ฒ ์คํ - JS ์ฝ๋ ๋ฒ๋ค ์์ฑ ์๋ฒ
npx react-native start --reset-cache
- ์ฑ ๋น๋ ๋ฐ ์ค์น - Kotlin ํฌํจ APK ๋น๋
npm run android
- ADB๋ฅผ ํตํด APK๊ฐ ๋๋ฐ์ด์ค์ ์ค์น ๋ฐ ์คํ
- ์ฑ ์คํ โ JS Bundle ๋ก๋ฉ (http://10.0.2.2:8081/...)
โถ๏ธ ์ฑ ๊ตฌ๋ ์์ (์ ์ฒด ํ๋ฆ)
1. ์ฌ์ฉ์ ์ฑ ์คํ
2. Android โ MainApplication.kt โ ReactNativeHost ์ด๊ธฐํ
3. Metro ์๋ฒ์์ JS ๋ฒ๋ค ๋ค์ด๋ก๋
4. React Native ๋ฐํ์ ์คํ โ App.js โ HomeScreen
5. ๋ฒํผ ํด๋ฆญ โ SecondScreen
6. NativeModules.MyNativeModule.getNativeMessage() ํธ์ถ
7. Kotlin ์ฝ๋ ์คํ โ ๋ฉ์์ง ๋ฐํ
8. React Native ํ๋ฉด์ ๋ฉ์์ง ํ์
๐ ์ ๋ฆฌ
- React Native๋ UI ๋ฐ ํ๋ฉด ์ ํ ๋ด๋น
- Kotlin์ ํ๋์จ์ด ๊ธฐ๋ฅ, ์์คํ ์ ๊ทผ ๋ด๋น
- Metro ์๋ฒ๋ ๊ฐ๋ฐ ์ ํ์์ ์ธ JS ์ฝ๋ ๊ณต๊ธ ์๋ฒ
- ๋ ์ฌ์ด๋ฅผ NativeModules๋ก ์ฐ๊ฒฐ