[프로젝트] RN 테스트 프로젝트를 위한 사전 조사 : 웹 뷰, 소셜 로그인, 카카오 맵 api 사용

Jade·2023년 4월 8일
2

프로젝트

목록 보기
25/28

최근에 React Native를 이용한 어플리케이션 개발 팀 프로젝트를 사이드 프로젝트로 시작하게 되었다.
팀원 전부 웹이 아닌 네이티브 어플리케이션은 처음이라 시작 전에 Oauth, 지도 API 사용과 관련해서 테스트 프로젝트를 만들어보자는 의견에 동의해서 진행 예정인데, 관련된 내용을 좀 정리해서 팀원들과 공유하고 싶어서 써보는 글!



기본적인 기술스택

Front

  • React Native
  • expo

Back (백엔드 팀원이 만들어주신 구조도)



소셜 로그인

Expo AuthSession Module

expo에서 제공하는 AuthSession 모듈을 사용해 소셜 로그인을 구현할 수 있는데,
이 모듈은 각 소셜 로그인 서비스에서 제공하는 인증 플로우를 처리해주고, 인증 결과를 리턴한다.

설치

npx expo install expo-auth-session expo-random
  • expo-random은 peer dependency라 함께 설치해주어야 한다고 함.
    (expo-random은 강력한 무작위 bytes를 생성하는 네이티브 인터페이스를 제공하는데, 이를 사용하면 node.js의 core crypto.randomBytes 라는 API와 동등한 값을 생성할 수 있다고 한다. expo에서 보안에 민감한 작업들을 할 때(암호화나 키 생성) 사용하는 모듈인듯)

아래 코드는 chat gpt에서 제공한 구글 소셜 로그인 구현 예시이다.

처음에 챗GPT가 알려준 코드에 useRedirectUri라는 함수가 있었는데 해당 함수는 공식문서 + 구글링으로 아무리 찾아봐도 래퍼런스가 없더라 챗GPT가 뭔가 잘못 알려준 것 같아서 빼고 다시 코드 작성해달라고 함...

import * as React from 'react';
import { Button } from 'react-native';
//expo-web-browser는 말 그래도 시스템의 웹 브라우저에 접근하게 해주고, 리다이렉션을 핸들링하게 해주는 모듈 (당연히 설치 필요 npx expo install expo-web-browser)
import * as WebBrowser from 'expo-web-browser';
import { ResponseType, useAuthRequest } from 'expo-auth-session';
import { makeRedirectUri } from 'expo-auth-session';

//maybeCompleteAuthSession API 사용 
//: 웹 윈도우 팝업에서 인증 세션을 완료할 수 있는지 여부 확인하는 함수 
//이 매서드는 윈도우가 리다이렉션 된 페이지에서 호출되어야 함
//이 함수가 호출되지 않으면 팝업 창이 자동으로 닫히지 않는다.
//리턴값은 리다이렉션 실패나 성공에 대한 메시지를 포함한 객체
WebBrowser.maybeCompleteAuthSession();

// Google configuration (구글 인증 관련된 설정들)
//googleClientId는 Google Developer Console에서 생성가능 
const googleClientId = 'your-google-client-id.apps.googleusercontent.com';
//discovery 객체 속 엔드포인트 정보들은 위 ClientId 받을 때 자동으로 생성됨 
const discovery = {
  authorizationEndpoint: 'https://accounts.google.com/o/oauth2/v2/auth',
  tokenEndpoint: 'https://www.googleapis.com/oauth2/v4/token',
  revocationEndpoint: 'https://accounts.google.com/o/oauth2/revoke',
};


//구글 로그인 버튼 컴포넌트
export default function GoogleLoginButton() {
  
  //useAuthRequest API (expo authsession이 제공하는 훅)
  //인증 요청을 만들고 로드하는데 사용되며, 비동기 설정을 허용
  //expo AuthSession 모듈에 포함된 API로 첫번째 인자로 config, 두번째 인자로 discovery라는 인증을 위한 엔드포인트들을 받는다. 
  //**config 종류 =>  필수 : clientId, redirectUri / 나머지는 옵션 설정들임 
  //리턴값들 중 promptAsync 함수를 호출하면 인증 프로세스를 시작할 수 있고
  //response 값은 promptAsync 인증 프로세스가 호출되기 전까지 null이다.  
  const [request, response, promptAsync] = useAuthRequest(
    {
      responseType: ResponseType.Token,
      clientId: googleClientId,
      scopes: ['openid', 'profile'],
      redirectUri: makeRedirectUri({
        scheme: 'your-expo-app',
      }),
    },
    discovery
  );
  
  //makeRedirectUri는 현재 플랫폼이나 환경에 리다이렉션 url을 생성해준다.
  //옵션 객체를 인자로 전달할 수 있음.
  //옵션 객체 내의 scheme 속성에는 자신의 expo 앱의 url 스키마를 입력한다.
  

  React.useEffect(() => {
    if (response?.type === 'success') {
      const { access_token } = response.params;
    //로그인 요청에 대한 응답이 성공적으로 수신되는 경우 access_token을 받아올 수 있고
    //받아온 access token으로 google api를 호출하면 사용자 정보를 받아올 수 있을듯 
    }
  }, [response]);

  return (
    <Button
      disabled={!request}
      title="Google 로그인"
      onPress={() => {
        promptAsync();
      }}
    />
  );
}

