새 Places SDK 클라이언트로 마이그레이션

이 가이드에서는 장소 호환성 라이브러리와 새로운 독립형 버전의 Places SDK for Android 간의 변경사항을 설명합니다. Android용 Places SDK의 새로운 독립형 버전으로 이전하는 대신 Places 호환성 라이브러리를 사용하고 있다면 이 가이드에서 Android용 Places SDK의 새 버전을 사용하도록 프로젝트를 업데이트하는 방법을 알아보세요.

Android용 Places SDK 버전 2.6.0 이상에서 기능과 버그 수정에 액세스하는 유일한 방법은 Android용 Places SDK를 사용하는 것입니다. 최대한 빨리 호환성 라이브러리에서 Android용 새 Places SDK 버전으로 업데이트하는 것이 좋습니다.

변경사항

주요 변경사항은 다음과 같습니다.

  • Android용 Places SDK의 새 버전은 정적 클라이언트 라이브러리로 배포됩니다. 2019년 1월 이전에는 Android용 Places SDK가 Google Play 서비스를 통해 제공되었습니다. 그 이후로 새로운 Android용 Places SDK로의 전환을 용이하게 하기 위해 장소 호환성 라이브러리가 제공되었습니다.
  • 새로운 메서드가 있습니다.
  • 이제 장소 세부정보를 반환하는 메서드에서 필드 마스크가 지원됩니다. 필드 마스크를 사용하여 반환할 장소 데이터 유형을 지정할 수 있습니다.
  • 오류를 보고하는 데 사용되는 상태 코드가 개선되었습니다.
  • 이제 자동 완성에서 세션 토큰을 지원합니다.
  • 장소 선택 도구는 더 이상 사용할 수 없습니다.

장소 호환성 라이브러리 정보

2019년 1월에 Android용 독립형 Places SDK 버전 1.0이 출시되면서 Google은 지원 중단된 Android용 Places SDK의 Google Play 서비스 버전(com.google.android.gms:play-services-places)에서 이전하는 데 도움이 되는 호환성 라이브러리를 제공했습니다.

이 호환성 라이브러리는 개발자가 독립형 SDK에서 새 이름을 사용하도록 코드를 이전할 때까지 Google Play 서비스 버전을 대상으로 하는 API 호출을 새 독립형 버전으로 리디렉션하고 변환하기 위해 일시적으로 제공되었습니다. 버전 1.0부터 버전 2.6.0까지 출시된 Android용 Places SDK의 각 버전에는 이에 상응하는 기능을 제공하기 위해 장소 호환성 라이브러리의 해당 버전이 출시되었습니다.

장소 호환성 라이브러리 동결 및 지원 중단

Android용 Places SDK 호환성 라이브러리의 모든 버전은 2022년 3월 31일부로 지원 중단되었습니다. 버전 2.6.0은 장소 호환성 라이브러리의 마지막 버전입니다. Android용 Places SDK 버전 2.6.0 이상에서 기능과 버그 수정에 액세스하는 유일한 방법은 Android용 Places SDK를 사용하는 것입니다.

버전 2.6.0 이상의 출시에서 제공되는 새로운 기능과 중요한 버그 수정에 액세스하려면 Android용 Places SDK로 이전하는 것이 좋습니다. 현재 호환성 라이브러리를 사용 중인 경우 Android용 Places SDK 설치 섹션의 아래 단계에 따라 Android용 Places SDK로 이전하세요.

클라이언트 라이브러리 설치

Android용 Places SDK의 새 버전은 정적 클라이언트 라이브러리로 배포됩니다.

Maven을 사용하여 Android용 Places SDK를 Android 스튜디오 프로젝트에 추가합니다.

  1. 현재 장소 호환성 라이브러리를 사용 중인 경우:

    1. dependencies 섹션에서 다음 줄을 바꿉니다.

          implementation 'com.google.android.libraries.places:places-compat:X.Y.Z'

      다음 줄을 사용하여 Android용 Places SDK로 전환합니다.

          implementation 'com.google.android.libraries.places:places:3.3.0'

  2. 현재 Android용 Places SDK의 Play 서비스 버전을 사용 중인 경우:

    1. dependencies 섹션에서 다음 줄을 바꿉니다.

          implementation 'com.google.android.gms:play-services-places:X.Y.Z'

      다음 줄을 사용하여 Android용 Places SDK로 전환합니다.

          implementation 'com.google.android.libraries.places:places:3.3.0'

  3. Gradle 프로젝트를 동기화합니다.

  4. 애플리케이션 프로젝트의 minSdkVersion16 이상으로 설정합니다.

  5. 'Google 지원' 저작물을 업데이트합니다.

    @drawable/powered_by_google_light // OLD
    @drawable/places_powered_by_google_light // NEW
    @drawable/powered_by_google_dark // OLD
    @drawable/places_powered_by_google_dark // NEW
    
  6. 앱을 빌드합니다. Android용 Places SDK로 전환하여 빌드 오류가 발생하면 아래 섹션에서 이러한 오류를 해결하는 방법을 확인하세요.

