프로젝트에서 보기 →

플러터 모바일 앱개발 | 모바일 앱 개발자를 위한 Flutter(플러터) 제대로 배우기 Part.4 중급3 구글 맵과 장소기록, 도서API 이용앱 | 취업·실무·창업 | 에어클래스

태그
기타 에어클래스
시작일
종료일
수정일

https://www.youtube.com/watch?v=3yXT-jNL8jA

description: |

1. 이건 꼭 알아야 한다^1

[? 질문] Flutter 앱에서 구글 맵을 “그냥 위젯 하나 띄우는 수준”이 아니라, 실제 서비스처럼 안정적으로 붙이려면 무엇을 먼저/반드시 해야 하는가^2
[= 답] Google Cloud Console에서 프로젝트 생성 → Maps SDK(플랫폼별) 사용 설정 → API 키 생성/복사 → Android/iOS 각 OS별 설정 파일에 키를 정확히 주입 → Flutter 코드에서 GoogleMap 위젯과 initialCameraPosition(카메라/뷰포트)를 제공하는 순서로 진행해야 한다.[^3]

[? 질문] 이 강의에서 만들려는 앱의 “기능 목표(요구사항)”는 무엇인가[^4]
[= 답] 사용자가 길을 가다 “기억해두고 싶은 장소”를 발견했을 때, 위도/경도 + 사진 + 제목/설명을 저장하고, 이를 CRUD(생성/조회/수정/삭제) 하며, 저장된 위경도로 지도(구글맵)에서 위치를 다시 보여주는 “장소 기록 앱”을 만든다.[^5]

[? 질문] 구글 맵은 유료라는데, 학습/초기 개발 단계에서 왜 ‘크게 걱정하지 말라’고 하는가[^6]
[= 답] 구글 맵은 할당량(쿼터) 기반 과금이지만, 일정 수준까지는 무료 구간이 충분히 크고, 만약 일일 접속이 “몇십만” 단위를 넘어 유료로 전환될 정도라면 이미 서비스가 성장해 비용을 감당할 상황일 가능성이 높다고 설명한다.[^7]

2. 큰 그림[^8]

이 콘텐츠는 Flutter 중급 단계에서 Google Maps 연동을 실제 앱 프로젝트에 통합하는 과정을 다룬다.[^9] 단순히 패키지 추가로 끝나지 않고, Google Cloud Console 설정, API 키 발급, Android/iOS 플랫폼별 환경설정 파일 수정, 그리고 Flutter 코드에서 지도를 띄우기 위한 카메라(뷰포트) 설정까지 “실무에서 막히는 지점”을 순서대로 밟는다.[^10] 또한 앞서 배운 SQLite(sqflite)카메라 연동까지 결합해 “장소 기록 + 지도 표시” 앱으로 확장하려는 맥락을 제시한다.[^11]

  • 플랫폼별 설정의 현실: Google Maps는 설정이 자주 바뀌고(Android/iOS도 다름), 책만 보고 따라 하기 어려운 “고개”가 많다고 강조한다.[^12]
  • API 키/콘솔 세팅이 핵심 병목: 코드보다 콘솔에서 프로젝트/SDK 사용 설정/키 발급/키 제한이 먼저이며, 여기서 실수하면 지도가 안 뜨는 문제가 생긴다.[^13]
  • 지도 표시의 최소 요건: Flutter에서 GoogleMap을 띄우려면 initialCameraPosition 이 필수이며, 이는 “어디를 어떤 확대 수준으로 볼지(위도/경도+줌)”를 의미한다.[^14]

3. 하나씩 살펴보기[^15]

3.1 오늘 프로젝트가 다루는 것: 지도 연동의 필요, 무료/유료, 그리고 ‘변하는 설정’[^16]

📸 1:49

강의는 “이번 프로젝트는 무엇을 하느냐”로 시작하며, 지도 연동(구글 맵 중심) 을 Flutter 앱에 붙여보겠다고 선언한다.[^17] 지도 연동은 현실적으로 네이버/다음/구글 등 다양한 선택지가 있는데, 간단한 수준이라면 네이버/다음도 가능하다고 말한다.[^18] 다만 “아주 대용량” 혹은 접속량이 큰 상황에서는 서비스마다 정책 차이가 있는데, 특히 구글 맵은 기본적으로 유료(과금 모델) 이라고 짚는다.[^19]

여기서 “유료면 부담 아닌가?”라는 학습자의 불안을 예상하고 다음 논리를 제시한다.[^20]

  • 구글은 유료이지만, 무료로 쓸 수 있는 범위가 매우 크다.[^21]
  • 일정 수준을 넘어서야 유료화되며, 그 수준이 “몇십만” 단위라면, 그쯤 되면 이미 서비스가 성공해 비용을 감당할 가능성이 높다는 식으로 설명한다.[^22]
  • 따라서 학습/프로토타이핑 단계에서는 “크게 걱정하지 말라”는 결론으로 정리한다.[^23]

또한 중요한 배경 설명으로, 구글 맵 연동은 계속 바뀌는 영역이라고 강조한다.[^24] 구글 측 콘솔/설정 화면이 바뀌어 책의 절차가 금방 낡고, 설정을 건드려야 하는 지점이 여러 군데라 “혼자 책 보고 하면 시행착오가 많다”고 말한다.[^25] 이 말은 곧, 강의에서 “실제로 어디를 눌러야 하는지”를 보여주며 따라가게 하겠다는 학습 설계로 이어진다.[^26]

