본문 바로가기

개발로그/리액트네이티브

리액트 네이티브에서 구글 맵 적용하기 Using a google maps API on the React Native, react-native-maps

 

리액트 네이티브 프로젝트를 진행하면서 맵뷰 Map View를 사용해야 할 일이 생겼습니다. 지도 API는 여러 가지가 있었는데 가장 최근까지 많은 커밋이 이루어진 지도 라이브러리를 사용하기로 했고, 찾아보니 react-native-community/react-native-maps가 최근까지 가장 활발하게 개발되고 있는 것 같아서 선택했습니다. 해당 라이브러리는 Google Maps SDK API를 이용해서 리액트 네이티브 안에서 맵뷰를 구현할 수 있는 라이브러리입니다. 아직 v0.27.1인걸 보니 리액트 네이티브 생태계가 아직까지 완전하게 성숙되진 않은 것 같네요.

 

 

※ 참고로 이 글을 작성하는 시점에 사용되는 라이브러리 버전은 다음과 같습니다.

 

- node: 12.16.3

- react: 16.13.1

- react-native: 0.63.2

- react-native-maps: 0.27.1

 

 

핵심 요약

 

이 글은 아래 3단계로 요약할 수 있습니다. 구글 맵을 리액트 네이티브 프로젝트에 띄우는 것 까지가 이 글의 목표입니다.

 

1. 구글 클라우드 플랫폼에서 API 키 등록 (iOS / Android)

2. 구글 클라우드 플랫폼에서 Maps SDK 사용 등록

3. 리액트 네이티브 프로젝트에 의존성 설치 및 설정

 

 

 

1. 구글 클라우드 플랫폼에서 API 키 등록 (iOS / Android)

 

구글 맵을 리액트 네이티브에 온전하게 띄우기 위해서는 우선 구글 개발자 콘솔에서 API 사용 등록이 필요합니다. 구글 클라우드 플랫폼으로 로그인 하시면 API 및 서비스 > 사용자 인증 정보 메뉴를 보실 수 있습니다. 해당 메뉴로 들어가시면, API 키를 생성하실 수 있는데요, 리액트 네이티브를 이용해서 보통 iOS, Android 모두에 대응하는 애플리케이션을 개발하기 때문에 API키 2개가 필요합니다.

 

 

 

상단에 사용자 인증 정보 만들기를 클릭해서 인증 정보를 만들어주시면 되는데요. API키를 눌러주시면 바로 키가 생성되는 것을 알 수 있습니다. 해당 배포 환경 (Live)에 있는 애플리케이션의 경우 해당 API키가 노출되지 않도록 주의하셔야 합니다.

 

 

우선 이 과정을 두 번 반복해서 API키를 두 개 생성하시면 됩니다. 그러면 API키 목록에 API 키가 생성되면서 주의사항 아이콘을 볼 수 있는데 이제 각 키별로 안드로이드에 사용할 것인지, iOS에 사용할 것인지 등 제한사항 설정을 해줘야 합니다. 해당 키를 클릭해서 상세 설정으로 들어가주세요.

 

 

 

1-1. Android 설정

 

API 키의 이름을 설정해주시고, 애플리케이션 제한사항에서 Android를 선택해주세요. 그리고 개발 중인 애플리케이션의 패키지 이름을 넣어줍니다. 개발 중이더라도 API를 이용하기 위해선 암호화된 인증서 디지털 지문이 필요한데요, 안드로이드 스튜디오를 이용해서 쉽게 확인 할 수 있습니다. 안드로이드 프로젝트는 디버그 모드로 처음 빌드할 때 인증서 디지털 지문 키가 생성됩니다. 이걸 확인 한 뒤에 붙여 넣으면 됩니다.

 

 

안드로이드 스튜디오에서 가장 우측에 Gradle 탭을 클릭하시면 프로젝트 하위에 signingReport라는 명령어 파일을 보실 수 있을 겁니다. 해당 파일을 더블 클릭해주시면 하단 터미널에 암호화된 인증서 디지털 지문이 생성됩니다. 이걸 복사해서 붙여주시면 됩니다.

 

 

만약 CLI 환경에서 확인하시고 싶으시다면 안드로이드 폴더로 이동해주신 후에 다음 명령어를 실행하시면 됩니다.

$ ./gradlew singingReport

 

이제 저장을 누르면 Maps SDK for Android를 위한 API 키 설정은 끝났습니다. API 제한 사항 중에 키 제한 부분은 일단 개발 중에는 신경쓰지 마시고, 나중에 배포 버전 API 키를 생성할 때 따로 설정해주시면 됩니다.

 

 

 

1-2. iOS 설정

 

iOS는 설정 방법이 더 간단합니다. 번들 ID만 입력해주시고, 저장하시면 됩니다.

 

 

 

 

2. 구글 클라우드 플랫폼에서 Maps SDK 사용 등록

 

