routo Maps Flutter SDK

routo Maps Flutter SDK는 routo의 공식 Flutter 플러그인으로, Android/iOS 네이티브 RoutoMapSDK를 Flutter 위젯으로 통합합니다.

웹 및 데스크톱은 지원하지 않습니다.


Supported API

Feature Android iOS
Map Widget
Camera position
Camera animations
Events
Map gestures
Map styles (Light / Dark / Custom)
User Location
Traffic layer
Scale bar
POI picking & filter
Incident layer
Parking layer
Markers
Marker clusters
Route lines
Dot / Pattern lines
Polygons
2.5D layer
HillShade layer
HD Map layer
Snapshot
RoutoMapScope (InheritedWidget)
Style DSL
Expression DSL
View Annotations

Requirements

  • iOS 15.1 or higher
  • Android SDK 21 or higher
  • Flutter 3.10.0 / Dart 3.0.0 or higher

Getting Started

1. SDK 접근 권한 신청

SDK 사용을 위한 App Key 및 패키지 접근 토큰은 routo 개발팀에 요청하세요.

App Key는 Android / iOS 공통으로 사용하는 단일 인증 키입니다. Android는 AndroidManifest.xml, iOS는 Info.plist에 각각 설정합니다.

2. pubspec.yaml

dependencies:
  routo_maps_flutter: ^0.1.4
flutter pub get

3. Android 설정

android/settings.gradle — JFrog Maven 저장소 추가 (네이티브 SDK 다운로드에 필수):

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS)
    repositories {
        google()
        mavenCentral()
        maven { url 'https://storage.flutter-io.cn/download.flutter.io' }
        maven { url 'https://jitpack.io' }
        maven {
            url = uri("https://routo.jfrog.io/artifactory/routo-sdk")
            credentials {
                username = "" // 계정정보는 routo 개발팀에 문의 바랍니다.
                password = "" // 계정정보는 routo 개발팀에 문의 바랍니다.
            }
        }
    }
}

AndroidManifest.xml — 권한 및 App Key:

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

<application>
    <!-- App Key (iOS의 RoutoAccessToken과 동일한 키) -->
    <meta-data
        android:name="com.routo.mapsdk.appkey"
        android:value="YOUR_ROUTO_APP_KEY" />
</application>

MainActivity.ktFlutterFragmentActivity 상속 필수:

import io.flutter.embedding.android.FlutterFragmentActivity
import io.flutter.embedding.android.RenderMode

class MainActivity : FlutterFragmentActivity() {
    override fun getRenderMode(): RenderMode = RenderMode.texture
}

4. iOS 설정

RoutoMapSDK SPM 패키지 추가 — Xcode에서 직접 추가합니다:

  1. Xcode에서 ios/Runner.xcworkspace 열기
  2. File > Add Package Dependencies 선택
  3. 패키지 URL 입력:
    https://github.com/hyundai-autoever-routo/routo-maps-ios.git
    
  4. 계정 정보 입력 (routo 개발팀에 문의)
  5. Dependency RuleExact Version으로 선택 후 배포 버전 입력
  6. Add Package 클릭하여 완료

Info.plist — App Key 및 위치 권한:

<!-- App Key (Android의 com.routo.mapsdk.appkey와 동일한 키) -->
<key>RoutoAccessToken</key>
<string>YOUR_ROUTO_APP_KEY</string>

<!-- 위치 권한 -->
<key>NSLocationWhenInUseUsageDescription</key>
<string>지도 서비스 이용을 위해 위치 권한이 필요합니다.</string>
cd ios && pod install && cd ..

Add a map

import 'package:routo_maps_flutter/routo_maps_flutter.dart';

class MapScreen extends StatefulWidget {
  const MapScreen({super.key});
  @override
  State<MapScreen> createState() => _MapScreenState();
}

class _MapScreenState extends State<MapScreen> {
  RoutoMapController? _controller;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: RoutoMapView(
        initialCameraPosition: CameraPosition(
          target: LatLng(37.5665, 126.9780),
          zoom: 14,
        ),
        onMapCreated: (controller) => _controller = controller,
        onMapReady: () => print('지도 준비 완료'),
      ),
    );
  }
}

RoutoMapController

