프로젝트/구글맵(안드로이드)

안드로이드로 구글맵 띄우고 마커표시, 마커클릭시 토스트 출력

2022. 12. 29. 06:30
글 목차


728x90

안드로이드 앱에서 구글맵을 띄우고 마커를 표시하고 그 마커를 클릭 시 토스트메세지를 출력하는 방법을 알아보자

 

그 차례는 아래와 같다.

1. 구글클라우드 설정
2. 안드로이드 환경 구축
2. 코드 작성

 

1. 구글클라우드 설정

a. 먼저 구글클라우드(https://cloud.google.com)에 개발자 계정으로 접속하여 콘솔에서 새로운 프로젝트를 만든다.

b. 구글 맵 sdk을 사용 설정 해준다.

c. 사용자 인증정보에서 api키를 발급한다 원래 키가 있다면 그걸 수정해도 되는 것 같다.

안드로이드 앱을 사용해 주고

패키지 이름은 내가 사용할 안드로이드 프로젝트의 패키지 이름을 적어준다.

SHA - 1 인증서 디지털 지문은 이렇게 얻는다.

cmd에서 안드로이드를 설치한 폴더아래 jre 폴더 아래 bin 폴더에서 keytool.exe를 실행한다.

그래서 keytool -list 어쩌고 하는 문장을 복사해서 실행해 준다. 그러면 SHA1로 인코딩된 키 값을 얻을 수 있다.

그럼 api키 발급은 끝이다.

 

2. 안드로이드 환경설정

프로젝트를 생성하고 난뒤

 

a. 모듈단위의 그래들 파일에 간다.

implementation 'com.google.android.gms:play-services-maps:18.1.0'

이 코드를 디펜던시에 추가한 후 Sync 해준다.

 

b. AndroidManifest.xml로 간다.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.GoogleMap"
        tools:targetApi="31">

        <meta-data
            android:name="com.google.android.geo.API_KEY"
            android:value="AOOOOOOOOOOOOOOOOOOOOOOOOOOOOOV1o" />

        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

            <meta-data
                android:name="android.app.lib_name"
                android:value="" />
        </activity>
    </application>

</manifest>

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

GPS나 네트워크를 통해 현재 위치를 받을 수 있도록 위치정보 권한을 얻을 수 있게 해준다.

 

<meta-data
            android:name="com.google.android.geo.API_KEY"
            android:value="AIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOojSvV1o" />

여기서 구글 맵 api에 접근하기 위한 키 정보를 입력한다 키는 발급받은 키를 이리저리 만저보면 API Key라는 곳에서 찾을 수 있다.

 

c. 다음으로 activity_main.xml에서 fragment 뷰를 추가해준다.

<fragment
    android:id="@+id/map"
    android:name="com.google.android.gms.maps.SupportMapFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

android:name만 잘 설정해주면 되는 듯하다.

 

3. 코드 작성

이제 MainActivity.java로 간다

package com.example.map;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import android.Manifest;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.widget.Toast;

import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;

public class MainActivity extends AppCompatActivity implements OnMapReadyCallback {

    private GoogleMap googleMap;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
        mapFragment.getMapAsync(this);
    }

    @Override
    public void onMapReady(@NonNull GoogleMap googleMap) {
        this.googleMap = googleMap;
        LatLng latLng = new LatLng(36.108516, 128.415172);
        googleMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
        googleMap.moveCamera(CameraUpdateFactory.zoomTo(15));
        MarkerOptions markerOptions = new MarkerOptions().position(latLng).title("싸피싸피");
        googleMap.addMarker(markerOptions);
        this.googleMap.setOnMarkerClickListener(markerClickListener);

        if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
            googleMap.setMyLocationEnabled(true);
        } else {
            checkLocationPermissionWithRationale();
        }
    }

    public static final int MY_PERMISSIONS_REQUEST_LOCATION = 99;

    private void checkLocationPermissionWithRationale() {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION)) {
                new AlertDialog.Builder(this)
                        .setTitle("위치정보")
                        .setMessage("접근을 허용해 이새끼야")
                        .setPositiveButton("확인이야", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                ActivityCompat.requestPermissions(MainActivity.this, new String[] {Manifest.permission.ACCESS_FINE_LOCATION}, MY_PERMISSIONS_REQUEST_LOCATION);
                            }
                        }).create().show();
            } else {
                ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.ACCESS_FINE_LOCATION}, MY_PERMISSIONS_REQUEST_LOCATION);
            }
        }
    }
    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case MY_PERMISSIONS_REQUEST_LOCATION: {
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
                        googleMap.setMyLocationEnabled(true);
                    }
                } else {
                    Toast.makeText(this, "permission denied", Toast.LENGTH_LONG).show();
                }
                return;
            }
        }
    }
    GoogleMap.OnMarkerClickListener markerClickListener = new GoogleMap.OnMarkerClickListener() {
        @Override
        public boolean onMarkerClick(@NonNull Marker marker) {
            String markerId = marker.getId();
            //선택한 타겟위치
            LatLng location = marker.getPosition();
            Toast.makeText(MainActivity.this, "마커 클릭 Marker ID : "+markerId+"("+location.latitude+" "+location.longitude+")", Toast.LENGTH_SHORT).show();
            return false;
        }
    };
}