[!IMPORTANT] 설정이 ‘자주 바뀌는’ 영역이라는 경고
구글 맵은 콘솔 UI와 설정 방식이 변동되어, 정적인 문서/책만으로는 그대로 재현이 어려울 수 있으니 “어디를 눌러야 하는지” 흐름을 이해하고 따라가라고 한다.[^24]

3.2 앱 요구사항 정의: 장소 기록(위도/경도+사진+텍스트)과 CRUD, 그리고 지도 표시[^27]

📸 3:35

강의는 “단순히 지도만 띄우고 끝내지 않겠다”는 방향을 잡는다.[^28] 바로 이전 프로젝트에서 배운 SQLite(sqflite) 를 그대로 활용해, 실제로 쓸 만한 응용 앱을 만들겠다고 한다.[^29]

여기서 앱의 원래 목적(시나리오)을 다음처럼 제시한다.[^30]

  • 사용자가 길을 가다가 “좋은 장소”를 발견했을 때 “메모해 두고 싶다”.[^31]
  • 그 장소 기록에는 최소한 다음 정보가 필요하다:
    • 위도(latitude)와 경도(longitude)[^32]
    • 사진(카메라로 촬영/연동)[^33]
    • 간단한 제목 또는 설명 텍스트[^34]
  • 이 데이터를 대상으로 CRUD(Create/Read/Update/Delete) 기능을 구현한다.[^35]
  • 그리고 저장된 위도/경도를 사용해 나중에 지도와 연동하여 위치를 보여준다.[^36]
  • 지도는 구글 지도를 쓸 것이며, 이를 위해 반드시 API 키가 필요하다고 못 박는다.[^37]

이 구성이 의미하는 바는, 단순 UI 데모가 아니라:

  1. 모바일 기기 기능(지도/카메라)
  2. 로컬 DB(SQLite)
    를 합쳐 “현업형 미니 프로젝트”로 만드는 흐름이다.[^38]

3.3 Google Cloud Console vs Firebase 구분, 그리고 ‘키(Access key) 필요’의 맥락[^39]

📸 4:17

구글 맵은 구글이 제공하는 서비스이므로 무한정 사용이 아니라 할당량(Quota) 기반으로 무료/유료가 갈린다고 다시 설명한다.[^40] 그리고 영화 API 때처럼, 구글 맵도 사용하려면 승인 키(Access key / API key) 를 발급받아 그 키로 앱을 개발해야 한다고 말한다.[^41]

이어서 학습자가 흔히 헷갈릴 수 있는 지점을 짚는다.[^42]

  • “구글 클라우드”는 Firebase가 아니다.[^43]
  • Firebase는 별도 법인/서비스로 분리되어 있고, 지금 다루는 맵 키 발급은 Google Cloud Console(콘솔 클라우드 구글 닷컴) 쪽에서 진행한다.[^44]

이 구분은 이후 단계(콘솔에서 프로젝트 만들고 API 활성화)를 정확히 따라가기 위한 전제다.[^45]

3.4 Flutter 프로젝트 생성 및 패키지 설치: google_maps_flutter 추가[^46]

📸 7:39

강의는 Flutter 프로젝트를 하나 만들고 실행해본 다음, 외부 라이브러리를 먼저 장착하겠다고 한다.[^47] 패키지 추가는 늘 하던 방식대로 pub.dev에서 google_maps_flutter를 찾아 설치(버전 문자열 복사)하고, pubspec.yaml의 dependencies에 추가하는 흐름이다.[^48]

진행 포인트는 다음과 같다.[^49]

  • pub.dev에서 google_maps_flutter를 검색한다.[^50]
  • 설치 화면의 버전 표기를 복사해서 pubspec.yaml에 붙여 넣는다.[^51]
  • 의존성 추가 후(예: “get dependencies”) 라이브러리 장착을 확인한다.[^52]
  • 강의자는 스펠링/자동 import가 꼬일 수 있으니, import 구문도 미리 복사해둘 수 있다고 팁을 준다(필요할 때 붙여넣기).[^^53]

[!TIP] import/문자열을 미리 복사해두는 습관
자동 import가 안 되거나 철자 실수로 시간을 쓰는 경우가 있으니, 패키지명/주요 구문을 메모해두면 효율적이라고 말한다.[^53]

3.5 Google Cloud Console에서 프로젝트 만들기 → Maps SDK 활성화[^54]

📸 7:33

패키지를 추가했으면 이제 “가장 중요한” API 키 발급 단계로 넘어간다.[^55] 강의자는 구글 쪽(google … 콘솔)으로 들어가 “개발자 콘솔”에서 작업한다고 안내한다.[^56]

