반응형

Places API Web Service를 이용하여 현재 위치 주변의 음식점 정보를 안드로이드의 구글맵에 표시하는 내용을 다룹니다.



Google Maps Android API를 사용하는 방법과  FusedLocationProviderClient 를 이용하여 현재 위치를 구글맵에 표시하는 내용을 다음 두 포스팅에서 다루었습니다.

중복된 내용은 빠져있기 때문에 본 포스팅에 있는 내용을 진행하기 전에 미리 검토해보세요..

 

Google Maps SDK for Android 사용방법 및 예제

https://webnautes.tistory.com/2050 

 

Android Google Map에 현재 위치 표시하기( FusedLocationProviderClient 사용)

https://webnautes.tistory.com/2051 




 2016.12. 4

 2017.11.27  주변 장소의 주소가 한글로 나오도록 수정

 2018. 6. 13 

 2019. 7. 19  FusedLocationProviderClient 사용하도록 수정

 2019. 8. 15  androidx,SupportMapFragment 사용하도록 수정

 2020. 6. 21 문제 발생시 추가

 2020. 9. 13 테스트 및 수정 (  Android Studio 4.0.1, Android 11.0  API 30 )

 2021. 5. 11 테스트 및 수정 (  Android Studio 4.1.3, Android 11.0  API 30 )

2022. 6. 18 라이브러리 인식 안되던 문제 해결





1. Places API Web Service 키 얻기

2. Google Map에 현재 위치 주변의 음식점 표시하기

3. 실행 결과

4. 구현시 참고




1. Places API Web Service 키 얻기

현재 위치 주변에 있는 장소를 종류별로 검색하는 기능을 Google Places API for Android에서는 아직 제공하지 않기 때문에 Places API Web Service를 사용합니다.



1. 1. Google Developers Console 사이트 (https://console.developers.google.com/apis/dashboard )에 접속합니다. 



앞에서 Google Map을 위해 생성했던 프로젝트를 선택한 상태에서 진행해야 합니다. 




2. API에 마우스 커서를 가져가면 보이는 메뉴에서 라이브러리를 선택합니다. 

 




3. place api를 검색하여 Places API를 선택합니다.

 



4. 사용을 클릭합니다.

 



5. 왼쪽에 마우스 커서를 가져가면 보이는 메뉴에서 사용자 인증 정보를 클릭합니다.

 



6. 사용자 인증 정보 만들기를 클릭하고 메뉴에서 API 키를 선택합니다. 

 



7. 생성된 API 키를 복사해두고  닫기를 클릭합니다. 

 



2. Google Map에 현재 위치 주변의 음식점 표시하기

Places API Web Service에서 제공하는 REST API를 사용하여 현재 위치 주변의 음식점에 대한 정보를 요청하여 획득된 JSON을 파싱하는 작업을 해주면  되지만 여기에서는 간단하게 구현이 가능한 Android-Google-Places-API 라이브러리(https://github.com/nomanr/Android-Google-Places-API)를 사용했습니다.



다음 포스팅에 있는 코드를 기반으로 수정하는 방법을 설명합니다.

 

Android Google Map에 현재 위치 표시하기( FusedLocationProviderClient 사용)

https://webnautes.tistory.com/1249 



settings.gradle에 다음 코드를 추가합니다. 

t_Haru 님이 댓글로 알려주셔서 반영했습니다. 

 



pluginManagement {
    repositories {
        gradlePluginPortal()
        google()
        mavenCentral()
        maven {
            url 'https://maven.google.com'
        }
        jcenter()
        maven { url 'https://maven.fabric.io/public' }
    }
}
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
        maven {
            url 'https://maven.google.com'
        }
        jcenter()
        maven { url 'https://maven.fabric.io/public' }
    }
}
rootProject.name = "Google Maps Android API Example"
include ':app'




레이아웃 파일( activity_main.xml )에 버튼을 추가하고 android:layout_weight 속성으로 화면에 보이는 지도와 버튼의 높이를 조정합니다. 



<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/layout_main"
    android:orientation="vertical"
    tools:context=".MainActivity" >

    <fragment
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="0.8"
        android:id="@+id/map"
        tools:context=".MapsActivity"
        android:name="com.google.android.gms.maps.SupportMapFragment" />

    <Button
        android:text="장소검색"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="0.2"
        android:id="@+id/button"/>

</LinearLayout>




app 모듈을 위한 build.gradle 파일에서  minSdkVersion15 이상으로 사용해야 합니다. 

 



Android-Google-Places-API 라이브러리를 추가해줍니다.  글 작성시점에서  최신 버전은 1.1.3입니다.

변경된 사항을 반영해주기 위해 상단 우측에 보이는  Sync Now를 클릭합니다.

 

implementation 'noman.placesapi:placesAPI:1.1.3'

 



