프로젝트들/날씨앱

[날씨앱] P2. Flutter Naver Maps 추가

Choi Jaekuk 2023. 3. 29. 17:06

https://github.com/cjk09083/ftweather

이전 포스트에서 Provider 라이브러리 추가 및 빌드를 성공하였다.

이번엔 Flutter 앱에 Naver maps를 추가하고 현재위치를 마커로 나타내보자.

 

기존에 사용하면 naver map 라이브러리 (https://github.com/LBSTECH/naver_map_plugin) 가 지원이 중단돼 새로운 라이브러리를 찾아보니 https://pub.dev/packages/flutter_naver_map 라이브러리가 개발중이였다.

 

다만 아직 베타버전이기 때문에 1.0 버전이 정식 출시되면 이전하도록 하고 이번 포스팅에선 기존 라이브러리 (LBSTECH)를 사용하였다.


1. 먼저 pubspec.yaml에 Dependencies 를 추가해준다.

 

dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^1.0.2
  provider: ^6.0.5
  naver_map_plugin:
    git: https://github.com/LBSTECH/naver_map_plugin.git

 

2. Naver Cloud (https://console.ncloud.com/naver-service/application) 에서 앱 등록후 Client ID 생성

 

3. AndroidManifest.xml에 권한, client ID 추가

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

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

(https://wikidocs.net/168854 를 참고하여 client id가 github에 올라가지 않도록 조치)

 

4. iOS 설정

# info.plist 추가
<key>NMFClientId</key>
<string>$(NAVER_MAP_KEY)</string>
<key>io.flutter.embedded_views_preview</key>
<string>YES</string>
<key>NSAppTransportSecurity</key>
<dict>
  <key>NSAllowsArbitraryLoads</key>
  <true/>
  <key>NSAllowsArbitraryLoadsInWebContent</key>
  <true/>
</dict>
<key>NSLocationWhenInUseUsageDescription</key>
<string>The app needs location permission</string>

위치권한을 얻어오기 위해 geolocator 패키지 사용

# pubspec.yaml
dependencies:
  geolocator: ^9.0.2


# main.dart
import 'package:geolocator/geolocator.dart';


Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await requestLocationPermission();
  runApp(MyApp());
}

/* MyApp 정의 이후*/

// 위치 서비스 권한 요청 함수
Future<void> requestLocationPermission() async {
  LocationPermission permission = await Geolocator.checkPermission();
  if (permission == LocationPermission.denied) {
    permission = await Geolocator.requestPermission();
    if (permission == LocationPermission.denied) {
      // 사용자가 위치 권한을 거부한 경우 처리
      return;
    }
  }

  if (permission == LocationPermission.deniedForever) {
    // 사용자가 위치 권한을 영구적으로 거부한 경우 처리
    return;
  }

  // 권한이 허용된 경우 처리
}

 

 

(https://ggasoon2.tistory.com/18 를 참고하여 client id가 github에 올라가지 않도록 조치
-> .xcconfig 파일을 생성후 기존 ios/Flutter 폴더내에 있는 Debug.xcconfig 에 include 추가)

#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"
#include "secret.xcconfig"

 

 

5. Home.dart 수정

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:naver_map_plugin/naver_map_plugin.dart';

import 'MyModel.dart';

class Home extends StatelessWidget {
  const Home({super.key});

  final CameraPosition _mapPosition = const CameraPosition(
    target: LatLng(37.5666805, 126.9784147),
    zoom: 15,
  );


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Flutter Weather App'),
      ),
      body: Center(
        child: NaverMap(
          mapType: MapType.Hybrid,
          initialCameraPosition: _mapPosition,
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          Provider.of<MyModel>(context, listen: false).addMarker();
        },
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

 

6. floatingButton을 누르면 현재 위치에 마커 추가가 되도록 수정

#Home.dart

import 'package:flutter/foundation.dart';
import 'package:naver_map_plugin/naver_map_plugin.dart';
import 'dart:developer';

class MyModel extends ChangeNotifier {
  final TAG = "ftweather";
  final CameraPosition _mapPosition = const CameraPosition(
    target: LatLng(37.5666805, 126.9784147),
    zoom: 15,
  );

  CameraPosition get mapPosition => _mapPosition;

  NaverMapController? _controller;

  final List<Marker> _markers = [];
  List<Marker> get markers => _markers;

  // NaverMapController 초기화
  void setController(NaverMapController controller) {
    _controller = controller;
  }

  Future<void> addMarker() async {
    log("$TAG : addMarker");

    if (_controller != null) {
      CameraPosition currentCameraPosition = await _controller!.getCameraPosition();
      log("$TAG : Pos $currentCameraPosition");
      // 현재 위치에 마커 추가
      final marker = Marker(
        markerId: _markers.length.toString(),
        position: currentCameraPosition.target,
      );

      _markers.add(marker);
    }

    notifyListeners();
  }

}
#MyModel.dart

import 'package:flutter/foundation.dart';
import 'package:naver_map_plugin/naver_map_plugin.dart';
import 'dart:developer';

class MyModel extends ChangeNotifier {
  final TAG = "ftweather"; // 로그 태그

  // 초기 카메라 위치 설정
  final CameraPosition _mapPosition = const CameraPosition(
    target: LatLng(37.5666805, 126.9784147),
    zoom: 15,
  );

  // 카메라 위치를 가져오는 getter
  CameraPosition get mapPosition => _mapPosition;

  // NaverMapController 변수
  NaverMapController? _controller;

  // 마커 목록 관리
  final List<Marker> _markers = [];
  List<Marker> get markers => _markers;

  // NaverMapController 초기화 메서드
  void setController(NaverMapController controller) {
    _controller = controller;
  }

  // 현재 위치에 마커를 추가하는 메서드
  Future<void> addMarker() async {
    // 로그 출력
    log("$TAG : addMarker");

    // NaverMapController가 초기화되었는지 확인
    if (_controller != null) {
      // 현재 카메라 위치 가져오기
      CameraPosition currentCameraPosition = await _controller!.getCameraPosition();
      // 로그 출력
      log("$TAG : Pos $currentCameraPosition");

      // 현재 위치에 마커 추가
      final marker = Marker(
        markerId: _markers.length.toString(),
        position: currentCameraPosition.target,
      );

      // 마커 목록에 추가
      _markers.add(marker);
    }

    // 마커가 추가되었음을 알림
    notifyListeners();
  }
}

 

 

 

7. 빌드시 아래와 같이 앱이 동작되고,  버튼을 누르면 지도 중심에 마커가 추가된다.