콘솔에서의 흐름은 다음처럼 설명된다.[^57]

  1. 로그인을 먼저 한다.[^58]
  2. 상단의 프로젝트 영역에서 새 프로젝트를 만든다.[^59]
    • 프로젝트 이름은 임의로 지정 가능(예: “맵테스트”).[^60]
    • “만들기”를 누르면 프로젝트가 생성된다.[^61]
  3. 생성된 프로젝트에서 API 및 서비스로 들어간다.[^62]
  4. 라이브러리로 들어가면 구글이 제공하는 여러 서비스 목록이 보인다.[^63]
    • 이 서비스들은 사용량에 따라 과금될 수 있으며, 보통 결제정보/인증을 나중에 붙이지만 처음 시작 시엔 없어도 된다고 언급한다.[^64]
  5. 검색창에 map(맵)을 검색한다.[^65]
  6. 여기서 중요한 것이 Maps SDK for Android, 그리고 iOS도 аналог하게 활성화해야 한다는 점이다.[^66]
    • 강의자는 “이것(안드로이드)과 이것을 쓸 겁니다”라고 하며 Android용 SDK를 눌러 사용(Enable) 을 활성화하면, 시간이 지난 뒤 “관리(Manage)”로 바뀌고 “API 사용 설정됨” 상태가 된다고 설명한다.[^67]

이 단계는 “키 발급” 전의 선행 조건으로 제시된다.[^68]

3.6 API 키 생성/복사, 키 제한(앱 제한/API 제한) 이해, 키 재생성 주의사항[^69]

📸 15:50

SDK를 활성화한 뒤, 키 및 사용자 인증 정보(credential) 메뉴로 이동해 API 키를 만든다.[^70] 강의자는 이미 키를 만들어 둔 상태라 화면이 다를 수 있지만, 처음 하는 사람은 “키 생성”이 보일 것이며 이를 눌러 키를 하나 만들면 된다고 안내한다.[^71]

생성한 뒤에는 다음을 강조한다.[^72]

  • 키를 반드시 복사해두라.[^73]
  • 나중에 지도 요청/표시 때마다 이 키를 사용하게 되고, 사용량 과금도 이 키를 기준으로 집계된다고 설명한다.[^74]

이어서 “키 제한(Restriction)” 옵션을 설명한다.[^75]

  • 애플리케이션 제한 설정:
    • 웹사이트, 특정 IP, Android 앱, iOS 앱 등 “어디에서 키를 쓸지”를 제한할 수 있다.[^76]
    • “없음”으로 하면 제한 없이 다 쓸 수 있다는 의미다.[^77]
    • 강의자는 보통 단일 Android 앱 수준이라면 “없음”으로 둬도 된다고 말한다.[^78]
  • API 제한 사항:
    • 특정 API에서만 키를 쓰게 제한하는 옵션(Select API)임을 언급한다.[^79]
    • 이번 실습에서는 “딱히 제한 없이” 공통으로 쓰겠다는 뉘앙스로 설명한다.[^80]
  • 키 재생성:
    • 키를 새로 만들면 새 키는 즉시 사용 가능하지만, 기존 키는 24시간 이내에 영구적으로 비활성화된다고 설명한다.[^81]
    • 즉, 잠깐 동안 키가 두 개가 공존하는 상황이 발생한다.[^82]
  • 강의자의 강의용 키는 강의 후 초기화할 예정이라, 시청자가 그대로 쓰기는 어렵다는 점도 말한다.[^83]

또한 키를 코드/소스 어딘가에 임시로 붙여넣어둘 수는 있지만, “나중에 지워야 한다”는 주의도 준다.[^84]

[!WARNING] 키 유출/하드코딩 주의(강의자의 경고 맥락)
키를 일단 복사해 소스 어딘가에 담아두되, “임시”이며 나중에 지우라고 말한다. 강의자는 자신의 강의용 키는 강의 후 초기화한다고도 언급한다.[^83]

3.7 “지도 안 뜰 때” 체크포인트: 콘솔에서 Enable/Disable 상태 확인[^85]

📸 21:22

강의자는 설정 화면이 바뀌며, 나중에 “별 실수한 것 같지 않은데 지도가 안 나오는” 상황이 생길 수 있다고 한다.[^86] 그때 확인할 포인트로, 라이브러리에서 해당 SDK가 Enable(사용 설정) 되어 있는지 확인하라고 안내한다.[^87]

  • 화면에 “Enable/Disable” 표시가 있을 수 있는데, Enable이 보이면 현재 Disable 상태이므로 Enable을 눌러야 한다는 식으로 설명한다.[^88]
  • Android 쪽 Maps SDK 설정 화면에서 그런 토글을 확인하라고 말한다.[^89]

이 부분은 “콘솔 설정이 바뀌어도 본질은 ‘활성화 여부’ 확인”이라는 문제 해결 안내로 기능한다.[^90]

3.8 플랫폼별 키 주입: Flutter 공통 코드가 아니라 Android/iOS 디렉토리를 수정해야 한다[^91]

📸 21:37

이제부터가 “골치 아픈” 구간이라고 말한다.[^92] 이유는 이 작업이 Flutter(Dart) 코드로만 끝나는 게 아니라, 각 플랫폼의 환경 설정 파일에 키를 넣어야 하기 때문이다.[^93]

