2022. 5. 14. 00:20ㆍ프로그래밍/개인프로젝트
cd ios && pod install
리액트 네이티브에서 서 Firebase 사용하기
1. https://firebase.google.com/ 이동 -> 우측 상단 '콘솔로 이동' 클릭
2. 프로젝트추가
3. 설치 https://rnfirebase.io/
npm install --save @react-native-firebase/app
4. 프로젝트 다 만들어지면 Project name작성
-> analytics 비활성화
-> platform 추가(Android & iOS)
4-1 Android 설정
https://rnfirebase.io/#2-android-setup
- package name에 ID 입력
(id는 내 앱/android/app/build.gradle 안에 defaultConfig 내부에 있음 "applicationId")
- 닉네임 작성
- Debug signing certificate SHA-1 입력
(앱에서 콘솔 열어주고 cd android && ./gradlew signingReport 입력 -> Task: app:signingReport내부에 SHA1부분 있음)
- Register App 누른 뒤 로딩 기다리면 설정 파일(google-services.json)을 다운로드할 수 있다
- 설정 파일을 앱의 android/app 내부에 넣어준다
- Next버튼 누르면 나오는 코드들을 정해진 위치에 추가해주면 됨
- 다 했으면 Next
4-2 iOS 설정:
https://rnfirebase.io/#3-ios-setup
- Firebase에서 Add app 클릭 -> iOS 클릭
- iOS Bundle ID 입력
(XCode를 열어서 general섹션에 bundle Identifier가 있음)
- 닉네임 설정
- 앱스토어 ID는 이미 앱스토어에 등록되어있는 경우에 작성 (나는 비워뒀음)
- Register app 클릭
- 설정 파일(GoogleService-Info.plist) 다운로드
- XCode에서 설정 파일을 프로젝트에 추가
(project 우클릭 -> Add File to 'project name' -> 설정파일 누르고 Copy items if needed항목 체크, create group 체크)
- Next버튼을 누른 뒤 코드들을 내 프로젝트의 적절한 위치에 추가하기
- 다했으면 터미널에 입력
cd ios && pod install
5. 인증을 위한 Firebae Authentication Module 설치
- Firebase의 콘솔에서 Authentication에 들어간 뒤 Get Started클릭, Email/Password 클릭해서 Enable 시켜준 뒤 Save
- 모듈설치
https://rnfirebase.io/auth/usage
npm install @react-native-firebase/auth
// ios는 cd ios && pod install도 해줘야함
- 리빌드, 시뮬레이터&에뮬레이터 재실행하고 작업 시작하기
- App.js에 다음을 작성
//App.js 인증을 위한 예시
import React, { useState, useEffect } from 'react';
import auth from '@react-native-firebase/auth';
export default function App() {
useEffect(()=>{
console.log(auth().currentUser);
},[])
return null;
}
// 콘솔에 null이 찍히면 정상
6. 이메일/비밀번호를 통한 인증 및 회원가입
import auth from '@react-native-firebase/auth';
- 로그인 확인 :
App.js에서는 auth를 확인해서 보여줄 화면을 선택할 수 있다
const[isLoggedIn, setIsLoggedIn] = useState(false);
// ...코드
auth().onAuthStateChanged((user)=>{
//user값에 따라 isLoggedIn state값을 변경시켜서 로그인스크린을 보여줄지 메뉴스크린을 보여줄지 정한다
if(user){
setIsLoggedIn(true)
}else{
setIsLoggedIn(false)
}
});
// ...코드
<NavigationContainer>
{isLoggedIn ? <1번컴포넌트 /> : <2번컴포넌트 />}
</NavigationContainer>
- 회원가입 :
useState를 통해 email, password값을 담고
catch문에서 유효성 체크를 할 수 있다
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
// 회원가입 함수
const signupEditing = async() => {
playSound(require("../asset/audio/btnClickSound.mp3"))
setLoading(true)
if(loading){
return;
}
try{
if(email !=="" && password !==""){
await auth().createUserWithEmailAndPassword(email, password)
}else{
setLoading(false)
setValidation('칸을 채워주세요')
}
}catch(e){
setLoading(false)
switch(e.code){
case "auth/email-already-in-use" : {
return setValidation('이미 사용중인 이메일입니다.')
}
case "auth/invalid-email" : {
return setValidation('이메일을 입력해주세요')
}
case "auth/weak-password" : {
return setValidation('안전하지 않은 비밀번호입니다.\n다른 비밀번호를 사용해 주세요.')
}
case "auth/operation-not-allowed" : {
return setValidation('operation-not-allowed \n관리자에게 문의하세요 ')
}
}
console.log("error1 = ", e.code)
}
}
// ...코드
return
<TextArea
placeholder="이메일"
value={email}
returnKeyType="next"
keyboardType = "email-address"
autoCapitalize="none"
autoCorrect={false}
onChangeText = {(text) => setEmail(text)}
onSubmitEditing = {onSubmitEmail}
/>
<TextArea
ref={PasswordInput}
placeholder="비밀번호"
value={password}
returnKeyType="done"
secureTextEntry
onChangeText = {(text) => setPassword(text)}
onSubmitEditing = {btnAlloter()}
/>
// ...코드
<Btn onPress = {signupEditing} style={{backgroundColor : navCheck == "Signup" ? colors.NAVY : "lightgray"}}>
{loading ? <ActivityIndicator color="white"/> : <BtnText>회원가입</BtnText>}
</Btn>
- 로그인
회원가입과 똑같은 TextArea를 사용하고 실행 함수만 바꿔준다
(auth().signInWithEmailAndPassword(email, password)를 통해 로그인)
// 로그인 함수
const loginEditing = async() => {
playSound(require("../asset/audio/btnClickSound.mp3"))
//ActivityIndicator컴포넌트 출력
setLoading(true)
// 두번눌리는걸 방지
if(loading){
return;
}
try{
if(email !=="" && password !==""){
// 입력값이 공백이 아니면 로그인
await auth().signInWithEmailAndPassword(email, password)
}else{
// 입력값이 공백이라면 메시지 출력
setLoading(false)
setValidation('칸을 채워주세요')
}
}catch(e){
// 에러 발생시 에러이유를 메시지로 출력
setLoading(false)
switch(e.code){
case "auth/invalid-email" : {
return setValidation("이메일을 입력해주세요")
}
case "auth/user-disabled" : {
return setValidation('user-disabled')
}
case "auth/user-not-found" : {
return setValidation('존재하지 않는 이메일 입니다')
}
case "auth/wrong-password" : {
return setValidation('비밀번호가 일치하지 않습니다')
}
case "auth/operation-not-allowed" : {
return setValidation('auth/operation-not-allowed \n관리자에게 문의하세요')
}
}
}
}
전체 코드
App.js
//App.js
import { NavigationContainer } from '@react-navigation/native';
import * as Font from "expo-font"
import AppLoading from 'expo-app-loading';
import React, { useState, useEffect } from 'react';
import {View, ActivityIndicator} from "react-native";
import InStack from './app/navigators/InStack';
import OutStack from './app/navigators/OutStack'
import { SafeAreaView } from 'react-native-safe-area-context';
import auth from '@react-native-firebase/auth';
import { NativeBaseProvider } from 'native-base';
import {SSRProvider} from '@react-aria/ssr';
export default function App() {
const [ready, setReady] = useState(false);
const onFinish = () => setReady(true);
const[isLoggedIn, setIsLoggedIn] = useState(false);
useEffect(()=>{
auth().onAuthStateChanged((user)=>{
// user를 받아서 user값이 참이면 로그인, false면 로그아웃 -> user값에 따라 isLoggedIn state값을 변경시켜서 로그인스크린을 보여줄지 메뉴스크린을 보여줄지 정한다
if(user){
setIsLoggedIn(true)
}else{
setIsLoggedIn(false)
}
})
},[])
const startLoading = async () =>{
// 로딩하고 싶은 것들을 담는 공간
// (ex. API호출 혹은 정보를 받거나 video요소를 미리 받아놓거나, DB를 미리 열거나, 아이콘을 미리준비)
await Font.loadAsync({
"SDChild": require("./app/asset/fonts/SDChildfundkorea.otf")
})
};
if(!ready){
return (
<AppLoading
startAsync={startLoading}
onFinish={onFinish}
onError={console.log} />
// ready가 안되어있으면 AppLoading은 splash screen을 비추도록 강제하고 startAsync를 호출,
// startAsync가 완료되면 AppLoading은 onFinish함수를 호출,
// onFinish는 state를 변경시키고 state가 변경되면 조건문 else에 해당하는 부분을 render한다
);
}
return (
<SSRProvider>
<NativeBaseProvider>
<NavigationContainer>
{ready && (
<SafeAreaView style={{flex:1}}>
{isLoggedIn ? <InStack />: <OutStack />}
</SafeAreaView>
)}
</NavigationContainer>
</NativeBaseProvider>
</SSRProvider>
)
}
Login.js
//Login.js
import React, {useState, useRef} from "react";
import {ActivityIndicator,Platform} from "react-native";
import styled from "styled-components/native";
import {colors} from "../component/Color"
import { Audio } from 'expo-av';
import auth from '@react-native-firebase/auth';
import AppleLogin from "../component/firebaseComponent/AppleLogin";
import GoogleLogin from "../component/firebaseComponent/GoogleLogin";
import Greeting from "../component/lottieComponent/Greeting";
import Welcome from "../component/lottieComponent/Welcome";
import GreetingNavy from '../component/lottieComponent/GreetingNavy';
const Container = styled.View`
justify-content: center;
align-items: center;
flex: 1;
`
const GreetingShell = styled.View`
width: 100%;
height: 25%;
`
const Contents = styled.View`
flex: 1;
width: 80%;
top: 10px;
border-radius: 15px;
`
const Nav = styled.View`
flex-direction: row;
justify-content: center;
`
const NavBtn = styled.TouchableOpacity`
width: 40%;
height: 40px;
justify-content: center;
/* border: 1px solid red; */
`
const NavBtnText = styled.Text`
text-align: center;
font-family: "SDChild";
font-size: 25px;
`
const Main = styled.ScrollView`
flex: 1;
top: 0px;
`
const Empty = styled.View`
width: 100%;
padding: 0px;
height: 30%;
/* border: 1px solid red; */
`
const TextArea = styled.TextInput`
width: 90%;
height: 40px;
margin: 10px 0px;
padding: 0px 10px;
border-radius: 15px;
border: 2px solid lightgray;
font-size: 23px;
font-family: "SDChild";
`
const Btn = styled.TouchableOpacity`
flex-direction: row;
width: 70%;
height: 45px;
margin: 10px 0px;
border-radius: 15px;
/* background-color: #EC705E; */
align-items: center;
justify-content: center;
`
const BtnText = styled.Text`
color: white;
font-size: 23px;
font-family: "SDChild";
`
const ValidationShell = styled.View`
width: 70%;
height: 18px;
align-items: center;
justify-content: center;
`
const ValidationText = styled.Text`
font-size: 18px;
font-family: "SDChild";
`
// ------------------------------------------------------------------
const Login = ({navigation}) => {
const PasswordInput = useRef()
const [navCheck, setNavCheck] = useState("Login")
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [loading, setLoading] = useState(false);
const [validation, setValidation] = useState("")
// 이메일입력 후 키보드에 next를 탭하면 password로 포커스를 이동
const onSubmitEmail = () => {
PasswordInput.current.focus();
}
// 로그인을 진행하는 함수
const loginEditing = async() => {
playSound(require("../asset/audio/btnClickSound.mp3"))
//ActivityIndicator컴포넌트 출력
setLoading(true)
// 두번눌리는걸 방지
if(loading){
return;
}
try{
if(email !=="" && password !==""){
// 입력값이 공백이 아니면 로그인
await auth().signInWithEmailAndPassword(email, password)
}else{
// 입력값이 공백이라면 유효성 체크 메시지 출력
setLoading(false)
setValidation('칸을 채워주세요')
}
}catch(e){
// 에러 발생시 에러이유를 유효성 체크 메시지로 출력
setLoading(false)
switch(e.code){
case "auth/invalid-email" : {
return setValidation("이메일을 입력해주세요")
}
case "auth/user-disabled" : {
return setValidation('user-disabled')
}
case "auth/user-not-found" : {
return setValidation('존재하지 않는 이메일 입니다')
}
case "auth/wrong-password" : {
return setValidation('비밀번호가 일치하지 않습니다')
}
case "auth/operation-not-allowed" : {
return setValidation('auth/operation-not-allowed \n관리자에게 문의하세요')
}
}
}
}
// 회원가입 버튼
const signupEditing = async() => {
playSound(require("../asset/audio/btnClickSound.mp3"))
setLoading(true)
if(loading){
return;
}
try{
if(email !=="" && password !==""){
await auth().createUserWithEmailAndPassword(email, password)
}else{
setLoading(false)
setValidation('칸을 채워주세요')
}
}catch(e){
setLoading(false)
switch(e.code){
case "auth/email-already-in-use" : {
return setValidation('이미 사용중인 이메일입니다.')
}
case "auth/invalid-email" : {
return setValidation('이메일을 입력해주세요')
}
case "auth/weak-password" : {
return setValidation('안전하지 않은 비밀번호입니다.\n다른 비밀번호를 사용해 주세요.')
}
case "auth/operation-not-allowed" : {
return setValidation('operation-not-allowed \n관리자에게 문의하세요 ')
}
}
console.log("error1 = ", e.code)
}
}
//Login인지 Signup인지 확인 후 버튼에 쓰이는 함수를 나눠줌
const btnAlloter = () => {
if(navCheck == "Login"){
return loginEditing
}else{
return signupEditing
}
}
// 오디오출력 관련 함수
function playSound(sound){
Audio.Sound.createAsync( sound,{ shouldPlay: true }
).then((res)=>{
res.sound.setOnPlaybackStatusUpdate((status)=>{
if(!status.didJustFinish) return;
res.sound.unloadAsync().catch(()=>{});
});
}).catch((error)=>{});
}
return(
<Container>
<GreetingShell style={{transform:[{scale:3}]}}>
{/* 로그인/회원가입 TextInput 상단 LottieAnimation */}
{navCheck == "Login" ? (<Greeting />):(<GreetingNavy />)}
</GreetingShell>
<Contents>
<Nav>
<NavBtn onPress={() => {setNavCheck("Login"), setValidation("")}}>
<NavBtnText style={{color : navCheck == "Login" ? "black" : "lightgray"}}>로그인</NavBtnText>
</NavBtn>
<NavBtn onPress={() => {setNavCheck("Signup"), setValidation("")}} >
<NavBtnText style={{color : navCheck == "Signup" ? "black" : "lightgray"}}>회원가입</NavBtnText>
</NavBtn>
</Nav>
<Main contentContainerStyle={{alignItems:"center"}}>
<TextArea
placeholder="이메일"
value={email}
returnKeyType="next"
keyboardType = "email-address"
autoCapitalize="none"
autoCorrect={false}
onChangeText = {(text) => setEmail(text)}
onSubmitEditing = {onSubmitEmail}
/>
<TextArea
ref={PasswordInput}
placeholder="비밀번호"
value={password}
returnKeyType="done"
secureTextEntry
onChangeText = {(text) => setPassword(text)}
onSubmitEditing = {btnAlloter()}
/>
<ValidationShell>
<ValidationText style={{color:colors.DARKGRAY}}>{validation}</ValidationText>
</ValidationShell>
{navCheck=="Login" ? (
// 로그인 관련 버튼
<>
<Btn onPress = {loginEditing} style={{backgroundColor : navCheck == "Login" ? "#EC705E" : "lightgray"}}>
{loading ? <ActivityIndicator color="white"/> : <BtnText>로그인</BtnText>}
</Btn>
<GoogleLogin />
{Platform.OS == "ios" && (
<AppleLogin />
)}
</>
):(
// 회원가입 관련 버튼
<Btn onPress = {signupEditing} style={{backgroundColor : navCheck == "Signup" ? colors.NAVY : "lightgray"}}>
{loading ? <ActivityIndicator color="white"/> : <BtnText>회원가입</BtnText>}
</Btn>
)}
</Main>
</Contents>
{navCheck == "Signup" ? (
<Empty style={{transform:[{scale:1}]}}>
<Welcome />
</Empty>
):(null)}
</Container>
)
}
export default Login;
'프로그래밍 > 개인프로젝트' 카테고리의 다른 글
탭탭카드놀이) 앱 아이콘 변경하기 (0) | 2022.05.14 |
---|---|
탭탭카드놀이) 안드로이드 상태바 가림 이슈 (0) | 2022.05.14 |
GitHub 웹 포트폴리오 -2 : HTML 템플릿 이용, 유튜브 영상 첨부, 이메일 보내기 구현 (0) | 2022.05.13 |
GitHub 웹 포트폴리오 제작 -1 : GitHub Pages 생성 (0) | 2022.05.13 |
탭탭카드놀이 Privacy Policy (0) | 2022.05.13 |