들어가기 전
Native로 안드로이드 어플을 개발하는 경우도 있지만, 웹을 만들어 안드로이드 앱 내에 웹뷰로 띄워주는 경우도 있습니다. 저는 이번에 웹뷰 테스트를 위해 React 웹에 Google Map API를 이용해 지도를 띄워야 했습니다. 이 과정에서 배운 Google Map API를 사용하는 방법과 외부 API를 사용할 때 중요한 API 키를 숨기는 방법을 작성하고자 합니다.
Google Map API 사용하기
구글 API를 사용하기 위해서는 Google Cloud Platform에 Project를 생성해야 합니다.
여기서 가장 중요한 것은 구글 API Key
를 발급 받는 것입니다.
위 사진과 같이 첨부된 구글 가이드를 통해서 프로젝트를 생성합니다.
API 활성화를 통해 API 키를 발급 받습니다.
Maps JavaScript API 를 설정한 후, API 사용 설정됨
이 뜨도록 합니다.
자세한 가이드는 위 구글 가이드 링크를 참고하시길 바랍니다.
React 코드 작성
npm install 하기
npm install @react-google-maps/api
구글 map api를 사용하기 위해서 터미널에 npm install
을 하였습니다.
페이지 작성
단순 구글 Map API 테스트를 위한 페이지이므로 구글 Map을 띄우는 화면만 작성하였습니다.
import React from 'react';
import { GoogleMap, LoadScript, Marker } from '@react-google-maps/api';
const containerStyle = {
width: '100%',
height: '400px'
};
const center = {
lat: // 원하는 위도
lng: // 원하는 경도
};
const apiKey = process.env.REACT_APP_GOOGLE_MAPS_API_KEY // api Key 가져오기
console.log("api key ", apiKey )
function GoogleMapComponent() {
return (
<LoadScript googleMapsApiKey={apiKey}>
<GoogleMap
mapContainerStyle={containerStyle}
center={center} // 지도에서 제일 처음 나타날 위치
zoom={19} // 초기 줌 레벨 설정
>
<Marker position={center} />
</GoogleMap>
</LoadScript>
);
}
export default React.memo(GoogleMapComponent);
구글 Map을 불러오기 위해서 앞서 발급 받은 apiKey를 apiKey 변수에 넣고 할당 해줍니다.
이 때 apiKey는 중요한 정보이므로 .env
파일을 통해서 가릴 수 있습니다.
containerStyle =
function GoogleMapComponent
를 통해서 google map이 그려집니다.
이 때 mapContainerStyle
에 const = containerStyle
(세로 400px, 가로 100%) 를 지정하여 map의 크기를 조정하였습니다.
트러블 슈팅 1 : React Routing 연결
기존에 src 폴더에 있던 모든 페이지.js 파일들을 page 폴더 아래에 위치하도록 옮겼습니다.
경로를 옮기면서 Main에 버튼을 클릭 시 해당 페이지들로 이동하도록 Router를 설정한 부분들이 모두 에러가 발생하였습니다.
import Main from './Main';
**import NoticeList from './page/NoticeList';
import ImageSwiper from './page/ImageSwiper';
import GoogleMap from './page/GoogleMap';**
function App() {
return (
<Router>
<Routes>
<Route path="/" element={<Main/>} />
**<Route path="/page/notice-list" element={<NoticeList/>} />
<Route path="/page/image-swiper" element={<ImageSwiper/>} />
<Route path="/page/google-map" element={<GoogleMap/>} />**
</Routes>
</Router>
);
}
export default App;
/notice-list , /image-swiper
와 같은 path를 /page/notice-list, /page/image-swiper
등 page 아래 path로 수정하여 오류를 해결하였습니다.
React의 Router
안드로이드만 계속 공부해왔기 때문에 React에 대해서는 잘 몰랐습니다.
하지만 이 부분이 마치 Android Compose의 Navigation과 비슷하다는 생각이 들었습니다.
따라서 React의 Router가 무엇인지 살펴보고 싶었습니다.
Router
“사용자가 입력한 주소를 감지하고 입력받은 주소에 따라 다른 페이지를 띄워주는 역할”
React는 SPA(Single Page Application)으로 하나의 페이지를 지원하는 Application입니다.
따라서 Router를 활용하면 각 페이지마다 SPA를 유지하면서 필요한 최소 데이터만 렌더링 할 수 있습니다.
코드 구조
사용 예시는 Main에서 버튼 클릭 시 Notice, ImageSwiper,GoogleMap으로 각각 이동 하는 웹입니다.
import React from 'react';
**import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';**
import Main from './Main';
import NoticeList from './page/NoticeList';
import ImageSwiper from './page/ImageSwiper';
import GoogleMap from './page/GoogleMap';
React와 Main, NoticeList, ImageSwiper, GoogleMap component 를 각각 import 해줍니다.
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
react-router-dom 패키지로부터 3가지 중요 컴포넌트들을 import 합니다.
function App() {
return (
<Router>
<Routes>
<Route path="/" element={<Main/>} />
<Route path="/page/notice-list" element={<NoticeList/>} />
<Route path="/page/image-swiper" element={<ImageSwiper/>} />
<Route path="/page/google-map" element={<GoogleMap/>} />
</Routes>
</Router>
);
}
그리고 Routes
안에 Route를
각각 넣어줍니다.
Main의 코드는 다음과 같습니다.
**import React from 'react';
import { useNavigate } from 'react-router-dom';**
function Main() {
**const navigate = useNavigate();**
return (
<div style={{ padding: '20px', textAlign: 'center' }}>
<h1>메인 화면</h1>
**<button onClick={() => navigate('/page/notice-list')} style={buttonStyle}>
공지사항 리스트 보기
</button>
<button onClick={() => navigate('/page/image-swiper')} style={buttonStyle}>
이미지 스와이프 보기
</button>
<button onClick={() => navigate('/page/google-map')} style={buttonStyle}>
구글맵 보기
</button>**
</div>
);
}
navigate
를 통해서 button onClick()
시에 이동 할 path를 설정해주면 됩니다.
트러블 슈팅 2 : API Key 숨기기
외부 API를 사용할 때 API Key는 잘 관리해야 합니다. Key가 노출될 경우 무단 엑세스의 위험이 있기 떄문입니다. 따라서 이번에도 API Key를 숨기려고 .env 파일을 활용하였으나 .. API Key를 인식하지 못 해 구글 Map이 로딩되지 않는 문제가 발생하였습니다.
import React from 'react';
import { GoogleMap, LoadScript, Marker } from '@react-google-maps/api';
// 중략
**const apiKey = process.env.REACT_APP_GOOGLE_MAPS_API_KEY**
console.log("api key ", apiKey )
function GoogleMapComponent() {
return (
<LoadScript googleMapsApiKey={apiKey}>
<GoogleMap
// 중략 ,,.
>
{/* 마커 추가 */}
<Marker position={center} />
</GoogleMap>
</LoadScript>
);
}
export default React.memo(GoogleMapComponent)
처음에 이렇게 코드를 작성하였습니다.
웹을 실행한 결과 아래 사진과 같이 google 지도를 제대로 로드할 수 없다는 문구가 나왔습니다.
Console을 확인해보니 API error : ApiProjectMapError
가 나타났습니다.
ApiProjectMapError
구글 문서를 살펴보니 해당 에러는 API Key가 제대로 인식되지 않는 문제였습니다.
따라서 .env 파일 내에 선언한 API Key 값이 제대로 인식되지 않음을 알게되었습니다.
콘솔 로그를 찍어봐도 빈 값이 나왔습니다 .
.env 환경변수 파일
값 자체에는 문제가 없는 것이라는 판단이 들어 .env 파일을 살펴보았습니다.
React에서는 환경변수를 설정할 때 .env 파일을 가지고 process.env로 가져옵니다.
접두어는 반드시 REACT_APP
파일 내에 환경변수 설정 시 변수명의 접두어는 반드시 REACT_APP_
이여야 합니다.
.env
REACT_APP_GOOGLE_MAP_API_KEY = 블라블라..
변수를 작성할 때도 끝에 ;를 붙이지 않고, “”로 값을 감싸지도 않습니다.
.env 파일을 변경한 후에는 반드시 재시작
.env 파일을 변경한 후에는 프론트 서버를 재시작 해야 합니다.
따라서 변수명을 바꾸거나 파일의 위치를 바꾸는 등의 변화가 있는 경우 재시작을 하였습니다.
⭐!!! .env 파일의 위치는 루트 경로에 있어야 한다.
사실 이 부분이 제 트러블슈팅의 원인이였습니다.
이전에 작성한 프로젝트를 github로 가져오면서 gitignore에 의해 .env 파일은 같이 오지 않았습니다.
따라서 .env 파일을 src 아래에 생성하고 만들었습니다.
하지만 .env
파일의 위치는 항상 루트 경로에 있어야 합니다.
이렇게 파일 위치를 변경하고 재시작을 해보니 ..
이렇게 google map이 잘 뜨는 것을 볼 수 있습니다.
API Key 관련 오류
key 관련 오류가 발생하면 Console을 통해서 어떤 에러 태그인지 확인하여 빠르게 해결하길 바랍니다.