새 Places SDK 클라이언트 초기화

다음 예와 같이 새 Places SDK 클라이언트를 초기화합니다.

// Add an import statement for the client library.
import com.google.android.libraries.places.api.Places;

...

// Initialize Places.
Places.initialize(getApplicationContext(), apiKey);

// Create a new Places client instance.
PlacesClient placesClient = Places.createClient(this);

상태 코드

QPS 한도 오류의 상태 코드가 변경되었습니다. 이제 QPS 한도 오류가 PlaceStatusCodes.OVER_QUERY_LIMIT를 통해 반환됩니다. 더 이상 QPD 한도가 없습니다.

다음 상태 코드가 추가되었습니다.

  • REQUEST_DENIED - 요청이 거부되었습니다. 여기에는 다음과 같은 여러 이유가 있을 수 있습니다.

    • API 키가 제공되지 않았습니다.
    • 잘못된 API 키가 제공되었습니다.
    • Cloud 콘솔에서 Places API가 사용 설정되지 않았습니다.
    • API 키에 잘못된 키 제한이 적용되었습니다.
  • INVALID_REQUEST - 인수가 누락되었거나 잘못되어 요청이 유효하지 않습니다.

  • NOT_FOUND: 지정된 요청에 대한 결과를 찾을 수 없습니다.

새로운 메서드

Android용 Places SDK의 새 버전에는 일관성을 위해 설계된 완전히 새로운 메서드가 도입되었습니다. 모든 새 메서드는 다음을 준수합니다.

  • 엔드포인트는 더 이상 get 동사를 사용하지 않습니다.
  • 요청 및 응답 객체는 해당 클라이언트 메서드와 동일한 이름을 공유합니다.
  • 이제 요청 객체에 빌더가 있습니다. 필수 매개변수는 요청 빌더 매개변수로 전달됩니다.
  • 버퍼는 더 이상 사용되지 않습니다.

이 섹션에서는 새로운 메서드를 소개하고 작동 방식을 보여줍니다.

ID로 장소 가져오기

fetchPlace()을 사용하여 특정 장소에 관한 세부정보를 가져옵니다. fetchPlace()getPlaceById()와 유사하게 작동합니다.

장소를 가져오려면 다음 단계를 따르세요.

  1. fetchPlace()를 호출하여 장소 ID를 지정하는 FetchPlaceRequest 객체와 반환할 장소 데이터를 지정하는 필드 목록을 전달합니다.

    // Define a Place ID.
    String placeId = "INSERT_PLACE_ID_HERE";
    
    // Specify the fields to return.
    List<Place.Field> placeFields = Arrays.asList(Place.Field.ID, Place.Field.DISPLAY_NAME);
    
    // Construct a request object, passing the place ID and fields array.
    FetchPlaceRequest request = FetchPlaceRequest.builder(placeId, placeFields)
            .build();
    
    
  2. addOnSuccessListener()를 호출하여 FetchPlaceResponse를 처리합니다. 단일 Place 결과가 반환됩니다.

    // Add a listener to handle the response.
    placesClient.fetchPlace(request).addOnSuccessListener((response) -> {
      Place place = response.getPlace();
      Log.i(TAG, "Place found: " + place.getName());
    }).addOnFailureListener((exception) -> {
        if (exception instanceof ApiException) {
            ApiException apiException = (ApiException) exception;
            int statusCode = apiException.getStatusCode();
            // Handle error with given status code.
            Log.e(TAG, "Place not found: " + exception.getMessage());
        }
    });
    

장소 사진 가져오기

fetchPhoto()를 사용하여 장소 사진을 가져옵니다. fetchPhoto()는 장소의 사진을 반환합니다. 사진 요청 패턴이 간소화되었습니다. 이제 Place 객체에서 직접 PhotoMetadata를 요청할 수 있습니다. 더 이상 별도의 요청이 필요하지 않습니다. 사진의 최대 너비 또는 높이는 1,600픽셀입니다. fetchPhoto()getPhoto()와 유사하게 작동합니다.

