<

새로 알게된 지식들

[Flutter] Google Maps Cloud 스타일 설정 가이드

sj han 2025. 11. 6. 21:24
728x90
반응형

Google Maps Cloud 스타일 설정 가이드

Flutter 앱에서 Google Maps의 외관을 완전히 커스터마이징하는 방법을 소개합니다.

📚 목차

  1. 개요
  2. 준비 사항
  3. Google Maps Platform 접근
  4. Step 1: 지도 스타일 편집
  5. Step 2: Map ID 생성
  6. Step 3: Flutter 앱 설정
  7. 실제 사용 예시
  8. 트러블슈팅

개요

Google Maps Platform의 Cloud 기반 스타일링 기능을 사용하면:

웹 기반 UI에서 지도 스타일을 시각적으로 편집
플랫폼별 (Android/iOS) 다른 스타일 적용 가능
코드 없이 지도 색상, 라벨, 도로 굵기 등 커스터마이징
Map ID를 통해 Flutter 앱에 즉시 반영
실시간 업데이트 - 앱 재배포 없이 서버에서 지도 스타일 변경 가능

기존 방식 vs Cloud 방식

항목 기존 방식 (JSON) Cloud 방식 (Map ID)
편집 도구 코드 직접 작성 웹 UI (시각적)
학습곡선 가파름 낮음
실시간 반영 앱 재배포 필요 즉시 반영
플랫폼별 스타일 수동 관리 별도 Map ID로 간편
버전 관리 복잡함 Cloud에서 자동

준비 사항

1. Google Cloud 프로젝트

  • Google Cloud Console에서 프로젝트 생성
  • Maps JavaScript API 활성화
  • API 키 생성 (또는 기존 키 사용)

2. 권한 확인

  • Google Maps Platform 액세스 가능
  • 청구 계정 연결 (일일 무료 할당량: 28,000개 로드)

3. Flutter 프로젝트

  • google_maps_flutter 패키지 설치
  • Android/iOS 플랫폼 설정 완료

Google Maps Platform 접근

접근 방법

  1. Google Cloud Console 로그인
  2. https://console.cloud.google.com
  3. 프로젝트 선택 또는 생성
  4. Google Maps API 활성화
  5. 메뉴 → "APIs & Services" → "Enabled APIs & services" → "Google Maps Platform" 또는 "Maps JavaScript API" 검색 및 활성화

Step 1: 지도 스타일 편집

Google Maps Platform Studio - Style 탭 접근

URL: https://console.cloud.google.com/google/maps-apis/studio/styles

1-1. 새 스타일 생성

1. "Create new style" 클릭
2. 스타일 이름 입력 (예: "Restaurant Style")
3. "Create and continue" 클릭

1-2. 스타일 커스터마이징

웹 기반 에디터에서 다음 요소들을 편집할 수 있습니다:

🎨 편집 가능한 요소

요소 설명 예시
Water 물, 강, 해수 파란색 → 진한 파란색
Land 육지, 공원 밝은 회색 → 베이지색
Roads 도로 네트워크 흰색 → 검은색 테두리
Labels 지역명, 도로명 글꼴, 색상, 크기
Boundaries 행정 경계선 국경, 시 경계
Points of Interest POI (음식점, 주유소 등) 아이콘 색상, 라벨 표시

📝 편집 단계

1. 왼쪽 패널에서 "Customize" 탭 선택
2. 편집할 요소 선택 (예: "Points of Interest")
3. 색상, 라벨 표시 여부, 아이콘 크기 등 조정
4. 변경사항이 지도에 실시간으로 반영됨

1-3. 음식점(POI) 스타일 예시

맛집 앱을 위한 최적 스타일:

Points of Interest:
├─ Food & Drink
│  ├─ Color: #FF5722 (주황색) ← 음식점 강조
│  ├─ Label: Show labels
│  └─ Icon scale: 130%
├─ Restaurants (하위 카테고리)
│  └─ Color: #E84C3D (더 진한 빨간색)
└─ Bars & Cafes
   └─ Color: #FFB74D (황금색)

Roads:
├─ Main streets: #333333 (진한 회색)
├─ Secondary: #666666 (중간 회색)
└─ Tertiary: #CCCCCC (밝은 회색)

Labels:
├─ Font: Roboto
├─ Color: #333333
└─ Size: 12-14px

1-4. 저장

오른쪽 상단 "Save and continue" 또는 "Save"
→ 스타일이 저장됨

Step 2: Map ID 생성

Google Maps Platform Studio - Maps 탭 접근

URL: https://console.cloud.google.com/google/maps-apis/studio/maps

2-1. 새 Map ID 생성