iOS와 Android에서 사용할 API 인증 키도 발급 받았으니 이제 Maps SDK 사용 신청을 할 차례입니다. 제일 간단한 과정입니다. API Library로 이동하신 후에 Maps SDK for Android, Maps SDK for iOS를 사용 체크하시면 됩니다. 다른 API도 필요하다면 똑같은 과정으로 사용 설정을 하시면 됩니다. 앞서 API 인증키 설정할 때 API 제한 사항 중 제한 사항 없음을 체크했으므로 해당 API 인증키로 모든 API를 사용하실 수 있습니다.

 

 

 

3. 리액트 네이티브 프로젝트에 의존성 설치 및 설정

 

이제 모든 설정은 끝났으니 본격적으로 리액트 네이티브 프로젝트에 구글 맵을 사용해봅시다. 우선 react-native-maps 라이브러리를 설치해줍니다. 저는 Yarn을 이용했지만 Npm을 사용하셔도 무방합니다.

$ yarn add react-native-maps

 

React Native 0.60 이상부터는 autolinking이 지원되기 때문에 설정이 많이 복잡하지 않습니다. react-native-maps 라이브러리가 모두 설치되었다면, ios 디렉토리로 이동 후에 XCode 프로젝트를 위한 의존성을 설치해줍니다.

$ cd ios
$ pod install

먼저 Android 프로젝트에서 구글 맵을 이용하는 방법을 살펴보겠습니다.

 

 

3-1. 안드로이드 환경 설정

 

우선 app 디렉토리의 AndroidManifest.xml 파일을 수정해야 합니다. 먼저 아래 권한이 작성되어 있는지 확인합니다. 아래 코드가 작성되어 있다면 그냥 두시면 됩니다.

<uses-permission android:name="android.permission.INTERNET" />

그리고 application 하위에 다음 코드를 삽입해줍니다.

<meta-data
	android:name="com.google.android.geo.API_KEY"
	android:value="[API_KEY가 들어가는 부분]"/>

<!-- You will also only need to add this uses-libray tag -->
<uses-library android:name="org.apache.http.legacy" android:required="false"/>

API_KEY가 들어가는 부분에는 아까 구글 클라우드 플랫폼에서 설정한 API KEY를 넣어줍니다. 완성된 AndroidManifest.xml은 다음과 같습니다.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="com.example">

    <uses-permission android:name="android.permission.INTERNET" />

    <application
      android:name=".MainApplication"
      android:label="@string/app_name"
      android:icon="@mipmap/ic_launcher"
      android:roundIcon="@mipmap/ic_launcher_round"
      android:allowBackup="false"
      android:theme="@style/AppTheme">
      <meta-data
        android:name="com.google.android.geo.API_KEY"
        android:value="[API_KEY가 들어가는 부분]"/>

      <!-- You will also only need to add this uses-libray tag -->
      <uses-library android:name="org.apache.http.legacy" android:required="false"/>
      <activity
        android:name=".MainActivity"
        android:label="@string/app_name"
        android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
        android:launchMode="singleTask"
        android:windowSoftInputMode="adjustResize">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
      </activity>
      <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
    </application>
    
</manifest>

 

그리고 Gradle 빌드를 해주시면 끝입니다.

 

 

3-2. iOS 환경 설정

 

react-native-maps를 사용할 때 따로 설정을 해주지 않으면 iOS 앱은 기본적으로 apple 지도를 사용합니다. 기본 맵을 구글 맵으로 바꿔서 사용하기 위해서 몇 가지 설정이 필요합니다.

 

우선 AppDelegate.m 파일을 찾아서 몇 가지 코드를 추가하겠습니다. 상단 헤더 파일을 불러오는 부분에 GoogleMaps 헤더를 불러오는 코드를 넣어줍니다.

#import <GoogleMaps/GoogleMaps.h>

 

그리고 didFinishLaunchingWithOptions 함수에 최상단에  API 인증키와 함께 아래 코드를 넣어 줍니다.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  [GMSServices provideAPIKey:@"[API_KEY가 들어가는 부분]"];
  // ... 
}

 

완성된 코드는 아래와 같습니다.

#import "AppDelegate.h"

#import <React/RCTBridge.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>

#ifdef FB_SONARKIT_ENABLED
#import <FlipperKit/FlipperClient.h>
#import <FlipperKitLayoutPlugin/FlipperKitLayoutPlugin.h>
#import <FlipperKitUserDefaultsPlugin/FKUserDefaultsPlugin.h>
#import <FlipperKitNetworkPlugin/FlipperKitNetworkPlugin.h>
#import <SKIOSNetworkPlugin/SKIOSNetworkAdapter.h>
#import <FlipperKitReactPlugin/FlipperKitReactPlugin.h>
#import <GoogleMaps/GoogleMaps.h>