장소 사진을 가져오려면 다음 단계를 따르세요.

  1. fetchPlace() 호출을 설정합니다. 요청에 PHOTO_METADATAS 필드를 포함해야 합니다.

    List<Place.Field> fields = Arrays.asList(Place.Field.PHOTO_METADATAS);
    
  2. 장소 객체를 가져옵니다 (이 예에서는 fetchPlace()를 사용하지만 findCurrentPlace()를 사용할 수도 있음).

    FetchPlaceRequest placeRequest = FetchPlaceRequest.builder(placeId, fields).build();
    
  3. OnSuccessListener를 추가하여 FetchPlaceResponse의 결과 Place에서 사진 메타데이터를 가져온 다음, 결과 사진 메타데이터를 사용하여 비트맵과 저작자 표시 텍스트를 가져옵니다.

    placesClient.fetchPlace(placeRequest).addOnSuccessListener((response) -> {
        Place place = response.getPlace();
    
        // Get the photo metadata.
        PhotoMetadata photoMetadata = place.getPhotoMetadatas().get(0);
    
        // Get the attribution text.
        String attributions = photoMetadata.getAttributions();
    
        // Create a FetchPhotoRequest.
        FetchPhotoRequest photoRequest = FetchPhotoRequest.builder(photoMetadata)
                .setMaxWidth(500) // Optional.
                .setMaxHeight(300) // Optional.
                .build();
        placesClient.fetchPhoto(photoRequest).addOnSuccessListener((fetchPhotoResponse) -> {
            Bitmap bitmap = fetchPhotoResponse.getBitmap();
            imageView.setImageBitmap(bitmap);
        }).addOnFailureListener((exception) -> {
            if (exception instanceof ApiException) {
                ApiException apiException = (ApiException) exception;
                int statusCode = apiException.getStatusCode();
                // Handle error with given status code.
                Log.e(TAG, "Place not found: " + exception.getMessage());
            }
        });
    });
    

사용자의 위치에서 장소 찾기

findCurrentPlace()를 사용하여 사용자 기기의 현재 위치를 찾습니다. findCurrentPlace()는 사용자의 기기가 있을만한 장소를 나타내는 PlaceLikelihood 목록을 반환합니다. findCurrentPlace()getCurrentPlace()와 유사하게 작동합니다.