강의자는 Flutter 프로젝트 구조를 보여주며 다음 원칙을 설명한다.[^94]

  • Flutter의 대부분 로직은 공통 디렉토리(다트 코드)에서 작업한다.[^95]
  • 하지만 권한/기기 승인/플랫폼 전용 설정은 OS별 디렉토리에서 별도로 한다.[^96]
    • Android 설정은 android/ 아래에서[^97]
    • iOS 설정은 ios/ 아래에서[^98]
    • macOS, web, windows도 각자 디렉토리에서 환경설정을 한다는 식으로 확장 설명한다.[^99]

이 설명은 “왜 내가 Dart 코드를 고쳤는데도 동작이 안 되지?” 같은 혼란을 방지하기 위한 맥락 제공이다.[^100]

3.9 Android 설정: AndroidManifest.xml에 메타데이터로 API 키 넣기[^101]

📸 23:27

Android에서 API 키를 넣는 위치를 구체 경로로 안내한다.[^102]

  • android/app/src/main/AndroidManifest.xml 파일을 연다.[^103]
  • <application> 태그 아래에 meta-data 항목을 추가한다.[^104]
  • 이 메타데이터는 XML 규격이며, 다음을 넣는다고 설명한다:
    • android:namecom.google.android.geo.API_KEY(강의 발화상 “Android geoapi 키”로 읽어줌) 형태의 키 이름[^105]
    • android:value에 방금 복사한 API 키 값[^106]
  • 태그를 닫아 한 세트로 완성하면 Android 쪽 키 세팅이 “일단 오케이”라고 말한다.[^107]

여기서 강의자는 “Android는 간단하다”는 톤으로 iOS 대비를 예고한다.[^108]

3.10 iOS 설정(1): AppDelegate.swiftGMSServices.provideAPIKey(...) + import GoogleMaps[^109]

📸 25:46

iOS는 ios/Runner/ 쪽을 수정한다고 말하며, 주로 손대는 파일이 두 가지라고 언급한 뒤, 키 값은 AppDelegate.swift 에 넣는다고 한다.[^110]

iOS 키 주입 방식은 다음과 같이 안내된다.[^111]

  • AppDelegate.swift에서 (강의에서는 “불 바로 밑”이라고 지칭) 다음 호출을 추가:
    • GMSServices.provideAPIKey("여기에 키")[^112]
  • 그리고 기본 제공이 아니므로 라이브러리를 불러와야 한다며:
    • import GoogleMaps를 추가하라고 한다.[^113]

즉, iOS는 “키를 넣는 호출 + import” 두 가지를 해야 한다는 점이 강조된다.[^114]

3.11 iOS 설정(2): Info.plist에 Flutter 관련 환경 변수 추가[^115]

📸 27:33

다음으로 iOS의 Info.plist 에서 제일 아래로 내려가 환경 변수를 하나 추가해야 한다고 한다.[^116] 이는 “아이폰의 환경 변수” 중 하나를 추가하는 것으로 설명된다.[^117]

강의에서 지시하는 키/값은 다음 구조로 제시된다.[^118]

  • key(키 이름):
    • io.flutter.embedded_views_preview (강의 발화는 IO 플루터 점 ... 임베디드 ... 뷰 ... 프리뷰 형태로 읽음)[^119]
  • value(값):
    • true[^120]

강의자는 지금까지 한 설정을 정리하며 다음 매핑을 다시 확인시킨다.[^121]

  • Android: AndroidManifest.xml에 메타데이터로 키 설정[^122]
  • iOS: AppDelegate.swift에 키 제공 호출 + Info.plist에 위 환경 변수 추가[^123]

3.12 Android/iOS SDK “사용 설정됨” 재확인: 둘 다 켜져 있어야 한다[^124]

📸 29:10

설정을 끝낸 뒤 강의자는 다시 콘솔로 돌아가 확인할 것을 요구한다.[^125]

  • Maps SDK for Android: 관리 화면에서 “API 사용 설정됨”인지 확인[^126]
  • Maps SDK for iOS: 마찬가지로 iOS용도 “사용(Enable)” 상태인지 확인[^127]

결론은 “양쪽 다 켜져 있어야 양쪽에서 쓸 수 있다”는 것이다.[^128]

3.13 Flutter 코드에서 지도 띄우기: GoogleMap 위젯 배치와 기본 Scaffold 구성[^129]

📸 29:41

이제 “진짜로 맵을 불러오자”며 소스 코드로 돌아온다.[^130] 메인 화면을 단순화하고, StatefulWidget 기반의 MyHomePage를 만들고, Scaffold를 구성한다.[^131]

  • AppBar 타이틀을 “보물지도”라고 설정한다.[^132]
  • body에서 지도를 띄우려면 GoogleMap(...)을 배치하면 된다고 말하며 “너무 간단하죠”라고 표현한다.[^133]
  • 다만 실제로는 바로 에러가 나는데, 그 이유는 GoogleMap에 필수 파라미터인 카메라(초기 카메라 위치) 를 넣지 않았기 때문이라고 이어진다.[^134]

또한 화면 구성상 GoogleMapContainer로 감싸보는 시도를 한다.[^135]

3.14 필수 개념: initialCameraPosition과 카메라(뷰포트) 비유[^136]

📸 32:08

코드에서 에러가 뜨자, 강의자는 “카메라” 개념을 설명한다.[^137]

  • 지도는 있지만, 사용자가 처음 보게 될 영역을 마치 망원경/카메라로 어느 부분을 바라볼지 정해야 한다는 비유를 든다.[^138]
  • 이 “바라보는 영역(뷰포트)”을 지정하는 것이며, 이를 CameraPosition이라고 부른다고 설명한다.[^139]