fragment뷰의 android:name이 저 SupportMapFragment이다.

getSupportFragmentManager().findFragmentById(R.id.map);

를 통해 해당 뷰를 xml에서 찾아주고

찾은 SupportMapFragment 를 getMapAsync메서드로 씽크시키고 콜백 메서드를 호출한다 

콜백메서드는 MainActivity가 OnMapReadyCallback 인터페이스를 implements 하여 override를 통해 구현한다. 그 구현하는 메서는 onMapReady이다

@Override
public void onMapReady(@NonNull GoogleMap googleMap) {
    this.googleMap = googleMap;
    LatLng latLng = new LatLng(36.108516, 128.415172);
    googleMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
    googleMap.moveCamera(CameraUpdateFactory.zoomTo(15));
    MarkerOptions markerOptions = new MarkerOptions().position(latLng).title("싸피싸피");
    googleMap.addMarker(markerOptions);
    this.googleMap.setOnMarkerClickListener(markerClickListener);

    if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
        googleMap.setMyLocationEnabled(true);
    } else {
        checkLocationPermissionWithRationale();
    }
}

특히

if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
    googleMap.setMyLocationEnabled(true);
} else {
    checkLocationPermissionWithRationale();
}

이부분은 위치찾기 권한에 대해 퍼미션이 있으면 setMyLocationEnabled(true)를 호출하게 되어 있다.

checkLocationPermissionWithRationale()도 결국에 퍼미션을 허용하는 팝업을 띄우게 한후 setMyLocationEnabled(true)호출하기 위한 것이다.

public static final int MY_PERMISSIONS_REQUEST_LOCATION = 99;

private void checkLocationPermissionWithRationale() {
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION)) {
            new AlertDialog.Builder(this)
                    .setTitle("위치정보")
                    .setMessage("접근을 허용해 이새끼야")
                    .setPositiveButton("확인이야", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            ActivityCompat.requestPermissions(MainActivity.this, new String[] {Manifest.permission.ACCESS_FINE_LOCATION}, MY_PERMISSIONS_REQUEST_LOCATION);
                        }
                    }).create().show();
        } else {
            ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.ACCESS_FINE_LOCATION}, MY_PERMISSIONS_REQUEST_LOCATION);
        }
    }
}

if 두개를 설명하자면 이 앱에 위치권한이 있는지 파악한 후(1) 앱이 명시적으로 사용자에 의해 위치권한 얻기가 거부당했다면(2) 내부 코드를 실행하는 코드다.

AlertDialog를 만들어서 실행 해 준다.

else문에 ActivityCompat.requestPermissions메서드는 클래스가 extends하는 AppCompatActivity가 상속하는 수많은 메서드중 하나인 onRequestPermissionsResult를 통해 조작 할 수 있는거 같다.

그래서 reqeustCode가 requestPermissions에서 보내는 코드값과 같다면 뭔가를 실행해 주는 문장이 있다.

@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode) {
        case MY_PERMISSIONS_REQUEST_LOCATION: {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
                    googleMap.setMyLocationEnabled(true);
                }
            } else {
                Toast.makeText(this, "permission denied", Toast.LENGTH_LONG).show();
            }
            return;
        }
    }
}
GoogleMap.OnMarkerClickListener markerClickListener = new GoogleMap.OnMarkerClickListener() {
    @Override
    public boolean onMarkerClick(@NonNull Marker marker) {
        String markerId = marker.getId();
        //선택한 타겟위치
        LatLng location = marker.getPosition();
        Toast.makeText(MainActivity.this, "마커 클릭 Marker ID : "+markerId+"("+location.latitude+" "+location.longitude+")", Toast.LENGTH_SHORT).show();
        return false;
    }
};

 

마지막으로 이 메서드는 마커를 클릭했을 때 어떻게 나와야 하는지 재정의하고 있다.

 

앱이 실행되는 모양이다.

728x90
안드로이드로 구글맵 띄우고 마커표시, 마커클릭시 토스트 출력