1. React Native 개발환경 준비하기

https://docs.expo.dev/get-started/installation/

이번 가이드에서는 expo를 이용하여 React Native 개발을 진행하겠습니다.

위 expo 공식 문서에 따라 React Native 개발 환경설정을 진행해주세요. 이미 React Native 개발환경이 설정되신 분은 넘어가셔도 좋습니다.

Git 저장소 다운로드

Sample 프로젝트를 다운받아 사용하고 싶으신 분은 다음 명령어를 통해 git 저장소를 다운로드 받으세요.

Furo Expo Sample 프로젝트를 다운로드 받습니다.

git clone https://github.com/lukasjhan/furo-sample-expo

직접 프로젝트를 만들고 싶으신 분은 다음 가이드를 따라 진행해주세요.

라이브러리 설치 및 사용법

이번 가이드에서 다음의 라이브러리를 추가적으로 사용합니다.

npm i @react-navigation/native @react-navigation/native-stack
npm i axios
// package.json
"dependencies": {
    "@react-navigation/native": "^6.1.7",
    "@react-navigation/native-stack": "^6.9.13",
    "axios": "^1.4.0",
    //...
}
  • @react-navigation/native, @react-navigation/native-stack

    로그인 이후 deeplink를 위한 라이브러리 입니다.

  • axios

    Furo의 authenticate API를 사용하기 위한 라이브러리 입니다.

//App.js

import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';

export default function App() {
  const linking = {
    prefixes: ['exp://'],
    config: {
      screens: {
        Home: '*',
      },
    },
  };
  const Stack = createNativeStackNavigator();

  return (
    <NavigationContainer linking={linking}>
      <Stack.Navigator>
        <Stack.Screen name="Home" component={HomeScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}
  • 추후에 deeplink의 params를 가져오기 위하여 App.js에서 linking config를 추가하고 최상위 컴포넌트에 NavigationContainer와 Stack를 추가합니다.

2. Furo 로그인 연동하기

  1. 콘솔에서 복사한 값을 .env 파일에 옮깁니다. 또는 .env파일을 생성한 후 아래와 같이 환경변수를 설정합니다. 만약.env 파일을 사용할 수 없다면 App.js 파일의 clientId에 콘솔에서 가져온 Client ID를 넣습니다.
EXPO_PUBLIC_CLIENT_ID="{{YOUR_CLIENT_ID}}"
  1. 콘솔 입력창의 Default Callback URI에 기본값 https://sample.furo.one/{{YOUR_CLIENT_ID}}http://localhost:3000/{{YOUR_CLIENT_ID}} 로 변경합니다.

3. Sample code

import * as React from 'react';
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View, Button, Linking } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import axios from 'axios';

const CLIENT_ID = ''; // Insert your furo project's client id

export default function App() {
  const linking = {
    prefixes: ['exp://'],
    config: {
      screens: {
        Home: '*',
      },
    },
  };
  const Stack = createNativeStackNavigator();

  return (
    <NavigationContainer linking={linking}>
      <Stack.Navigator>
        <Stack.Screen name="Home" component={HomeScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

function HomeScreen({ route }) {
  const [data, setData] = React.useState();

  React.useEffect(() => {
    Linking.addEventListener('url', ({ url }) => {
      const query = url.split('?');
      if (query.length < 2) return;
      const [, code] = query[1].split('=');
      if (code) {
        (async () => {
          try {
            const response = await authenticateWithCode(code);
            const { access_token } = response;
            setData(access_token);
          } catch (e) {
            console.log('error: ', e.response.data);
          }
        })();
      }
    });
  }, []);
  const loginUrl = `https://auth.furo.one/login/${CLIENT_ID}`;

  const loginWithRedirect = async () => {
    Linking.openURL(loginUrl);
  };

  const authenticateWithCode = async (code) => {
    const { data } = await axios.post(
      'https://api.furo.one/sessions/code/authenticate',
      { code },
      { headers: { origin: 'exp://' } }
    );
    return data;
  };

  return (
    <View style={styles.container}>
      <Text style={{ fontSize: 16, fontWeight: '600' }}>
        [Furo] React Native Tutorial
      </Text>
      <View style={{ marginTop: 10, width: '80%' }}>
        <Text>{data}</Text>
      </View>
      <StatusBar style="auto" />
      {!data ? (
        <Button title={'Sign In'} onPress={loginWithRedirect} />
      ) : (
        <Button title={'Clear'} onPress={() => setData()} />
      )}
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});