안드로이드 앱에서 구글맵을 띄우고 마커를 표시하고 그 마커를 클릭 시 토스트메세지를 출력하는 방법을 알아보자
그 차례는 아래와 같다.
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;
}
};
마지막으로 이 메서드는 마커를 클릭했을 때 어떻게 나와야 하는지 재정의하고 있다.
앱이 실행되는 모양이다.