백엔드와 구현 방식을 이야기했을 때 소셜 로그인 관련 처리를 클라에서 완료해서 사용자 정보를 받아오면 우리 서버쪽 DB에 사용자 정보를 최초 1회 저장하는 방식으로 구현하기로 했는데, 위와 같은 로직에서 사용자 데이터를 받아오는 로직만 추가하면 되지 않을까 한다 (일단 예상)


_____________________

카카오 맵 api 사용

카카오맵을 리액트 네이티브에서 사용할 때
다음과 같이 웹 뷰 형식으로 지도를 띄우는 방법을 생각하고 있다.

expo에서 카카오 맵을 사용 가능한지 찾아봤을 때 불가능할 거라는 식의 글들을 봐서... 첨부터 맘 편하게 웹 뷰 형식으로 띄우자고 이야기 함.

피그마 참고하면 아래와 같은 형태가 될 거고 아마 하단바도 웹 뷰라 없을 가능성이 높다.


WebView 띄우기

react-native-webview라는 패키지가 존재하는데 이 모듈은 네이티브 뷰 내부에서 웹을 렌더하는 WebView 컴포넌트를 제공한다. 설치는 아래 명령어로 할 수 있음.

npx expo install react-native-webview

공식 문서에서 제공하는 대표적인 사용 방법은 아래와 같다.

import React, { Component } from 'react';
import { WebView } from 'react-native-webview';

class MyInlineWeb extends Component {
  render() {
    return (
      <WebView
        originWhitelist={['*']}
        source={{ html: '<h1>This is a static HTML source!</h1>' }}
      />
    );
  }
}

WebView 컴포넌트에는 여러 props들이 존재한다

  • source : WebView에서 로드할 정적 HTML 또는 URI(선택적 헤더 포함) 지정 (정적 HTML 로드하기 위해서는 originWhitelist 값을 "*"로 설정해야 함)
  • injectedJavaScript: WebView가 로드된 후 실행할 JavaScript 코드를 지정
  • onMessage: 웹뷰에서 postMessage 매서드를 호출할 때마다 호출되는 함수를 지정
  • onLoad: 페이지 로드가 완료될 때 호출되는 함수를 지정
  • javaScriptEnabled: 웹뷰에서 자바스크립트 실행 여부를 지정.

공식 문서에 있는 injectedJavaScript 사용 예시
=> runFirst에 문자열로 저장되어 있는 자바스크립트 코드가 페이지가 로드되면 실행되면서 바디 스타일이 빨간색으로 변하고 2초 뒤 alert창이 띄워지는 것을 확인할 수 있다.

import React, { Component } from 'react';
import { View } from 'react-native';
import { WebView } from 'react-native-webview';

export default class App extends Component {
  render() {
    const runFirst = `
      document.body.style.backgroundColor = 'red';
      setTimeout(function() { window.alert('hi') }, 2000);
      true; // note: this is required, or you'll sometimes get silent failures
    `;
    return (
      <View style={{ flex: 1 }}>
        <WebView
          source={{
            uri: 'https://github.com/react-native-webview/react-native-webview',
          }}
          onMessage={(event) => {}}
          injectedJavaScript={runFirst}
        />
      </View>
    );
  }
}

비슷하지만 다른 injectJavaScript라는 '매서드'가 있는데 웹뷰 컴포넌트의 ref속성을 이용해 호출할 수 있다.

공식 문서를 보고 이해한 게 맞다면 injectedJavaScript prop은 웹뷰 컴포넌트가 로드된 후 한 번만 실행되는데, 매서드는 지정된 자바스크립트 코드를 즉시 실행시켜준다고 한다. 아래 링크로 연결해둔 스택 오버 플로에서 차이점을 이야기하고 있긴 한데 아직 와닿지는 않는다...
(stackOverFlow : injectedJavaScript & injectJavaScript )