RoutoMapControlleronMapCreated 콜백으로 전달됩니다. 하위 위젯에서 공유하려면 RoutoMapScope를 사용하세요:

RoutoMapScope(
  controller: _controller!,
  child: MyMapControls(),
)

// 하위 위젯에서
RoutoMapScope.of(context).setMapTraffic(true);

Camera and animations

// 즉시 이동
await _controller?.moveCamera(37.4979, 127.0276, zoom: 15);

// 애니메이션 이동 (CameraUpdate 빌더)
await _controller?.animateCamera(
  CameraUpdate.newCameraPosition(
    CameraPosition(target: LatLng(37.4979, 127.0276), zoom: 16, bearing: 90, tilt: 45),
  ),
  duration: const Duration(milliseconds: 800),
);

// 줌 in / out
await _controller?.zoomIn();
await _controller?.zoomOut(duration: const Duration(milliseconds: 300));

// 현재 카메라 상태 조회
final camera = await _controller?.getCamera();
print('중심: ${camera?.target}  줌: ${camera?.zoom}');

// 범위에 맞추기
await _controller?.fitBounds(
  LatLngBounds(southwest: LatLng(37.45, 126.90), northeast: LatLng(37.60, 127.10)),
  padding: const EdgeInsets.all(60),
);

Events

void _onMapCreated(RoutoMapController controller) {
  controller.onCameraChanged.listen((e) {
    print('중심: (${e.lat}, ${e.lng})  줌: ${e.zoom}');
  });

  controller.onPoiPicked.listen((e) {  // setPoiPickingEnabled(true) 필요
    print('POI: ${e.name}  (${e.lat}, ${e.lng})');
  });

  controller.onMapTapped.listen((e) => print('탭: (${e.lat}, ${e.lng})'));
  controller.onMapLongTapped.listen((e) => print('롱탭: (${e.lat}, ${e.lng})'));
  controller.onMarkerTapped.listen((e) => print('마커: ${e.id}'));
}

Map styles

// 프리셋 스타일 변경
await _controller?.setStyle(RoutoMapStyle.basic);       // Routo Light
await _controller?.setStyle(RoutoMapStyle.dark);        // Routo Dark
await _controller?.setStyle(RoutoMapStyle.hybrid);      // Routo Hybrid
await _controller?.setStyle(RoutoMapStyle.trafficDay);  // Traffic Day
await _controller?.setStyle(RoutoMapStyle.trafficNight);// Traffic Night
await _controller?.setStyle(RoutoMapStyle.streets);     // Mapbox Streets

// 커스텀 URL 지정
await _controller?.setMapStyle('https://example.com/custom-style.json');

// 초기 스타일 — 프리셋 (RoutoMapStyle enum 직접 사용)
RoutoMapView(mapStyle: RoutoMapStyle.dark, ...)

// 초기 스타일 — 커스텀 URL
RoutoMapView(mapStyleUri: 'https://example.com/custom-style.json', ...)

Map layers

await _controller?.setMapTraffic(true);       // 교통 레이어
await _controller?.setScaleBar(true);          // 스케일바
await _controller?.setIncidentLayer(true);     // 유고정보
await _controller?.setMap2_5DLayer(true);      // 2.5D 건물
await _controller?.setHillShadeLayer(true);    // HillShade 지형

Markers

await _controller?.addMarker('marker_1', 37.5665, 126.9780);
await _controller?.addMarkerWithLabel('marker_2', 37.4979, 127.0276, label: '강남역');
await _controller?.removeMarker('marker_1');

User location

await _controller?.setUserLocationEnabled(true);
await _controller?.startLocationTracking(mode: FollowUserMode.following);

_controller?.onLocationMapMoved.listen((_) {
  setState(() => _isTracking = false);
});

Snapshot

final imageBytes = await _controller?.snapshotMap();  // Uint8List (PNG)

LatLng utilities

const seoul = LatLng(37.5665, 126.9780);
const gangnam = LatLng(37.4979, 127.0276);

final meters = seoul.distanceTo(gangnam);  // ≈ 9,400 m

Platform docs


© 2026 routo Inc. All rights reserved.

Libraries

routo_maps_flutter
Flutter plugin for Routo Maps SDK.