[Flutter] Flutter에서

Flutter에서 네이버 지도를 열 수 있게 해주는 플러그인입니다.

Flutter 프로젝트에서 네이버 지도를 표시하는 플러그인은 Android와 iOS를 지원합니다.

설치하기 위해서

플러그인은 네이버 클라우드 플랫폼 – 지도 안드로이드와 iOS 환경에서 제공하는 지도 서비스를 표시해주는 플러그인입니다.

  • 네이버 클라우드 플랫폼에서 콘솔의 AI/애플리케이션 서비스 > AI/NAVER API > 애플리케이션에서 애플리케이션을 등록합니다.

  • 등록된 어플리케이션을 선택하고 Client ID 값을 확인하여 변경 화면에서 Maps가 선택되어 있는지 확인합니다.

pubspec.yaml에 플러그인 종속성 작성

dependencies:
  naver_map_plugin: ^0.9.6

경고

  • 카드에서 제공하는 기본 컨트롤러가 잘 안되네요(이유를 모르겠습니다)
  • 안드로이드에서는 현재 위치 버튼만 정상적으로 동작

참고(안드로이드)

  • 한국인
    • 네이버에서 제공하는 SDK의 경우 기본적으로 GLSurfaceView를 사용하여 Android에서 지도를 표시합니다.

      네이버 지도 SDK 바이너리의 부정확한 원인으로 인해 핫 리로드 시 앱 크래시가 발생합니다.

      다시 로드하지 않는 릴리스 버전에서는 더 나은 성능의 GLSurfaceView를 사용하고 그렇지 않으면 즉석에서 다시 로드할 수 있는 TextureView를 사용하십시오.
  • 영어
    • NaverMap SDK는 기본적으로 GLSurfaceView를 사용하여 Android에서 지도 보기를 지웁니다.

      핫 리로드는 불명확한 이유로 Naver Map SDK 바이너리에서 앱 충돌을 일으킵니다.

      게시된 버전을 생성할 때 이 플러그인은 더 나은 성능을 위해 GLSurfaceView를 사용하고 그렇지 않으면 TextureView를 사용하여 핫 리로드를 노출합니다.

안드로이드 시작하기

AndroidManifest.xml에 지정됨

<manifest>
    <application>
        <meta-data
            android:name="com.naver.maps.map.CLIENT_ID"
            android:value="YOUR_CLIENT_ID_HERE" />
    </application>
</manifest>

내비게이션 지도에서 현재 위치 조회 기능을 사용하려면 AndroidManifest.xml에 권한을 부여해야 합니다.

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

또한 Android API Level 23(M) 이상에서는 동적 권한이 필요합니다.

다음은 동적 권한을 요청하는 샘플 코드입니다.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) !
= PackageManager.PERMISSION_GRANTED) { requestPermissions(new String(){Manifest.permission.ACCESS_FINE_LOCATION}, 0); } }

iOS 시작하기

대용량 파일을 받기 위해 자식-lfs 설치가 필요합니다.

$ brew install git-lfs

그리고 git-lfs를 사용하기 위해 다음 명령어를 입력합니다.

lfs가 활성화되지 않은 경우 포드 간에 종속성이 다운로드되지 않습니다.

$ git lfs install

info.plist에 지정됨

<dict>
  <key>NMFClientId</key>
  <string>YOUR_CLIENT_ID_HERE</string>
  <key>io.flutter.embedded_views_preview</key>
  <true/>
  <key>NSAllowsArbitraryLoads</key>
  <true/>
</dict>

내비게이션 지도에서 현재 위치에 대한 검색 기능을 사용하려면 info.plist에 권한을 지정합니다.

<dict>
    <key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
	<string>(USAGE PERPOSE)</string>
	<key>NSLocationAlwaysUsageDescription</key>
	<string>(USAGE PERPOSE)</string>
	<key>NSLocationWhenInUseUsageDescription</key>
	<string>(USAGE PERPOSE)</string>
</dict>

이후 AppDelfate에서 위치 권한을 획득하는 예시입니다.

if (CLLocationManager.locationServicesEnabled()) {
    switch CLLocationManager.authorizationStatus() {
    case .denied, .notDetermined, .restricted:
        self.manager.requestAlwaysAuthorization()
        break
    default:
        break
    }
}       

샘플 코드

import 'package:flutter/material.dart';

import 'package:naver_map_plugin_example/base_map.dart';
import 'package:naver_map_plugin_example/circle_map.dart';
import 'package:naver_map_plugin_example/padding_test.dart';
import 'package:naver_map_plugin_example/marker_map_page.dart';
import 'package:naver_map_plugin_example/path_map.dart';
import 'package:naver_map_plugin_example/polygon_map.dart';
import 'package:naver_map_plugin_example/text_field_page.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MainPage(),
    );
  }
}

class MainPage extends StatefulWidget {
  @override
  _MainPageState createState() => _MainPageState();
}

class _MainPageState extends State<MainPage> {
  List<String> menuText = (
    '기본 지도 예제',
    '마커 예제',
    '패스 예제',
    '원형 오버레이 예제',
    '컨트롤러 테스트',
    '폴리곤 예제',
    'GLSurface Thread collision test',
  );

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        padding: EdgeInsets.all(16),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: menuText
              .map((text) => GestureDetector(
                    onTap: () => _onTapMenuItem(text),
                    child: Container(
                      margin: EdgeInsets.symmetric(vertical: 8),
                      padding: EdgeInsets.all(16),
                      decoration: BoxDecoration(
                        borderRadius: BorderRadius.circular(6),
                        border: Border.all(color: Colors.indigo),
                      ),
                      child: Text(
                        text,
                        style: TextStyle(
                          color: Colors.indigo,
                          fontSize: 12,
                          fontWeight: FontWeight.w600,
                        ),
                        textAlign: TextAlign.center,
                      ),
                    ),
                  ))
              .toList(),
        ),
      ),
    );
  }

  _onTapMenuItem(String text) {
    final index = menuText.indexOf(text);
    switch (index) {
      case 0:
        Navigator.push(
            context,
            MaterialPageRoute(
              builder: (context) => BaseMapPage(),
            ));
        break;
      case 1:
        Navigator.push(
            context,
            MaterialPageRoute(
              builder: (context) => MarkerMapPage(),
            ));
        break;
      case 2:
        Navigator.push(
            context,
            MaterialPageRoute(
              builder: (context) => PathMapPage(),
            ));
        break;
      case 3:
        Navigator.push(
            context,
            MaterialPageRoute(
              builder: (context) => CircleMapPage(),
            ));
        break;
      case 4:
        Navigator.push(
            context,
            MaterialPageRoute(
              builder: (context) => PaddingTest(),
            ));
        break;
      case 5:
        Navigator.push(
            context,
            MaterialPageRoute(
              builder: (_) => PolygonMap(),
            ));
        break;
      case 6:
        Navigator.push(
          context,
          MaterialPageRoute(
            builder: (_) => TextFieldPage(),
          ));
    }
  }
}

원천: https://pub.dev/packages/naver_map_plugin