import React, { Component } from 'react';
import { View } from 'react-native';
import { WebView } from 'react-native-webview';

export default class App extends Component {
  render() {
    const run = `
      document.body.style.backgroundColor = 'blue';
      true;
    `;

    setTimeout(() => {
      this.webref.injectJavaScript(run);
    }, 3000);

    return (
      <View style={{ flex: 1 }}>
        <WebView
          ref={(r) => (this.webref = r)}
          source={{
            uri: 'https://github.com/react-native-webview/react-native-webview',
          }}
        />
      </View>
    );
  }
}

아무튼 웹 뷰 컴포넌트를 사용해서 카카오 맵 api에서 제공하는 도메인을 웹뷰의 source로 전달해야 할 것 같다.

현재 위치 가져오기

현재 위치를 위도, 경도로 받아오는 방식은 노마드 코더 무료 강의에서도 배웠듯이 expo-location 패키지를 설치하고 위치 권한과 현재 위치를 받아와 저장할 수 있다.

  • requestForegroundPermissionAsync() : 권한 요청 매서드
  • getCurrentPositionAsync() : 현재 위치 받아오는 매서드 (accuracy 설정도 가능)
  • reverseGeocodeAsync() : 위 매서드로 받아온 위경도를 reverse해서 도시 등의 읽을 수 잇는 주소로 바꿔줌

공식문서 예제 코드

import React, { useState, useEffect } from 'react';
import { Platform, Text, View, StyleSheet } from 'react-native';

import * as Location from 'expo-location';

export default function App() {
  const [location, setLocation] = useState(null);
  const [errorMsg, setErrorMsg] = useState(null);

  useEffect(() => {
    (async () => {
      
      let { status } = await Location.requestForegroundPermissionsAsync();
      if (status !== 'granted') {
        setErrorMsg('Permission to access location was denied');
        return;
      }

      let location = await Location.getCurrentPositionAsync({});
      setLocation(location);
    })();
  }, []);

  let text = 'Waiting..';
  if (errorMsg) {
    text = errorMsg;
  } else if (location) {
    text = JSON.stringify(location);
  }

  return (
    <View style={styles.container}>
      <Text style={styles.paragraph}>{text}</Text>
    </View>
  );
}

const styles = StyleSheet.create({ ... }); 

근데 웹뷰와 카카오 맵 관련된 질의응답에 보면 안드로이드 geolocation으로 위치 가져오는 부분에 있어서 문제가 있다는 글만 있고 해결한 글들이 없어서...^^ 살짝 걱정된다.

카카오 맵 api

카카오맵공식 페이지에 들어가보면 지도 url 안내가 나와 있다.

지도 라이브러리들도 있는데, clusterer, services, drawing과 같이 마커들을 무리지어주거나, 장소 검색이나 주소-좌표 변환을 가능하게 하거나, 지도 위에 마커와 그래픽스 객체들을 쉽게 그릴 수 있는 모드를 지원한다고 한다.

아마 우리가 원하는 키워드로 장소를 검색하고 목록으로 표출하는 건 이 부분을 따라 작성하면 될 것 같다.

목록을 찾는 것부터 마커를 생성하는 것까지 포함된 코드인듯... 다만... 키워드 검색과 함께 필요한 게 사용자 위치 정보를 기점으로 검색하는 것이라 두 가지를 합칠 수 있을지가 고민이었는데

또 찾다보니 search 함수에서 사용할 수 있는 옵션 파라미터에 location이라는 옵션이 있다는 것을 발견했다. 위 이미지에서는 카테고리 검색 옵션이지만, 우리가 사용하게 될 키워드 검색 함수에서도 옵션으로 location이 있는 것을 확인했다. (다만 카테고리 검색은 해당 옵션이 필수 옵션인데, 키워드는 필수가 아니므로 빠트리지 않고 지정할 수 있도록 해야할듯)


이제 남은 건 위 내용들을 조합해서 실제로 프로젝트를 생성해보는 것...
갠적으론 지도 api 연결이 꽤 걱정이 되는데...
일단 웹 뷰를 띄운 상태에서 조작해야 하는 부분도 많아 보여서...막연하게 웹 뷰에서 사용하는 자바스크립트 코드라면 injectJavaScript를 사용하면 되지 않을까 생각은 하는데, 실제로 조작해봐야 알 것 같다.
가보자고?

profile
키보드로 그려내는 일

0개의 댓글