따라서 해야 할 일은 다음이다.[^140]

  • CameraPosition 변수를 하나 만들고[^141]
  • 그 안에:
    • target: LatLng(위도, 경도) 형태로 위치를 지정[^142]
    • zoom: 얼마나 확대해서 볼지를 지정[^143]
  • 그리고 GoogleMap 위젯의 initialCameraPosition:에 이 CameraPosition을 전달한다.[^144]

3.15 위도(latitude)/경도(longitude) 설명과 줌 레벨 감각(12 vs 14~15)[^145]

📸 33:08

CameraPosition.target 타입을 따라가보면 LatLng를 받는다고 하며, 여기서 위도/경도를 설명한다.[^146]

  • 위도는 영어로 latitude, 경도는 longitude라고 설명한다.[^147]
  • 위도는 예로 “38선” 같은 개념을 들어 설명한다.[^148]
  • “북극 쪽으로 올라가는” 방향의 각을 위도, 태평양을 기준으로 좌우로 왔다 갔다 하는 각을 경도라고 말한다.[^149]
  • zoom은 “얼마나 줌인할 것이냐”이며, 다음 감각을 제시한다:
    • 줌 12 정도: “한 9개 동(지역 단위)을 한꺼번에 보는” 꽤 넓은 범위[^150]
    • 줌 14~15 정도: 골목길 등 상세하게 볼 때[^151]
  • 실습에서는 줌을 12로 둔다.[^152]

3.16 테스트용 위경도 구하기: Google 지도에서 URL의 3D/4D 값 읽기[^153]

📸 35:25

초기 위치(위경도)를 “임의로” 잡아야 하니, 테스트 방법을 보여준다고 한다.[^154] 여기서 강의자는 브라우저에서 구글 지도(google maps) 로 들어가 특정 장소(예: 서울역)를 검색한다.[^155]

그리고 “위경도 찾는 방법”으로 다음 요령을 설명한다.[^156]

  1. 구글 지도에서 원하는 장소를 검색한다(예: 서울역).[^157]
  2. 주소(URL)를 자세히 보면 경도가 숨어 있다고 말하며, URL을 복사해 텍스트로 붙여넣어 확인한다.[^158]
  3. URL 문자열 중에 3D...4D... 형태로 들어있는 숫자 값이 있는데, 이것이 위도/경도라고 설명한다.[^159]
    • 3D가 위도, 4D가 경도라고 짚는다.[^160]
    • 순서는 위도를 먼저, 경도를 뒤에 넣어야 한다고 강조한다.[^161]

이 값들을 LatLng(latitude, longitude)에 넣어 초기 위치로 사용한다는 것이다.[^162]

+++ 상세 예시(강의 흐름 재현)

  • 구글 지도에서 “서울역” 검색 → 결과 위치가 잡힘.[^155]
  • 주소(URL) 복사 → 문자열에서 3D가 붙은 값과 4D가 붙은 값을 찾음.[^159]
  • LatLng(3D값, 4D값) 순으로 입력.[^161]
    +++

3.17 GoogleMap(initialCameraPosition: ...)로 연결, 실행 시 에러 발생까지[^163]

📸 38:27

위에서 만든 CameraPositionGoogleMap에 넣으려는 과정에서, 강의자는 “그냥 바로 쓰면 안 되고 initialCameraPosition: 네임드 파라미터로 넣어야 한다”는 식으로 한 번 더 정리한다.[^164] 즉 최종적으로는:

  • GoogleMap(
    • initialCameraPosition: position,
      )
      같은 형태로 넣어줘야 한다고 말한다.[^165]

그리고 “잘 되나 실행해보자”고 하며 컴파일 후 실행한다.[^166] 실행 결과 “뭔가 에러가 폭 떨어졌다”고 말하며, 화면 위로 올라가서 에러를 보겠다고 하는 지점에서 영상 제공 텍스트가 끝난다.[^167]

즉, 이 파트의 마지막은:

  • 콘솔/키/플랫폼 설정 및 지도 위젯 코드까지는 넣었고[^168]
  • 실행했더니 에러가 발생했으며, 다음 단계에서 에러 메시지를 기반으로 추가 설명/수정을 하려는 전개 직전에서 종료된다.[^169]

4. 핵심 통찰[^170]

  1. 구글 맵 연동의 난이도는 “위젯 사용법”보다 콘솔 설정 + 플랫폼별 환경설정에 더 크게 걸려 있다.[^171]
  2. Flutter는 공통 코드가 강점이지만, 지도/권한/키 같은 요소는 결국 Android/iOS 각각의 설정 파일을 건드려야 한다.[^172]
  3. “지도 안 뜸” 문제는 코드보다 먼저 Maps SDK 활성화(Enable) 여부API 키 주입 위치부터 의심해야 한다.[^173]
  4. GoogleMap의 최소 요건은 initialCameraPosition이며, 이는 “처음에 어디를 어떤 줌으로 볼지”를 결정하는 앱의 기본 UX다.[^174]
  5. 위경도는 외부에서 가져오면 되는데, 강의는 구글 지도 URL의 3D/4D 값에서 위도/경도 추출하는 실용적 방법을 제시한다.[^175]
  • 실행 행동 항목(콘텐츠가 요구하는 체크리스트)
    • 콘솔에서 프로젝트 생성 후 Maps SDK for Android / iOS를 각각 Enable 했는지 확인한다.[^176]
    • API 키를 만든 뒤 복사해두고, AndroidManifest 및 iOS(AppDelegate, Info.plist)에 정확히 넣는다.[^177]
    • Flutter 코드에서 GoogleMap을 쓸 때 initialCameraPosition을 반드시 제공한다.[^178]