1. "Create new map" 클릭
2. Map 이름 입력 (예: "Android_Restaurant_Map", "iOS_Restaurant_Map")
3. Map type 선택: "Raster" (기본값, 일반 2D 지도)
4. "Create" 클릭

2-2. 스타일 적용

1. 새로 생성된 Map 선택
2. "Style" 섹션에서 "Edit style" 또는 스타일 선택
3. Step 1에서 생성한 스타일 선택
4. "Save" 클릭

2-3. Map ID 확인

생성된 Map의 상세 페이지:
├─ Display name: "Android_Restaurant_Map"
└─ ID: "{your_map_id}" ← 이 값을 Flutter에서 사용

Map ID 형식:

16자-32자의 16진수 문자열 (예: 2368c5231d5s4dc1af11fbb9)

2-4. 플랫폼별 Map ID 전략

안드로이드와 iOS에 다른 스타일 적용:

Google Maps Platform Studio (Maps 탭)
├─ "Android_Restaurant_Map"
│  ├─ Map ID: {your_map_id}
│  └─ Style: "Restaurant Style (Vibrant)"
│
└─ "iOS_Restaurant_Map"
   ├─ Map ID: {your_map_id}
   └─ Style: "Restaurant Style (Light)"

이렇게 하면 iOS에서는 밝은 스타일, Android에서는 진한 스타일 적용 가능!


Step 3: Flutter 앱 설정

3-1. .env 파일에 Map ID 저장

# .env
GOOGLE_MAPS_API_KEY={your_api_key}

# ✅ 플랫폼별 Map ID
GOOGLE_MAPS_ANDROID_MAP_ID={your_map_id}
GOOGLE_MAPS_IOS_MAP_ID={your_map_id}

3-2. api_config.dart에서 Map ID 로드

import 'dart:io' show Platform;
import 'package:flutter_dotenv/flutter_dotenv.dart';

class ApiConfig {
  // Android Google Maps Cloud Map ID
  static String get googleMapsAndroidMapId {
    try {
      return dotenv.get(
        'GOOGLE_MAPS_ANDROID_MAP_ID',
        fallback: '{your_map_id}',
      );
    } catch (e) {
      return '{your_map_id}';
    }
  }

  // iOS Google Maps Cloud Map ID
  static String get googleMapsIosMapId {
    try {
      return dotenv.get(
        'GOOGLE_MAPS_IOS_MAP_ID',
        fallback: '{your_map_id}',
      );
    } catch (e) {
      return '{your_map_id}';
    }
  }

  // 현재 플랫폼에 맞는 Map ID 자동 반환
  static String get googleMapsCloudMapId {
    if (Platform.isAndroid) {
      return googleMapsAndroidMapId;
    } else if (Platform.isIOS) {
      return googleMapsIosMapId;
    } else {
      return googleMapsAndroidMapId;
    }
  }
}

3-3. GoogleMap 위젯에 적용

import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:project_1/config/api_config.dart';

GoogleMap(
  // ✅ Cloud Map ID 설정 - 스타일 적용됨!
  cloudMapId: ApiConfig.googleMapsCloudMapId,

  initialCameraPosition: CameraPosition(
    target: LatLng(37.5665, 126.9780),  // 서울
    zoom: 14.0,
  ),

  markers: markers,
  onMapCreated: (controller) {
    mapController = controller;
  },
)

실제 사용 예시

프로젝트 적용 사례

class SearchPage extends ConsumerStatefulWidget {
  @override
  ConsumerState<SearchPage> createState() => _SearchPageState();
}

class _SearchPageState extends ConsumerState<SearchPage> {
  GoogleMapController? mapController;

  @override
  Widget build(BuildContext context) {
    return GoogleMap(
      // ✅ 앱 초기화 시 로드된 Map ID 사용
      cloudMapId: ApiConfig.googleMapsCloudMapId,

      initialCameraPosition: CameraPosition(
        target: LatLng(37.5665, 126.9780),
        zoom: 15.0,
      ),

      markers: _buildRestaurantMarkers(),

      onMapCreated: (controller) {
        setState(() => mapController = controller);
      },
    );
  }

  Set<Marker> _buildRestaurantMarkers() {
    // 음식점 마커 생성
    // Map ID의 "Food & Drink" 스타일이 자동으로 적용됨
    return restaurants.map((restaurant) {
      return Marker(
        markerId: MarkerId(restaurant.id),
        position: LatLng(restaurant.lat, restaurant.lng),
        infoWindow: InfoWindow(title: restaurant.name),
      );
    }).toSet();
  }
}

앱 초기화 시 Map ID 검증