메니패스트 파일(AndroidManifest.xml)에서 <application> 태그의 allowBackup 속성을 false로 수정합니다.

 

 android:allowBackup="false"

 



MainActivity에서 PlacesListener 인터페이스를 구현해줘야 합니다.

PlacesListener를 추가해줍니다.

 

public class MainActivity extends AppCompatActivity
        implements
        OnMapReadyCallback,
        ActivityCompat.OnRequestPermissionsResultCallback,
        PlacesListener{




다음 다섯 줄을 추가해줍니다.

 

import noman.googleplaces.NRPlaces;
import noman.googleplaces.Place;
import noman.googleplaces.PlaceType;
import noman.googleplaces.PlacesException;
import noman.googleplaces.PlacesListener;



추가한 인터페이스에서 요구하는 다음 4개의 메소드를 추가해줍니다.

 

@Override
public void onPlacesFailure(PlacesException e) {

}

@Override
public void onPlacesStart() {

}

@Override
public void onPlacesSuccess(List<Place> places) {

}

@Override
public void onPlacesFinished() {

}



필요한 변수를 추가해줍니다.

 

List<Marker> previous_marker = null;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);




onPlacesSuccess 메소드의 파라미터 타입에 final을 추가해주고 다음 코드를 입력합니다.

 

@Override
public void onPlacesSuccess(final List<Place> places) {

      runOnUiThread(new Runnable() {
            @Override
            public void run() {
                for (noman.googleplaces.Place place : places) {

                    LatLng latLng
                            = new LatLng(place.getLatitude()
                            , place.getLongitude());

                    String markerSnippet = getCurrentAddress(latLng);

                    MarkerOptions markerOptions = new MarkerOptions();
                    markerOptions.position(latLng);
                    markerOptions.title(place.getName());
                    markerOptions.snippet(markerSnippet);
                    Marker item = mMap.addMarker(markerOptions);
                    previous_marker.add(item);

                }

                //중복 마커 제거
                HashSet<Marker> hashSet = new HashSet<Marker>();
                hashSet.addAll(previous_marker);
                previous_marker.clear();
                previous_marker.addAll(hashSet);

            }
        });

}




showPlaceInformation() 메소드를 추가해줍니다. 

 "Places API Web Service 키" 부분에 따로 복사해둔 키를 입력하셔야 합니다.

 

public void showPlaceInformation(LatLng location)
{
mMap.clear();//지도 클리어

if (previous_marker != null)
previous_marker.clear();//지역정보 마커 클리어

new NRPlaces.Builder()
.listener(MainActivity.this)
.key("Places API Web Service 키")
.latlng(location.latitude, location.longitude)//현재 위치
.radius(500) //500 미터 내에서 검색
.type(PlaceType.RESTAURANT) //음식점
.build()
.execute();
}




onCreate 메소드에  ArrayList 초기화와 버튼 클릭시 showPlaceInformation() 메소드를 호출하는 코드를 추가합니다.

 

setContentView(R.layout.activity_main);


previous_marker = new ArrayList<Marker>();

Button button = (Button)findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showPlaceInformation(currentPosition);
}
});



3. 실행 결과

실행하면 현재 위치가 지도에 표시됩니다.

 

주변 영역이 많이 보이도록 지도의 줌을 적당하게 조정한 후,  장소 검색 버튼을 누르면 현재 위치 주변의 음식점 위치들이 지도에 표시됩니다.

 

결과를 가져오는데 좀 시간이 걸립니다. 

 




음식점 위치를 표시하는 마커 하나를 선택하면 음식점 이름과 주소가 나타납니다.

장소 검색버튼을 다시 누르면 기존 마커들을 다지우고 새로 음식점 마커들을 표시합니다.

 



4. 구현시 참고

https://developers.google.com/places/web-service/supported_types?hl=ko 에 있는 Places API Web Service에서 지원되는 장소 유형을  Android-Google-Places-API 라이브러리에서 다음처럼 정의해놓고 있습니다. 

package noman.googleplaces;