5. 헷갈리는 용어 정리 (해당 시에만)[^179]

CRUD: Create/Read/Update/Delete. 데이터(장소 기록)를 생성·조회·수정·삭제하는 기본 기능 묶음.[^180]
Quota(할당량): API를 무료로 사용할 수 있는 호출/사용량 한도. 한도를 넘으면 과금될 수 있다.[^181]
Google Cloud Console: 구글 API(맵 등)의 프로젝트 생성, API 활성화, 키(자격 증명) 발급을 하는 관리 콘솔.[^182]
Maps SDK for Android / iOS: 각 플랫폼에서 구글 맵을 사용하기 위해 콘솔에서 활성화해야 하는 API/SDK 항목.[^183]
API Key(승인 키/Access key): 구글 맵 API 사용을 인증하고 사용량 과금/통계를 연결하는 키.[^184]
CameraPosition: 지도를 어떤 위치(LatLng)를 중심으로 어느 확대(zoom)로 보여줄지 결정하는 “초기 뷰포트” 설정.[^185]
LatLng: 위도(latitude)와 경도(longitude)로 좌표를 표현하는 타입/구조.[^186]
zoom: 지도의 확대 수준. 값이 커질수록 더 확대(상세)된다.[^187]
AndroidManifest.xml: Android 앱의 권한/메타데이터/구성 정보를 담는 핵심 설정 파일. 구글 맵 키도 메타데이터로 주입한다.[^188]
AppDelegate.swift: iOS 앱 초기화 흐름에서 SDK 설정을 넣는 진입점 파일. 구글 맵 키 제공 호출을 넣는다.[^189]
Info.plist: iOS 앱의 환경 변수/설정 값을 담는 plist 파일. Flutter/임베디드 뷰 관련 키를 추가하라고 안내한다.[^190]


참고(콘텐츠 정보)[^191]

  • 제목: 플러터 모바일 앱개발 | 모바일 앱 개발자를 위한 Flutter(플러터) 제대로 배우기 Part.4 중급3 구글 맵과 장소기록, 도서API 이용앱 | 취업·실무·창업 | 에어클래스[^192]
  • 채널: 에어클래스[^193]
  • 길이: 39분 28초[^194]
  • 링크: https://www.youtube.com/watch?v=3yXT-jNL8jA[^195]

