이 튜토리얼에서는 React Native, Expo 및 Firebase를 백엔드 서비스로 사용하여 채팅 애플리케이션을 구축할 것입니다. 응용 프로그램에는 특정 사용자별로 이메일 주소를 사용하는 간단한 로그인 시스템이 포함됩니다. 사용자는 프로필 사진을 업로드할 수 있습니다. 채팅 앱은 글로벌 채팅방에 가깝지만 실시간으로 작동합니다.
이 튜토리얼의 전체 소스 코드는 이 GitHub Repository에서 확인할 수 있습니다.
종속성 설치 중
시작하려면 로컬 시스템에 Expo CLI가 설치되어 있어야 합니다. 터미널에서 다음 명령을 실행하여 CLI를 설치하고 이를 사용하여 새 프로젝트를 생성합니다.
# To install expo-cli
npm install -g expo-cli
# To generate new project
expo init RNfirebase-chat
# Choose blank template when asked
# traverse inside the project directory
cd RNfirebase-chat
프로젝트가 생성되면 iOS 시뮬레이터 또는 Android 에뮬레이터에서 실행하여 모든 것이 작동하는지 확인할 수 있습니다. Android 개발자는 아래 명령을 실행하기 전에 Android 가상 장치가 실행 중인지 확인해야 합니다.
# for iOS simalulor
yarn ios
# for Android device/emulator
yarn android
다음으로 대화 응용 프로그램에 사용자 정의 가능한 UI를 제공하는 react-native-gifated-chat이라는 종속성을 설치합니다. 서로 다른 화면을 탐색하기 위해서는 리액트 내비게이션을 사용할 예정이며, 마지막으로 Firebase 프로젝트와 연결하려면 Firebase SDK가 필요합니다.
npm install @react-navigation/native @react-navigation/stack react-native-gifted-chat
# OR is using yarn
yarn add @react-navigation/native @react-navigation/stack react-native-gifted-chat
# after the above dependencies install successfully
expo install firebase expo-constants dotenv react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view
애플리케이션을 구축하려면 다음이 필요합니다.
- 사용자 인증 서비스
- 사용자의 전자 메일을 저장하는 서비스
- 메시지를 저장하는 서비스
이 모든 서비스는 파이어베이스에서 활용된다. 인증 플로우를 구축할 때 엑스포로 파이어베이스 Auth 구현의 깊이를 다루지 않을 것입니다. 여기서는 이미 별도의 튜토리얼에서 자세히 다루었습니다.
파이어베이스 설정
파이어베이스는 이메일과 소셜미디어 인증, 실시간 데이터베이스, 머신러닝 키트, API 등과 같은 서비스를 SDK에 제공하는 구글의 애플리케이션 개발 도구이다. 파이어베이스는 클라우드 서비스인 구글 클라우드 플랫폼과 통합이 가능하다.
애플리케이션에서는 이메일 인증과 클라우드 스토리지를 사용할 예정입니다. Firebase 자유 계층 프로젝트를 설정하려면 Firebase Console을 방문하여 새 프로젝트를 만들고 이름을 입력한 다음 Add Project 버튼을 클릭합니다.
그런 다음 새 Firebase 프로젝트의 이름을 추가한 다음 계속을 누르십시오. Google Analytics 설정을 요청하면 이 예제에서는 사용되지 않으므로 해당 설정을 비활성화할 수 있습니다. 그런 다음 프로젝트 생성을 누르십시오.
파이어베이스 프로젝트가 만들어지면 아래와 같이 홈 스크린에서 환영받을 것입니다.
왼쪽에 있는 사이드 메뉴바를 보세요. 파이어베이스 프로젝트의 주요 내비게이션입니다. 먼저 인증을 활성화해야 합니다. 빌드 섹션 아래의 인증 탭을 클릭한 다음 로그인 방법을 클릭합니다. Email/Password를 사용하여 인증을 활성화한 다음 Save(저장) 버튼을 누릅니다.
Dashboard 화면의 왼쪽 메뉴에서 설정 아이콘을 클릭한 다음 Project Settings 페이지로 이동하여 General > Your apps 섹션을 찾습니다. 새로운 프로젝트라면 앱이 없을 거예요.
웹 단추를 누릅니다. 앱의 세부 정보를 입력하라는 메시지가 표시됩니다. 앱의 닉네임을 입력한 다음 앱 등록 버튼을 클릭합니다.
그런 다음 Firebase는 구성 개체에 API 키와 다른 Firebase 서비스를 사용하는 데 필요한 기타 키를 제공합니다.
이러한 API 키는 Firebase 서비스의 백엔드 리소스에 액세스하는 데 사용되지 않으므로 React Native 앱에 포함될 수 있습니다. 그것은 파이어베이스 보안 규칙에 의해서만 가능하다.
그렇다고 해서 이러한 키를 GitHub와 같은 버전 제어 호스트에 노출해야 하는 것은 아닙니다.
엑스포 앱에 파이어베이스 인증을 통합하는 방법 게시물에서는 환경변수를 .env에서 설정하고 엑스포 컨스턴트 패키지를 사용하여 사용하는 방법에 대해 논의했습니다. 우리는 여기서 같은 방법론을 따를 것입니다.
응답 네이티브 프로젝트의 루트에 .env 파일을 생성하고 다음을 추가하십시오. X를 Firebase의 실제 키로 교체합니다.
API_KEY=XXXX
AUTH_DOMAIN=XXXX
PROJECT_ID=XXXX
STORAGE_BUCKET=XXXX
MESSAGING_SENDER_ID=XXXX
APP_ID=XXX
다음으로 app.json 파일의 이름을 프로젝트의 루트에 있는 app.config.js로 바꿉니다. import 문을 추가하여 dotenv 구성을 사용하여 환경 변수를 읽습니다. JavaScript 파일이므로 Expo 구성 변수를 모두 내보내고 Firebase 구성 키를 포함하는 개체를 추가해야 합니다. 이 단계 이후의 파일 모양은 다음과 같습니다.
import 'dotenv/config';
export default {
expo: {
name: 'expo-firebase-auth-example',
slug: 'expo-firebase-auth-example',
version: '1.0.0',
orientation: 'portrait',
icon: './assets/icon.png',
splash: {
image: './assets/splash.png',
resizeMode: 'contain',
backgroundColor: '#ffffff'
},
updates: {
fallbackToCacheTimeout: 0
},
assetBundlePatterns: ['**/*'],
ios: {
supportsTablet: true
},
android: {
adaptiveIcon: {
foregroundImage: './assets/adaptive-icon.png',
backgroundColor: '#FFFFFF'
}
},
web: {
favicon: './assets/favicon.png'
},
extra: {
apiKey: process.env.API_KEY,
authDomain: process.env.AUTH_DOMAIN,
projectId: process.env.PROJECT_ID,
storageBucket: process.env.STORAGE_BUCKET,
messagingSenderId: process.env.MESSAGING_SENDER_ID,
appId: process.env.APP_ID
}
}
};
이제, 엑스포 컨스탄트를 사용하여 추가 객체 안에 있는 모든 키를 앱 전체에 걸쳐 읽을 수 있습니다. 이 패키지를 사용하면 app.json(이 경우 app.config.js 파일)에서 값을 읽을 수 있습니다.
React Native 프로젝트 내에서 config/라는 새 디렉토리를 루트에 작성하고 firebase.js라는 파일을 추가합니다. 아래와 같이 파일을 편집합니다.
import { initializeApp } from 'firebase/app';
import { getAuth } from 'firebase/auth';
import { getFirestore } from 'firebase/firestore';
import Constants from 'expo-constants';
// Firebase config
const firebaseConfig = {
apiKey: Constants.manifest.extra.apiKey,
authDomain: Constants.manifest.extra.authDomain,
projectId: Constants.manifest.extra.projectId,
storageBucket: Constants.manifest.extra.storageBucket,
messagingSenderId: Constants.manifest.extra.messagingSenderId,
appId: Constants.manifest.extra.appId,
databaseURL: Constants.manifest.extra.databaseURL
};
// initialize firebase
initializeApp(firebaseConfig);
export const auth = getAuth();
export const database = getFirestore();
Firestore 데이터베이스 설정
다음 단계는 데이터베이스 규칙을 실행하는 것입니다. 사이드바 메뉴에서 Firestore Database라는 두 번째 탭을 방문하십시오.
데이터베이스 작성을 누르십시오. 보안 규칙을 묻는 메시지가 표시되면 이 예의 테스트 모드를 선택합니다. 여기에서 Firebase를 사용한 보안 규칙에 대해 자세히 알아보고 그에 따라 규칙을 업데이트할 수 있습니다.
그런 다음 위치를 기본값으로 설정하고 사용을 클릭합니다.
세팅은 여기까지입니다. 다음 섹션에서는 애플리케이션 구축을 시작하겠습니다.
채팅 화면
리액트 네이티브 영재 채팅 구성 요소를 사용하면 서로 다른 사용자가 보낼 채팅 메시지를 표시할 수 있습니다. 시작하려면 화면이라는 새 디렉터리를 만드십시오. 여기에 스크린 부품을 모두 보관할 예정입니다. 이 디렉토리 내에 다음 코드 조각으로 Chat.js라는 새 파일을 작성합니다.
import React from 'react'
import { GiftedChat } from 'react-native-gifted-chat'
export default function Chat() {
return (
<GiftedChat />
)
}
이제 App.js 파일을 열고 논리를 추가하여 반응 내비게이션 모듈을 사용하여 내비게이션 구성 요소를 만듭니다. 이 파일은 하나의 화면만 포함하는 ChatStack 탐색기인 RootNavigator를 포함할 것이며, 나중에 인증된 사용자를 처리하여 채팅 화면만 볼 수 있도록 비즈니스 논리를 갖춘 AuthStack 탐색기를 추가할 것입니다.
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import Chat from './screens/Chat';
const Stack = createStackNavigator();
function ChatStack() {
return (
<Stack.Navigator>
<Stack.Screen name='Chat' component={Chat} />
</Stack.Navigator>
);
}
function RootNavigator() {
return (
<NavigationContainer>
<ChatStack />
</NavigationContainer>
);
}
export default function App() {
return <RootNavigator />;
}
이제 시뮬레이터 장치를 실행하면 플레인 화이트 헤더와 배경, 화면 하단에 사용자가 메시지를 입력할 수 있는 입력 영역이 있는 베어 최소 채팅 화면이 있음을 알 수 있습니다. 무언가를 입력하면 보내기 단추가 자동으로 나타납니다.
그러나 이 보내기 버튼은 현재 기능이 없습니다.
로그인 화면 추가
화면/디렉토리 내에 Login.js라는 화면 구성 요소를 만듭니다. 이 구성 요소 파일에는 로그인 화면의 구성 요소 구조가 포함됩니다.
화면 자체에는 앱 사용자가 자격 증명을 입력할 수 있는 두 개의 입력 필드와 앱에 로그인하기 위한 버튼이 있습니다. 사용자가 앱에 등록하지 않은 경우 가입 화면으로 이동할 수 있는 또 다른 버튼이 제공됩니다. 이러한 모든 구성요소는 Responent Native를 사용하여 작성됩니다.
먼저 React Native Core에서 필요한 구성 요소를 가져오고 config/firebase.js 파일에서 auth 개체를 가져옵니다.
OnHandleLogin 메서드는 Firebase Auth의 signInWithEmailAndPassword() 메서드를 사용하여 사용자의 자격 증명을 인증합니다. 자격 증명이 정확한 경우 사용자는 대화 화면으로 이동합니다. 그렇지 않으면 터미널 창에 오류가 표시됩니다. 이러한 오류를 처리하기 위해 자신만의 비즈니스 논리를 추가할 수 있습니다.
다음은 Login.js 파일의 전체 코드 조각입니다.
import React, { useState } from 'react';
import { StyleSheet, Text, View, Button, TextInput } from 'react-native';
import { signInWithEmailAndPassword } from 'firebase/auth';
import { auth } from '../config/firebase';
export default function Login({ navigation }) {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const onHandleLogin = () => {
if (email !== '' && password !== '') {
signInWithEmailAndPassword(auth, email, password)
.then(() => console.log('Login success'))
.catch(err => console.log(`Login err: ${err}`));
}
};
return (
<View style={styles.container}>
<Text style={styles.title}>Welcome back!</Text>
<TextInput
style={styles.input}
placeholder='Enter email'
autoCapitalize='none'
keyboardType='email-address'
textContentType='emailAddress'
autoFocus={true}
value={email}
onChangeText={text => setEmail(text)}
/>
<TextInput
style={styles.input}
placeholder='Enter password'
autoCapitalize='none'
autoCorrect={false}
secureTextEntry={true}
textContentType='password'
value={password}
onChangeText={text => setPassword(text)}
/>
<Button onPress={onHandleLogin} color='#f57c00' title='Login' />
<Button
onPress={() => navigation.navigate('Signup')}
title='Go to Signup'
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
paddingTop: 50,
paddingHorizontal: 12
},
title: {
fontSize: 24,
fontWeight: '600',
color: '#444',
alignSelf: 'center',
paddingBottom: 24
},
input: {
backgroundColor: '#fff',
marginBottom: 20,
fontSize: 16,
borderWidth: 1,
borderColor: '#333',
borderRadius: 8,
padding: 12
}
});
화면의 모양은 다음과 같습니다.
등록 화면 만들기
로그인 화면과 비슷합니다. 입력 필드와 버튼은 하나만 제외하고 동일합니다. onHandleSignup이라는 이 파일에 정의된 처리기 메서드는 Firebase의 createUserWithEmailAndPassword() 메서드를 사용하여 새 사용자 계정을 만듭니다.
화면 디렉터리 내에 새 파일을 만들고 이름을 Signup.js로 지정합니다. 다음 코드 조각을 추가합니다.
import React, { useState } from 'react';
import { StyleSheet, Text, View, Button, TextInput } from 'react-native';
import { createUserWithEmailAndPassword } from 'firebase/auth';
import { auth } from '../config/firebase';
export default function Signup({ navigation }) {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const onHandleSignup = () => {
if (email !== '' && password !== '') {
createUserWithEmailAndPassword(auth, email, password)
.then(() => console.log('Signup success'))
.catch(err => console.log(`Login err: ${err}`));
}
};
return (
<View style={styles.container}>
<Text style={styles.title}>Create new account</Text>
<TextInput
style={styles.input}
placeholder='Enter email'
autoCapitalize='none'
keyboardType='email-address'
textContentType='emailAddress'
value={email}
onChangeText={text => setEmail(text)}
/>
<TextInput
style={styles.input}
placeholder='Enter password'
autoCapitalize='none'
autoCorrect={false}
secureTextEntry={true}
textContentType='password'
value={password}
onChangeText={text => setPassword(text)}
/>
<Button onPress={onHandleSignup} color='#f57c00' title='Signup' />
<Button
onPress={() => navigation.navigate('Login')}
title='Go to Login'
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
paddingTop: 50,
paddingHorizontal: 12
},
title: {
fontSize: 24,
fontWeight: '600',
color: '#444',
alignSelf: 'center',
paddingBottom: 24
},
input: {
backgroundColor: '#fff',
marginBottom: 20,
fontSize: 16,
borderWidth: 1,
borderColor: '#333',
borderRadius: 8,
padding: 12
}
});
화면의 모양은 다음과 같습니다.
인증된 사용자 제공자를 추가하는 중
Reactjs에서 Context API는 리액트 구성 요소 트리에 대해 전역으로 간주되는 데이터를 공유하도록 설계되었습니다. 컨텍스트를 작성할 때 기본값을 전달해야 합니다. 이 값은 구성 요소에 일치하는 공급자가 없을 때 사용됩니다.
공급자를 사용하면 React 구성 요소가 컨텍스트 변경사항을 구독할 수 있습니다. 이러한 상황 변화는 채팅 앱에서 사용자의 로그인 상태를 확인하는 데 도움이 될 수 있습니다.
이 섹션에서는 App.js 파일을 채팅 및 Auth 관련 화면을 위한 두 개의 스택 네비게이터로 수정할 것입니다. 먼저 Import 문을 추가한 다음 ChatStack 및 AuthStack 탐색기 함수를 정의하겠습니다.
import React, { useState, createContext, useContext, useEffect } from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import { View, ActivityIndicator } from 'react-native';
import { onAuthStateChanged } from 'firebase/auth';
import { auth } from './config/firebase';
import Login from './screens/Login';
import Signup from './screens/Signup';
import Chat from './screens/Chat';
const Stack = createStackNavigator();
function ChatStack() {
return (
<Stack.Navigator>
<Stack.Screen name='Chat' component={Chat} />
</Stack.Navigator>
);
}
function AuthStack() {
return (
<Stack.Navigator screenOptions={ headerShown: false }>
<Stack.Screen name='Login' component={Login} />
<Stack.Screen name='Signup' component={Signup} />
</Stack.Navigator>
);
}
인증 공급자를 생성하려면 AuthenticatedUserProvider라는 기능을 내보냅니다. 이 공급자는 화면 구성 요소가 응용 프로그램의 현재 사용자에게 액세스할 수 있도록 허용합니다. user라는 상태 변수를 정의합니다.
다음 코드 조각을 추가합니다.
const AuthenticatedUserContext = createContext({});
const AuthenticatedUserProvider = ({ children }) => {
const [user, setUser] = useState(null);
return (
<AuthenticatedUserContext.Provider value={ user, setUser }>
{children}
</AuthenticatedUserContext.Provider>
);
};
다음으로 RootNavigator 함수를 수정합니다. 이 기능에서는 사용자의 로그인 상태 변경을 처리할 파이어베이스 메소드를 AuthStateChanged()에 사용할 것입니다. useEffect hook을 사용하면 이 상태 변경 함수를 구독하고 구성 요소가 마운트 해제될 때 구독을 취소할 수 있습니다. 이 방법을 사용하면 사용자가 작업을 수행할 때 실시간 이벤트를 구독할 수 있습니다. 여기서 수행할 수 있는 작업은 로그인, 로그아웃 등이 있습니다.
function RootNavigator() {
const { user, setUser } = useContext(AuthenticatedUserContext);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
// onAuthStateChanged returns an unsubscriber
const unsubscribeAuth = onAuthStateChanged(
auth,
async authenticatedUser => {
authenticatedUser ? setUser(authenticatedUser) : setUser(null);
setIsLoading(false);
}
);
// unsubscribe auth listener on unmount
return unsubscribeAuth;
}, [user]);
if (isLoading) {
return (
<View style={ flex: 1, justifyContent: 'center', alignItems: 'center' }>
<ActivityIndicator size='large' />
</View>
);
}
return (
<NavigationContainer>
{user ? <ChatStack /> : <AuthStack />}
</NavigationContainer>
);
}
마지막으로 앱 기능 내에서 AuthenticatedUserProvider로 RootNavigator를 래핑합니다.
export default function App() {
return (
<AuthenticatedUserProvider>
<RootNavigator />
</AuthenticatedUserProvider>
);
}
파이어베이스 인증은 앱에서 구현됩니다.
채팅 기능 추가
현재 채팅 어플리케이션에서 인증이 작동 중이기 때문에, 우리는 앞으로 나아가 채팅 기능 자체를 추가할 수 있습니다. 이 구성 요소는 채팅 메시지를 생성하고 전송하기 위해 파이어베이스의 사용자 정보가 필요합니다.
먼저 Respect Native Guident Chat 라이브러리에서 필요한 구성 요소를 가져오고 Firebase/firestore에서 auth 및 database 객체를 가져와 데이터를 컬렉션에 추가합니다.
import React, {
useState,
useEffect,
useLayoutEffect,
useCallback
} from 'react';
import { TouchableOpacity, Text } from 'react-native';
import { GiftedChat } from 'react-native-gifted-chat';
import {
collection,
addDoc,
orderBy,
query,
onSnapshot
} from 'firebase/firestore';
import { signOut } from 'firebase/auth';
import { auth, database } from '../config/firebase';
Chat 함수 내에는 useLayoutEffect를 사용하여 로그아웃 작업을 처리하는 메시지 상태 및 함수를 만들고 OnSignOut 핸들러 메서드 내에서 사용자를 로그아웃시키는 비즈니스 로직을 만듭니다.
export default function Chat({ navigation }) {
const [messages, setMessages] = useState([]);
const onSignOut = () => {
signOut(auth).catch(error => console.log('Error logging out: ', error));
};
useLayoutEffect(() => {
navigation.setOptions({
headerRight: () => (
<TouchableOpacity
style={
marginRight: 10
}
onPress={onSignOut}
>
<Text>Logout</Text>
</TouchableOpacity>
)
});
}, [navigation]);
Firestore 데이터베이스에서 오래된 메시지를 검색하려면 데이터베이스 컬렉션에 대한 API 호출이 필요합니다. 우리는 컬렉션 이름을 채팅으로 설정하고 useLayoutEffect hook을 사용하여 이 데이터베이스를 호출할 것입니다.
메시지를 보내기 위해 onSend라는 커스텀 핸들러 메소드를 만들겠습니다. 이 방법은 useCallback 훅을 사용하며 메시지를 Firestore 모음인 채팅에 저장합니다. Firestore의 addDoc 메소드를 사용하여 새 메시지가 전송될 때 자동 생성된 ID로 새 문서를 작성합니다.
useLayoutEffect(() => {
const collectionRef = collection(database, 'chats');
const q = query(collectionRef, orderBy('createdAt', 'desc'));
const unsubscribe = onSnapshot(q, querySnapshot => {
setMessages(
querySnapshot.docs.map(doc => ({
_id: doc.data()._id,
createdAt: doc.data().createdAt.toDate(),
text: doc.data().text,
user: doc.data().user
}))
);
});
return unsubscribe;
});
const onSend = useCallback((messages = []) => {
setMessages(previousMessages =>
GiftedChat.append(previousMessages, messages)
);
const { _id, createdAt, text, user } = messages[0];
addDoc(collection(database, 'chats'), {
_id,
createdAt,
text,
user
});
}, []);
마지막으로 영재챗 컴포넌트와 다양한 소품을 사용할 것입니다. 첫 번째 요소는 메시지를 표시하는 메시지입니다. 다음 prop showAvatarForEveryMessage가 true로 설정됩니다. 우리는 이 예에 대해 로그인하고 메시지를 보내는 각 사용자에 대해 무작위 아바타를 설정할 것입니다. 당신은 그것을 당신만의 논리로 대체하여 더 나은 아바타 생성 솔루션을 추가할 수 있습니다.
onSend 소품은 메시지 전송을 담당합니다. 사용자 객체는 메시지를 발송하는 사용자를 식별하는 것입니다.
return (
<GiftedChat
messages={messages}
showAvatarForEveryMessage={true}
onSend={messages => onSend(messages)}
user={
_id: auth?.currentUser?.email,
avatar: 'https://i.pravatar.cc/300'
}
/>
);
다음은 이 단계 이후의 출력입니다.
결론
파이어베이스는 시간 절약과 더 빠른 앱 개발 측면에서 훌륭한 서비스입니다. 처음부터 완전한 백엔드를 구축하지 않고 특정 사용 사례(예: 이 튜토리얼에서 설명)와 통합하는 것이 모든 Ract Native 개발자에게 장점입니다.
마지막으로 민감한 논리로 Response Native 앱을 구축하는 경우에는 가이드를 따라 코드 도난 및 리버스 엔지니어링으로부터 앱을 보호해야 합니다.
원래 아만 미탈이 Jscrambler 블로그에 게시하였다.
'javascript' 카테고리의 다른 글
8가지 무료 개발자 튜토리얼을 통해 실제로 일자리를 얻으실 수 있습니다. (0) | 2021.12.30 |
---|---|
콩키스타 미냐 바가 데센볼베도르 주니오르 (0) | 2021.12.30 |
이게 뭐야? JavaScript에서 실행 컨텍스트 이해 (0) | 2021.12.29 |
트릴하르 펀더마 다 로켓 시트 아프렌더 컴 (0) | 2021.12.29 |
Mapas con 자바스크립트 (0) | 2021.12.29 |
댓글