// app_initialization_provider.dart
class AppInitializationNotifier extends Notifier<AppInitializationState> {
  Future<void> initializeApp() async {
    // Phase 0: Google Maps 설정 로드
    state = state.copyWith(currentTask: 'Google Maps 설정 로드 중...');

    final mapId = ApiConfig.googleMapsCloudMapId;
    appDebugPrint(
      '✅ Google Maps Map ID 로드 완료: $mapId',
      tag: 'app_initialization',
    );

    // ... 나머지 초기화
  }
}

트러블슈팅

❌ "Map ID가 유효하지 않습니다" 에러

원인: Map ID가 잘못되었거나 API 키와 매칭되지 않음

해결:

1. Google Cloud Console에서 Map ID 확인
2. .env 파일에 정확히 복사
3. API 키가 올바른지 확인
4. "Maps JavaScript API" 활성화 확인

❌ 지도가 회색으로만 보입니다

원인:

  • 스타일이 로드되지 않음
  • 네트워크 연결 끊김
  • CloudMapId가 빈 문자열

해결:

// cloudMapId 확인
debugPrint('Map ID: ${ApiConfig.googleMapsCloudMapId}');

// 빈 문자열이 아닌지 확인
if (ApiConfig.googleMapsCloudMapId.isEmpty) {
  print('⚠️ Map ID가 로드되지 않았습니다!');
}

❌ Android와 iOS에서 다른 스타일이 보입니다

원인: Map ID가 다르게 설정됨 (의도된 것일 수 있음)

확인:

print('Android Map ID: ${ApiConfig.googleMapsAndroidMapId}');
print('iOS Map ID: ${ApiConfig.googleMapsIosMapId}');

// 같은 스타일을 원하면 동일한 Map ID 사용

❌ 지도 스타일 변경이 앱에 반영되지 않습니다

원인: 캐싱 또는 앱 재시작 필요

해결:

1. 앱 완전 재시작 (앱 강제 종료 → 재실행)
2. 핫 리로드/핫 리스타트 사용 (변경사항 반영 안 될 수 있음)
3. Google Cloud Console에서 실제로 저장되었는지 확인

💡 팁: 개발 중 빠른 테스트

// 여러 Map ID를 빠르게 전환하면서 테스트
class ApiConfig {
  static String get googleMapsCloudMapId {
    // 개발 중: 주석 처리해서 다양한 스타일 테스트
    // return 'DEV_MAP_ID_1'; // 스타일 A
    return 'DEV_MAP_ID_2'; // 스타일 B
    // return ApiConfig.googleMapsAndroidMapId; // 프로덕션
  }
}

고급 팁

1️⃣ 다중 스타일 관리

Google Maps Platform → Maps 탭:
├─ "Dev_Map": 개발용 (밝은 스타일)
├─ "Staging_Map": 스테이징용 (중간 스타일)
└─ "Production_Map": 프로덕션용 (다크 스타일)

.env 파일로 환경별 관리:

# .env.dev
GOOGLE_MAPS_ANDROID_MAP_ID=dev_map_id_123

# .env.staging
GOOGLE_MAPS_ANDROID_MAP_ID=staging_map_id_456

# .env.production
GOOGLE_MAPS_ANDROID_MAP_ID=prod_map_id_789

2️⃣ 사용자 선택에 따른 동적 스타일 변경

// 사용자가 "다크 모드" 토글 시 스타일 변경
Future<void> toggleDarkMode(bool isDark) async {
  final newMapId = isDark 
    ? 'dark_map_id_123'
    : 'light_map_id_456';

  // 지도 컨트롤러를 통해 새 Map ID 적용
  // (현재 google_maps_flutter에서 런타임 변경 지원 안 함)
  // → Widget 재구성 필요
  setState(() {
    currentMapId = newMapId;
  });
}

3️⃣ 음식점 카테고리별 색상 커스터마이징

Google Maps Studio → Style:
├─ Points of Interest
│  ├─ Food & Drink: #FF5722 (주황색)
│  ├─ Restaurant: #E84C3D (빨간색)
│  ├─ Bar: #FFA726 (황금색)
│  └─ Cafe: #AB47BC (보라색)

이렇게 설정하면 지도에 자동으로 카테고리별 색상이 표시됨!


결론

Google Maps Cloud 스타일링은:

비용 효율적 - 개발자 개입 최소화
시각적 - 코드 없이 드래그&드롭 편집
실시간 - 앱 재배포 없이 즉시 반영
플랫폼별 - Android/iOS 다른 스타일 관리 가능
확장성 - 새로운 스타일 쉽게 추가 가능

다음 단계:

  1. Google Cloud Console에서 스타일 생성
  2. Map ID 획득
  3. .env 파일에 저장
  4. Flutter 앱에 cloudMapId 설정
  5. 앱 재시작해서 스타일 확인!

참고 자료

728x90
반응형
LIST