[^3]: @[10:48] "API 키를 구글에 가서 따야 됩니다" / @[23:27] AndroidManifest 경로 안내 / @[26:25] iOS AppDelegate에 provideAPIKey / @[38:50] initialCameraPosition 필요 [^4]: @[04:49] "원래 목적은... 장소 기록" [^5]: @[05:03] "장소 기록" / @[05:12] "위도와 경도" / @[05:18] "사진" / @[05:25] "제목이나 설명" / @[05:33] "crud" [^6]: @[01:06] "유료입니다" [^7]: @[01:09] "굉장히 많은 수까지 무료" / @[01:24] "몇십만... 넘어간다 하면" [^8]: @[01:49] "구글 맵 연동하는 거" / @[03:41] "SQL 라이트... 같이" / @[07:04] "카메라 연동" [^9]: @[03:57] "구글맵 플로터... 패키지" [^10]: @[02:24] "설정... 여러 군데를 건드려야" / @[03:13] "안드로이드 다르고 아이폰 다르고" [^11]: @[03:41] "SQ 라이트 배웠잖아요" / @[07:04] "카메라 연동" [^12]: @[01:57] "계속 바뀌어요" / @[02:13] "책하고 내용이 계속 바뀌니까" [^13]: @[07:33] "API 키 따는 거" / @[13:55] "요금... 결제 정보" [^14]: @[32:00] "이닛 카메라" 에러 / @[32:41] "뷰포트를 지정" / @[35:03] "줌" [^15]: @[07:39] "프로젝트를 하나 만들고... 들어가 보도록" [^16]: @[00:03] "구글 맵 연동" / @[01:57] "계속 바뀌어요" [^17]: @[01:49] "구글 맵 연동... 볼 거예요" [^18]: @[00:40] "간단한 거는 네이버나 다음" [^19]: @[01:06] "구글은... 유료" [^20]: @[01:09] "크게 걱정을 안 해도" [^21]: @[01:09] "굉장히 많은 수까지 무료" [^22]: @[01:24] "몇십만... 넘어간다 하면" [^23]: @[01:21] "넘어가야지 유료화... 크게 걱정 안 해도" [^24]: @[01:57] "계속 바뀌어요" [^25]: @[02:24] "여러 군데를 건드려야" / @[02:30] "시행 착오" [^26]: @[03:13] "안드로이드 다르고 아이폰 다르고... 오늘 다 배우려 그래요" [^27]: @[04:49] "장소 기록" / @[05:33] "crud" [^28]: @[03:35] "조금 더 단순하게... 않고" [^29]: @[03:41] "SQ 라이트... 응용 프로그램" [^30]: @[04:49] "원래 목적" [^31]: @[04:49] "길을 가다가... 메모" [^32]: @[05:07] "위도와 경도" [^33]: @[05:18] "사진" [^34]: @[05:25] "제목이나 설명" [^35]: @[05:33] "crud" [^36]: @[05:41] "위도와 경도로... 지도 연동" [^37]: @[05:58] "API 키" [^38]: @[03:41] SQLite + @[07:04] 카메라 + @[05:41] 지도연동 [^39]: @[06:22] "구글 클라우드... 파이어베이스 아니에요" [^40]: @[04:17] "무한적... 할당량" [^41]: @[04:27] "반드시... 어세스 키" [^42]: @[06:22] "구글 클라우드... 파이어베이스 아니에요" [^43]: @[06:22] "파이어베이스 아니에요" [^44]: @[06:32] "콘솔 클라우드 구글 닷컴" [^45]: @[07:33] "API 키 따는 거... 제일 먼저" [^46]: @[08:35] "외부 라이브러리... 장착" [^47]: @[07:39] "프로젝트... 만들고" / @[08:27] 실행 확인 [^48]: @[09:12] "구글 맵스 플러터" / @[09:55] pubspec에 추가 [^49]: @[09:24] "인스톨... 버전" / @[10:35] "패키지를 먼저" [^50]: @[09:01] "구글... 맵스" [^51]: @[09:33] "복사" [^52]: @[10:44] "라이브러리 장착" [^53]: @[10:06] "미리 복사를... 스펠링" [^54]: @[11:43] "프로젝트... 만들어 줘야" [^55]: @[07:33] "API 키... 제일 먼저" [^56]: @[10:52] "구글에 가서" / @[11:20] "개발자 콘솔" [^57]: @[11:47] 로그인 / @[11:51] 프로젝트 생성 / @[13:00] API 및 서비스 [^58]: @[11:43] "로그인을 먼저" [^59]: @[11:51] "프로젝트 부분" [^60]: @[12:14] "아무거나... 맵테스트" [^61]: @[12:23] "만들기" [^62]: @[12:56] "API 및 서비스" [^63]: @[13:26] "라이브러리" [^64]: @[13:55] "과금... 결제 정보... 처음엔 없어도" [^65]: @[14:02] "맵이라고" [^66]: @[14:25] "SDK... 안드로이드" / @[29:26] iOS도 확인 [^67]: @[14:39] "사용... 관리... API 사용 설정됨" [^68]: @[04:38] "키값... 받아야" [^69]: @[15:50] "키 및 사용자 인증 정보" / @[16:36] "키 생성" [^70]: @[15:50] "키 및 사용자 인증 정보" [^71]: @[16:36] "키 생성" [^72]: @[16:50] "복사" [^73]: @[16:50] "복사" [^74]: @[16:59] "사용량이 과금" [^75]: @[17:05] "애플리케이션 제한" [^76]: @[17:14] "웹사이트... 특정 IP... 안드로이드... 아이폰" [^77]: @[17:22] "없음이라 그러면 다 쓴다" [^78]: @[17:29] "없음으로 하시면" [^79]: @[17:46] "API 제한 사항" [^80]: @[18:05] "딱히 제한 없이" [^81]: @[18:24] "새키... 현재 키는 24시간" [^82]: @[18:33] "키가 잠깐 동안 두 개" [^83]: @[18:44] "강의 끝난 다음에... 초기" [^84]: @[19:30] "임시로... 나중에 지우셔야" [^85]: @[20:26] "네이블 디에이블" / @[21:20] "이네이블 눌러" [^86]: @[21:22] "별 크게 실수... 지도 안" [^87]: @[20:41] "이네이블... 눌러" [^88]: @[21:14] "이네이블 되어 있으면... 디스에이블" [^89]: @[20:46] "안드로이드... 이네이블" [^90]: @[21:26] "이쪽으로 와서 네이블" [^91]: @[22:12] "특정 환경... OS 디렉토리" [^92]: @[21:37] "골체 아파요" [^93]: @[21:42] "코드로... 환경 설정" [^94]: @[22:06] "디렉토리" 설명 [^95]: @[22:00] "소스 코드를 공통" [^96]: @[22:25] "권한 설정... 안드로이드 다르고" [^97]: @[22:29] "안드로이드는... 여기" [^98]: @[22:41] "iOS... 여기서" [^99]: @[22:52] "맥... 웹... 윈도우즈" [^100]: @[23:05] "각각마다 환경 설정... 차이" [^101]: @[23:23] Android로 이동 [^102]: @[23:27] "앱... 소스... 메인" [^103]: @[23:45] "Android manifest.xml" [^104]: @[24:25] "어플리케이션... 밑에" [^105]: @[24:47] "com google... Android geoapi 키" [^106]: @[25:06] "여기에다가 키값" [^107]: @[25:31] "안드로이드는 일단 오케이" [^108]: @[25:36] "다음 iOS" [^109]: @[26:03] "델리게이트 스위프트" [^110]: @[25:46] "Runner" / @[26:05] "여기에 넣어" [^111]: @[26:25] provideAPIKey [^112]: @[26:25] "GMSS... provide API key" [^113]: @[27:00] "import... 구글맵스" [^114]: @[27:12] "됐어요" [^115]: @[27:27] "p 리스트" [^116]: @[27:33] "제일 밑으로" [^117]: @[27:44] "아이폰의 환경 변수" [^118]: @[27:52] "키는 키라고" [^119]: @[28:06] "io flutter... embedded... views preview" [^120]: @[28:25] "true" [^121]: @[28:42] 설정 정리 [^122]: @[28:42] "안드로이드는 매니페스트" [^123]: @[28:32] "피리스트... 스위프트" [^124]: @[29:16] "API 사용 설정" 확인 [^125]: @[29:10] "잠깐만... 확인" [^126]: @[29:16] "안드로이드... API 사용 설정" [^127]: @[29:26] "iOS... 사용" [^128]: @[29:35] "그래야지 양쪽 다" [^129]: @[29:41] "맵을 한번 불러" [^130]: @[29:41] "소스에서... 맵" [^131]: @[30:23] "stf... 마이 홈페이지" [^132]: @[31:02] "보물지도" [^133]: @[31:22] "구글 맵 하면 돼요" [^134]: @[32:00] "이닛 카메라" 에러 [^135]: @[31:49] "컨테이너로 감싸" [^136]: @[32:19] "카메라가 뭐냐면요" [^137]: @[32:08] "에러가 뜬" [^138]: @[32:24] "망원경" [^139]: @[32:41] "뷰포트를 지정... 카메라" [^140]: @[32:50] "CameraPosition" [^141]: @[32:50] "변수" [^142]: @[33:22] "latlng" [^143]: @[34:58] "줌" [^144]: @[38:50] "initial camera position" [^145]: @[33:39] latitude / @[34:02] longitude / @[35:08] zoom [^146]: @[33:08] "target... latlng" [^147]: @[33:39] "라티튜드" / @[34:02] "롱지..." [^148]: @[34:02] "38선" [^149]: @[34:24] "태평양... 정도" [^150]: @[35:08] "12 정도... 9나 동" [^151]: @[35:13] "골목길... 14 15" [^152]: @[35:13] "12 정도로" [^153]: @[35:30] "테스트... 보여" [^154]: @[35:25] "시작 위경도... 임으로" [^155]: @[36:22] "서울역" [^156]: @[36:49] "주소를... 경도가 숨어" [^157]: @[36:32] "서울역" [^158]: @[36:55] "카피" / @[36:57] "붙여 놓고" [^159]: @[37:09] "3D... 4D" [^160]: @[37:29] "3가... 위도" / @[37:56] "경도" [^161]: @[38:05] "위도를 먼저... 경도를 뒤" [^162]: @[33:22] LatLng + @[38:05] 순서 [^163]: @[38:50] "initialCameraPosition" [^164]: @[38:27] "포지션을 써야 돼... 네임드" [^165]: @[38:50] "이니셜 카메라 포지션" [^166]: @[39:06] "실행해 봅시다" [^167]: @[39:18] "에러가 폭" [^168]: @[27:19] Android+iOS 설정 완료 / @[38:50] 코드 연결 [^169]: @[30:02] "에러... 다시 설명" 예고 / @[39:18] 에러 발생 [^170]: @[02:30] "시행 착오" / @[22:12] 플랫폼별 설정 / @[32:41] 카메라 [^171]: @[02:24] "여러 군데" / @[21:42] "환경 설정" [^172]: @[22:12] "OS 디렉토리" / @[23:27] AndroidManifest / @[26:03] iOS AppDelegate [^173]: @[21:22] "지도 안" / @[29:16] API 사용 설정 확인 [^174]: @[32:00] initial camera 에러 / @[34:58] zoom [^175]: @[37:09] "3D... 4D" [^176]: @[29:16] Android / @[29:26] iOS 사용 확인 [^177]: @[24:25] Android meta-data / @[26:25] iOS provideAPIKey / @[28:06] Info.plist true [^178]: @[38:50] initialCameraPosition [^179]: @[05:33] CRUD / @[04:17] 할당량 / @[06:22] 구글 클라우드 [^180]: @[05:33] "crud" [^181]: @[04:17] "할당량" [^182]: @[06:32] "콘솔 클라우드" [^183]: @[14:28] "SDK... 안드로이드" / @[29:26] iOS [^184]: @[06:02] "API 키" / @[04:38] "승인 키" [^185]: @[32:50] "카메라 포지션" / @[34:58] "줌" [^186]: @[33:22] "latlng" [^187]: @[35:03] "줌" [^188]: @[23:45] AndroidManifest.xml [^189]: @[26:03] delegate swift [^190]: @[27:27] Info.plist [^191]: @[00:03] 콘텐츠 도입부 맥락 [^192]: 사용자 제공 메타데이터(제목) [^193]: 사용자 제공 메타데이터(채널) [^194]: 사용자 제공 메타데이터(길이) [^195]: 사용자 제공 메타데이터(링크)

← 프로젝트에서 보기