/**
* Created by Noman on 8/25/2016.
* https://developers.google.com/places/supported_types
*/
public interface PlaceType {
    public String ACCOUNTING = "accounting";
    public String AIRPORT = "airport";
    public String AMUSEMENT_PARK = "amusement_park";
    public String AQUARIUM = "aquarium";
    public String ART_GALLERY = "art_gallery";
    public String ATM = "atm";
    public String BAKERY = "bakery";
    public String BANK = "bank";
    public String BAR = "bar";
    public String BEAUTY_SALON = "beauty_salon";
    public String BICYCLE_STORE = "bicycle_store";
    public String BOOK_STORE = "book_store";
    public String BOWLING_ALLEY = "bowling_alley";
    public String BUS_STATION = "bus_station";
    public String CAFE = "cafe";
    public String CAMPGROUND = "campground";
    public String CAR_DEALER = "car_dealer";
    public String CAR_RENTAL = "car_rental";
    public String CAR_REPAIR = "car_repair";
    public String CAR_WASH = "car_wash";
    public String CASINO = "casino";
    public String CEMETERY = "cemetery";
    public String CHURCH = "church";
    public String CITY_HALL = "city_hall";
    public String CLOTHING_STORE = "clothing_store";
    public String CONVENIENCE_STORE = "convenience_store";
    public String COURTHOUSE = "courthouse";
    public String DENTIST = "dentist";
    public String DEPARTMENT_STORE = "department_store";
    public String DOCTOR = "doctor";
    public String ELECTRICIAN = "electrician";
    public String ELECTRONICS_STORE = "electronics_store";
    public String EMBASSY = "embassy";
    public String FINANCE = "finance";
    public String FIRE_STATION = "fire_station";
    public String FLORIST = "florist";
    public String FUNERAL_HOME = "funeral_home";
    public String FURNITURE_STORE = "furniture_store";
    public String GAS_STATION = "gas_station";
    public String GYM = "gym";
    public String HAIR_CARE = "hair_care";
    public String HARDWARE_STORE = "hardware_store";
    public String HINDU_TEMPLE = "hindu_temple";
    public String HOME_GOODS_STORE = "home_goods_store";
    public String HOSPITAL = "hospital";
    public String INSURANCE_AGENCY = "insurance_agency";
    public String JEWELRY_STORE = "jewelry_store";
    public String LAUNDRY = "laundry";
    public String LAWYER = "lawyer";
    public String LIBRARY = "library";
    public String LIQUOR_STORE = "liquor_store";
    public String LOCAL_GOVERNMENT_OFFICE = "local_government_office";
    public String LOCKSMITH = "locksmith";
    public String LODGING = "lodging";
    public String MEAL_DELIVERY = "meal_delivery";
    public String MEAL_TAKEAWAY = "meal_takeaway";
    public String MOSQUE = "mosque";
    public String MOVIE_RENTAL = "movie_rental";
    public String MOVIE_THEATER = "movie_theater";
    public String MOVING_COMPANY = "moving_company";
    public String MUSEUM = "museum";
    public String NIGHT_CLUB = "night_club";
    public String PAINTER = "painter";
    public String PARK = "park";
    public String PARKING = "parking";
    public String PET_STORE = "pet_store";
    public String PHARMACY = "pharmacy";
    public String PHYSIOTHERAPIST = "physiotherapist";
    public String PLUMBER = "plumber";
    public String POLICE = "police";
    public String POST_OFFICE = "post_office";
    public String REAL_ESTATE_AGENCY = "real_estate_agency";
    public String RESTAURANT = "restaurant";
    public String ROOFING_CONTRACTOR = "roofing_contractor";
    public String RV_PARK = "rv_park";
    public String SCHOOL = "school";
    public String SHOE_STORE = "shoe_store";
    public String SHOPPING_MALL = "shopping_mall";
    public String SPA = "spa";
    public String STADIUM = "stadium";
    public String STORAGE = "storage";
    public String STORE = "store";
    public String SUBWAY_STATION = "subway_station";
    public String SYNAGOGUE = "synagogue";
    public String TAXI_STAND = "taxi_stand";
    public String TRAIN_STATION = "train_station";
    public String TRANSIT_STATION = "transit_station";
    public String TRAVEL_AGENCY = "travel_agency";
    public String UNIVERSITY = "university";
    public String VETERINARY_CARE = "veterinary_care";
    public String ZOO = "zoo";

}



showPlaceInformation() 메소드에서 PlaceType.RESTAURANT를 필요시 위에 나온 원하는 타입으로 바꾸시면 됩니다. 

 

 

.type(PlaceType.RESTAURANT)를 지우면 주변에 있는 모든 타입의 장소가 검색됩니다.



5. 문제 발생시

로그캣에서 Place API 관련 주소를 찾을 수 있습니다. 

해당 주소를 복사하여  웹브라우저에 붙여넣기 해보세요.



다음과 같은 에러가 발생한다면..

{

   "error_message" : "You must enable Billing on the Google Cloud Project at https://console.cloud.google.com/project/_/billing/enable Learn more at https://developers.google.com/maps/gmp-get-started",

   "html_attributions" : [],

   "results" : [],

   "status" : "REQUEST_DENIED"

}



구글 클라우드 플랫폼에서 다음처럼 결재 수단을 선택하여 

신용 카드 또는 체크 카드를 등록해야 정상적으로 주변 장소 정보를 받을 수 있습니다. 

 

 

반응형

문제 발생시 지나치지 마시고 댓글 남겨주시면 가능한 빨리 답장드립니다.

도움이 되셨다면 토스아이디로 후원해주세요.
https://toss.me/momo2024


제가 쓴 책도 한번 검토해보세요 ^^

+ Recent posts