static void InitializeFlipper(UIApplication *application) {
  FlipperClient *client = [FlipperClient sharedClient];
  SKDescriptorMapper *layoutDescriptorMapper = [[SKDescriptorMapper alloc] initWithDefaults];
  [client addPlugin:[[FlipperKitLayoutPlugin alloc] initWithRootNode:application withDescriptorMapper:layoutDescriptorMapper]];
  [client addPlugin:[[FKUserDefaultsPlugin alloc] initWithSuiteName:nil]];
  [client addPlugin:[FlipperKitReactPlugin new]];
  [client addPlugin:[[FlipperKitNetworkPlugin alloc] initWithNetworkAdapter:[SKIOSNetworkAdapter new]]];
  [client start];
}
#endif

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  [GMSServices provideAPIKey:@"[API_KEY가 들어가는 부분]"];
#ifdef FB_SONARKIT_ENABLED
  InitializeFlipper(application);
#endif

  RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
  RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
                                                   moduleName:@"example"
                                            initialProperties:nil];

  rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];

  self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
  UIViewController *rootViewController = [UIViewController new];
  rootViewController.view = rootView;
  self.window.rootViewController = rootViewController;
  [self.window makeKeyAndVisible];
  return YES;
}

- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
#if DEBUG
  return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
#else
  return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif
}

@end

 

다음으로 앱의 Info.plist에 사용자의 위치를 공유한다는 Privacy 옵션을 넣어주어야 합니다.

일단 NSLocationWhenInUseUsageDescription 옵션만 있으면 되는데, 필요에 따라서 항상 공유할 것인지, 앱을 사용할 때만 공유할 것인지, 공유하지 않을 것인지를 사용자가 선택 할 수 있도록 해야 합니다. 즉 위치 서비스에 대한 사용자의 권한 허용이 있어야 합니다.

 

마지막으로 Podfile을 수정해서 GoogleMaps SDK 의존성을 명시해줘야 합니다. Podfile을 열어서 아래 코드를 추가해줍니다.

# React Native Maps dependencies
rn_maps_path = '../node_modules/react-native-maps'
pod 'react-native-google-maps', :path => rn_maps_path
pod 'GoogleMaps'
pod 'Google-Maps-iOS-Utils'

 

완성된 PodFile은 아마 아래 형태와 유사할 것입니다.

require_relative '../node_modules/react-native/scripts/react_native_pods'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
# React Native Maps dependencies
rn_maps_path = '../node_modules/react-native-maps'

platform :ios, '10.0'

target 'thumbup' do
  pod 'react-native-google-maps', :path => rn_maps_path
  pod 'GoogleMaps'
  pod 'Google-Maps-iOS-Utils'
  config = use_native_modules!

  use_react_native!(:path => config["reactNativePath"])

  target 'thumbupTests' do
    inherit! :complete
    # Pods for testing
  end

  # Enables Flipper.
  #
  # Note that if you have use_frameworks! enabled, Flipper will not work and
  # you should disable these next few lines.
  use_flipper!
  post_install do |installer|
    flipper_post_install(installer)
  end
end

target 'thumbup-tvOS' do
  # Pods for thumbup-tvOS

  target 'thumbup-tvOSTests' do
    inherit! :search_paths
    # Pods for testing
  end
end

 

 

4. MapView 컴포넌트 사용해보기

 

자, 이제 모든 설정이 끝났습니다. 처음 설정한다면 조금 복잡하게 느껴질 수도 있습니다. 이 글을 따라서 해보시고 잘 안되시는 분은 댓글로 문의 주시거나 work.hyunwoo@gmail.com으로 이메일 주시면 도와드리겠습니다.

 

이제 설정이 끝났으니 맵을 한 번 띄워봐야겠죠? 간단하게 MapView를 띄워보겠습니다. 주의 할 점은 iOS 앱에서는 MapView 컴포넌트에 provider={PROVIDER_GOOGLE} props가 전달되어야 애플 지도가 아닌 구글 지도가 나타난다는 것입니다. 만약 iOS에서 계속 애플 지도가 나온다면 이 부분을 한 번 확인해보세요.

import React from "react";
import { View, Text } from "react-native";
import MapView, { PROVIDER_GOOGLE } from "react-native-maps";

function App() {
  return (
    <>
      <View style={{ flex: 1 }}>
        <MapView
          style={{ flex: 1 }}
          provider={PROVIDER_GOOGLE}
          initialRegion={{
            latitude: 37.78825,
            longitude: -122.4324,
            latitudeDelta: 0.0922,
            longitudeDelta: 0.0421,
          }}
        />
      </View>
    </>
  );
}

export default App;

 

 

iOS와 Android 환경에서 구글 맵을 띄우는데 성공했습니다. 이제 여기에 버튼도 넣어보고 마커도 넣고 이런저런 장난을 쳐볼수 있겠죠? 일단 맵을 띄우는 것까지 성공했다면 귀찮은 부분은 다 끝났습니다. 축하드려요 :)

다음 포스팅: 리액트 네이티브에서 현재 위치 가져와서 구글맵에 그려주기


 

 

만약 이 포스팅이 조금이나마 도움이 되셨다면 커피 한 잔 사주시면 감사하겠습니다 ☺️

Buy me a coffee Buy me a coffee