사용자 기기의 현재 위치를 가져오려면 다음 단계를 따르세요.

  1. 앱이 ACCESS_FINE_LOCATIONACCESS_WIFI_STATE 권한을 요청하는지 확인합니다. 사용자는 현재 기기 위치에 액세스할 수 있는 권한을 부여해야 합니다. 자세한 내용은 앱 권한 요청을 참고하세요.

  2. 반환할 장소 데이터 유형 목록을 포함하는 FindCurrentPlaceRequest를 만듭니다.

      // Use fields to define the data types to return.
      List<Place.Field> placeFields = Arrays.asList(Place.Field.DISPLAY_NAME);
    
      // Use the builder to create a FindCurrentPlaceRequest.
      FindCurrentPlaceRequest request =
              FindCurrentPlaceRequest.builder(placeFields).build();
    
  3. findCurrentPlace를 호출하고 응답을 처리합니다. 먼저 사용자가 기기 위치 사용 권한을 부여했는지 확인합니다.

      // Call findCurrentPlace and handle the response (first check that the user has granted permission).
      if (ContextCompat.checkSelfPermission(this, ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
          placesClient.findCurrentPlace(request).addOnSuccessListener(((response) -> {
              for (PlaceLikelihood placeLikelihood : response.getPlaceLikelihoods()) {
                  Log.i(TAG, String.format("Place '%s' has likelihood: %f",
                          placeLikelihood.getPlace().getName(),
                          placeLikelihood.getLikelihood()));
                  textView.append(String.format("Place '%s' has likelihood: %f\n",
                          placeLikelihood.getPlace().getName(),
                          placeLikelihood.getLikelihood()));
              }
          })).addOnFailureListener((exception) -> {
              if (exception instanceof ApiException) {
                  ApiException apiException = (ApiException) exception;
                  Log.e(TAG, "Place not found: " + apiException.getStatusCode());
              }
          });
      } else {
          // A local method to request required permissions;
          // See https://developer.android.com/training/permissions/requesting
          getLocationPermission();
      }
    

자동 완성 예상 검색어 찾기

findAutocompletePredictions()를 사용하여 사용자 검색어에 대한 응답으로 장소 예상 검색어를 반환합니다. findAutocompletePredictions()getAutocompletePredictions()와 유사하게 작동합니다.

다음은 findAutocompletePredictions()를 호출하는 예를 보여줍니다.

// Create a new token for the autocomplete session. Pass this to FindAutocompletePredictionsRequest,
// and once again when the user makes a selection (for example when calling fetchPlace()).
AutocompleteSessionToken token = AutocompleteSessionToken.newInstance();
// Create a RectangularBounds object.
RectangularBounds bounds = RectangularBounds.newInstance(
  new LatLng(-33.880490, 151.184363),
  new LatLng(-33.858754, 151.229596));
// Use the builder to create a FindAutocompletePredictionsRequest.
FindAutocompletePredictionsRequest request = FindAutocompletePredictionsRequest.builder()
// Call either setLocationBias() OR setLocationRestriction().
   .setLocationBias(bounds)
   //.setLocationRestriction(bounds)
   .setCountry("au")
   .setTypesFilter(Arrays.asList(PlaceTypes.ADDRESS))
   .setSessionToken(token)
   .setQuery(query)
   .build();

placesClient.findAutocompletePredictions(request).addOnSuccessListener((response) -> {
   for (AutocompletePrediction prediction : response.getAutocompletePredictions()) {
       Log.i(TAG, prediction.getPlaceId());
       Log.i(TAG, prediction.getPrimaryText(null).toString());
   }
}).addOnFailureListener((exception) -> {
   if (exception instanceof ApiException) {
       ApiException apiException = (ApiException) exception;
       Log.e(TAG, "Place not found: " + apiException.getStatusCode());
   }
});

세션 토큰

세션 토큰은 사용자 검색의 쿼리 및 선택 단계를 결제 목적의 개별 세션으로 그룹화합니다. 모든 자동 완성 세션에 세션 토큰을 사용하는 것이 좋습니다. 세션은 사용자가 쿼리를 입력하기 시작하면 시작되고 장소를 선택하면 종료됩니다. 세션마다 여러 개의 쿼리가 포함될 수 있으며 하나의 장소가 선택됩니다. 세션이 종료되면 토큰이 더 이상 유효하지 않습니다. 앱은 각 세션에 대해 새 토큰을 생성해야 합니다.

필드 마스크

장소 세부정보를 반환하는 메서드에서는 각 요청과 함께 반환할 장소 데이터 유형을 지정해야 합니다. 이렇게 하면 실제로 사용할 데이터만 요청하고 비용을 지불할 수 있습니다.

반환할 데이터 유형을 지정하려면 다음 예와 같이 FetchPlaceRequestPlace.Field 배열을 전달합니다.

// Include address, ID, and phone number.
List<Place.Field> placeFields = Arrays.asList(Place.Field.FORMATTED_ADDRESS,
                                              Place.Field.ID,
                                              Place.Field.INTERNATIONAL_PHONE_NUMBER);

필드 마스크에 사용할 수 있는 필드 목록은 장소 데이터 필드 (신규) 를 참고하세요.

Places Data SKU에 대해 자세히 알아보세요.

장소 선택기 및 자동 완성 업데이트

이 섹션에서는 장소 위젯 (장소 선택기 및 자동 완성)의 변경사항을 설명합니다.

프로그래매틱 자동 완성

autocomplete가 다음과 같이 변경되었습니다.

  • PlaceAutocomplete에서 Autocomplete로 이름이 변경되었습니다.
    • PlaceAutocomplete.getPlace에서 Autocomplete.getPlaceFromIntent로 이름이 변경되었습니다.
    • PlaceAutocomplete.getStatus에서 Autocomplete.getStatusFromIntent로 이름이 변경되었습니다.
  • PlaceAutocomplete.RESULT_ERROR의 이름이 AutocompleteActivity.RESULT_ERROR로 변경되었습니다(자동 완성 프래그먼트의 오류 처리는 변경되지 않음).

장소 선택기

장소 선택 도구는 2019년 1월 29일에 지원 중단되었습니다. 2019년 7월 29일에 사용 중지되었으며 더 이상 사용할 수 없습니다. 계속 사용하면 오류 메시지가 표시됩니다. 새 SDK는 장소 선택 도구를 지원하지 않습니다.

자동 완성 위젯

자동 완성 위젯이 업데이트되었습니다.

  • Place 접두사가 모든 클래스에서 삭제되었습니다.
  • 세션 토큰 지원을 추가했습니다. 위젯은 백그라운드에서 자동으로 토큰을 관리합니다.
  • 사용자가 선택한 후 반환할 장소 데이터 유형을 선택할 수 있는 필드 마스크 지원이 추가되었습니다.

다음 섹션에서는 프로젝트에 자동 완성 위젯을 추가하는 방법을 보여줍니다.

AutocompleteFragment 삽입

자동 완성 프래그먼트를 추가하려면 다음 단계를 따르세요.

  1. 다음 예와 같이 활동의 XML 레이아웃에 프래그먼트를 추가합니다.

    <fragment
      android:id="@+id/autocomplete_fragment"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:name=
    "com.google.android.libraries.places.widget.AutocompleteSupportFragment"
      />
    
  2. 활동에 자동 완성 위젯을 추가하려면 다음 단계를 따르세요.

    • 애플리케이션 컨텍스트와 API 키를 전달하여 Places를 초기화합니다.
    • AutocompleteSupportFragment를 초기화합니다.
    • setPlaceFields()를 호출하여 가져올 장소 데이터 유형을 나타냅니다.
    • 결과로 작업을 실행하고 발생할 수 있는 오류를 처리하는 PlaceSelectionListener를 추가합니다.

    다음 예는 활동에 자동 완성 위젯을 추가하는 방법을 보여줍니다.

    /**
     * Initialize Places. For simplicity, the API key is hard-coded. In a production
     * environment we recommend using a secure mechanism to manage API keys.
     */
    if (!Places.isInitialized()) {
        Places.initialize(getApplicationContext(), "YOUR_API_KEY");
    }
    
    // Initialize the AutocompleteSupportFragment.
    AutocompleteSupportFragment autocompleteFragment = (AutocompleteSupportFragment)
            getSupportFragmentManager().findFragmentById(R.id.autocomplete_fragment);
    
    autocompleteFragment.setPlaceFields(Arrays.asList(Place.Field.ID, Place.Field.DISPLAY_NAME));
    
    autocompleteFragment.setOnPlaceSelectedListener(new PlaceSelectionListener() {
        @Override
        public void onPlaceSelected(Place place) {
            // TODO: Get info about the selected place.
            Log.i(TAG, "Place: " + place.getName() + ", " + place.getId());
        }
    
        @Override
        public void onError(Status status) {
            // TODO: Handle the error.
            Log.i(TAG, "An error occurred: " + status);
        }
    });
    

인텐트를 사용하여 자동 완성 활동 실행

  1. 앱 컨텍스트 및 API 키를 전달하여 Places 초기화
  2. Autocomplete.IntentBuilder를 사용하여 인텐트를 만들고 원하는 PlaceAutocomplete 모드 (전체 화면 또는 오버레이)를 전달합니다. 인텐트는 startActivityForResult를 호출해야 하며, 이 인텐트를 식별하는 요청 코드를 전달해야 합니다.
  3. 선택한 장소를 수신하도록 onActivityResult 콜백을 재정의합니다.

다음 예에서는 인텐트를 사용하여 자동 완성을 실행한 다음 결과를 처리하는 방법을 보여줍니다.

    /**
     * Initialize Places. For simplicity, the API key is hard-coded. In a production
     * environment we recommend using a secure mechanism to manage API keys.
     */
    if (!Places.isInitialized()) {
        Places.initialize(getApplicationContext(), "YOUR_API_KEY");
    }

    ...

    // Set the fields to specify which types of place data to return.
    List<Place.Field> fields = Arrays.asList(Place.Field.ID, Place.Field.DISPLAY_NAME);

    // Start the autocomplete intent.
    Intent intent = new Autocomplete.IntentBuilder(
            AutocompleteActivityMode.FULLSCREEN, fields)
            .build(this);
    startActivityForResult(intent, AUTOCOMPLETE_REQUEST_CODE);

    ...

    /**
     * Override the activity's onActivityResult(), check the request code, and
     * do something with the returned place data (in this example its place name and place ID).
     */
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == AUTOCOMPLETE_REQUEST_CODE) {
            if (resultCode == RESULT_OK) {
                Place place = Autocomplete.getPlaceFromIntent(data);
                Log.i(TAG, "Place: " + place.getName() + ", " + place.getId());
            } else if (resultCode == AutocompleteActivity.RESULT_ERROR) {
                // TODO: Handle the error.
                Status status = Autocomplete.getStatusFromIntent(data);
                Log.i(TAG, status.getStatusMessage());
            } else if (resultCode == RESULT_CANCELED) {
                // The user canceled the operation.
            }
        }
    }

장소 선택 도구를 더 이상 사용할 수 없음

장소 선택 도구는 2019년 1월 29일에 지원 중단되었습니다. 2019년 7월 29일에 사용 중지되었으며 더 이상 사용할 수 없습니다. 계속 사용하면 오류 메시지가 표시됩니다. 새 SDK는 장소 선택 도구를 지원하지 않습니다.