新しい Places SDK クライアントへの移行

このガイドでは、プレイス互換性ライブラリと、Places SDK for Android の新しいスタンドアロン バージョンの変更点について説明します。このガイドでは、Places SDK for Android の新しいスタンドアロン バージョンに移行せずにプレイス互換性ライブラリを使用している場合に、プロジェクトをアップデートして Places SDK for Android の新しいバージョンを使用する方法について説明します。

バージョン 2.6.0 以降の Places SDK for Android の機能やバグの修正を利用するには、Places SDK for Android を使用する必要があります。できるだけ早く互換ライブラリを新しい Places SDK for Android バージョンに更新することをおすすめします。

変更内容

主な変更は次のとおりです。

  • Places SDK for Android の新しいバージョンは、静的クライアント ライブラリとして配布されています。2019 年 1 月より前は、Places SDK for Android は Google Play 開発者サービスを通じて公開されていました。それ以来、新しい Places SDK for Android への移行を容易にするために、プレイス互換性ライブラリが提供されています。
  • まったく新しいメソッドを利用できます。
  • Place Details を返すメソッドでフィールド マスクがサポートされるようになりました。フィールド マスクを使用して、返される場所データのタイプを指定できます。
  • エラーの報告に使用するステータス コードが改善されました。
  • 予測入力でセッション トークンがサポートされるようになりました。
  • Place Picker はご利用いただけなくなりました

プレイス互換性ライブラリについて

2019 年 1 月、スタンドアロンの Places SDK for Android バージョン 1.0 のリリースに伴い、Google は Places SDK for Android(com.google.android.gms:play-services-places)の廃止された Google Play 開発者サービス バージョンからの移行に役立つ互換性ライブラリを提供しました。

この互換性ライブラリは、デベロッパーがスタンドアロン SDK で新しい名前を使用するようにコードを移行できるようになるまで、Google Play 開発者サービス バージョンを対象とした API 呼び出しを新しいスタンドアロン バージョンにリダイレクトして変換するために一時的に提供されていました。バージョン 1.0 からバージョン 2.6.0 までにリリースされた Places SDK for Android の各バージョンでは、同等の機能を提供するプレイス互換性ライブラリの対応バージョンがリリースされています。

プレイス互換性ライブラリの凍結とサポート終了

Places SDK for Android の互換性ライブラリのすべてのバージョンは、2022 年 3 月 31 日をもって非推奨となりました。バージョン 2.6.0 は、プレイス互換性ライブラリの最終バージョンです。バージョン 2.6.0 以降の Places SDK for Android の機能やバグの修正を利用するには、Places SDK for Android を使用する必要があります。

バージョン 2.6.0 より上のリリースの新機能や重要なバグの修正を利用するために、Places SDK for Android に移行することをおすすめします。現在、互換性ライブラリを使用している場合は、以下の Places SDK for Android をインストールするセクションの手順に沿って、Places SDK for Android に移行してください。

クライアント ライブラリをインストールする

Places SDK for Android の新しいバージョンは、静的クライアント ライブラリとして配布されています。

Maven を使用して、Places SDK for Android を Android Studio プロジェクトに追加します。

  1. プレイス互換性ライブラリを現在ご使用の場合:

    1. dependencies セクションの次の行を置き換えます。

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

      次の行を使用して、Places SDK for Android に切り替えます。

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

  2. 現在、Places SDK for Android の Play 開発者サービス バージョンを使用している場合:

    1. dependencies セクションの次の行を置き換えます。

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

      次の行を使用して、Places SDK for Android に切り替えます。

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

  3. Gradle プロジェクトを同期します。

  4. アプリ プロジェクトの minSdkVersion16 以上に設定します。

  5. 「Powered by 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. アプリを作成します。Places SDK for Android に変換したためにビルドエラーが発生した場合は、以下のセクションでエラーの解決方法を確認してください。

新しい 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 - 指定されたリクエストの結果が見つからなかったことを示します。

新しいメソッド

新しいバージョンの Places SDK for Android では、整合性を重視して設計された、まったく新しいメソッドが導入されています。新しいメソッドはすべて次のルールに準拠しています。

  • エンドポイントでは 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.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_LOCATION 権限と ACCESS_WIFI_STATE 権限をリクエストしていることを確認します。ユーザーは、現在のデバイスの位置情報にアクセスする権限を付与する必要があります。詳しくは、アプリの権限をリクエストするをご覧ください。

  2. FindCurrentPlaceRequest を作成します。この中には、返される場所のデータタイプのリストを含めます。

      // Use fields to define the data types to return.
      List<Place.Field> placeFields = Arrays.asList(Place.Field.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());
   }
});

セッション トークン

セッション トークンは、ユーザー検索のクエリフェーズと選択フェーズを、請求処理のために個別のセッションにグループ化します。すべての予測入力セッションでセッション トークンを使用することをおすすめします。セッションはユーザーがクエリの入力を開始すると開始され、場所を選択すると終了します。各セッションには複数のクエリがあり、その後に 1 つの場所が選択されます。セッションが終了するとトークンは無効になるため、アプリはセッションごとに新しいトークンを生成する必要があります。

フィールド マスク

Place Details を返すメソッドでは、各リクエストで返す場所データのタイプを指定する必要があります。これにより 実際に使用するデータのみを リクエストして支払うことができます

返されるデータ型を指定するには、次の例に示すように、FetchPlaceRequestPlace.Field の配列を渡します。

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

次のフィールドの 1 つ以上を使用できます。

  • Place.Field.ADDRESS
  • Place.Field.ID
  • Place.Field.LAT_LNG
  • Place.Field.NAME
  • Place.Field.OPENING_HOURS
  • Place.Field.PHONE_NUMBER
  • Place.Field.PHOTO_METADATAS
  • Place.Field.PLUS_CODE
  • Place.Field.PRICE_LEVEL
  • Place.Field.RATING
  • Place.Field.TYPES
  • Place.Field.USER_RATINGS_TOTAL
  • Place.Field.VIEWPORT
  • Place.Field.WEBSITE_URI

詳しくは、Places Data SKU をご覧ください。

Place Picker と Autocomplete の更新

このセクションでは、プレイス ウィジェット(Place Picker と Autocomplete)の変更点について説明します。

プログラムによる予測入力

予測入力が次のように変更されました。

  • PlaceAutocomplete の名前が Autocomplete に変更されました。
    • PlaceAutocomplete.getPlace の名前が Autocomplete.getPlaceFromIntent に変更されました。
    • PlaceAutocomplete.getStatus の名前が Autocomplete.getStatusFromIntent に変更されました。
  • PlaceAutocomplete.RESULT_ERROR の名前が AutocompleteActivity.RESULT_ERROR に変更されました(予測入力フラグメントのエラー処理は変更されていません)。

Place Picker

Place Picker は 2019 年 1 月 29 日をもってサポートを終了しました。この機能は 2019 年 7 月 29 日に無効になり、ご利用いただけなくなりました。そのまま使用すると、エラー メッセージが表示されます。新しい SDK は Place Picker に対応していません。

予測入力ウィジェット

予測入力ウィジェットが更新されました。

  • 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. 予測入力ウィジェットをアクティビティに追加する手順は次のとおりです。

    • Places を初期化し、アプリケーション コンテキストと API キーを渡します。
    • 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.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. Places を初期化し、アプリのコンテキストと API キーを渡す
  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.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.
            }
        }
    }

Place Picker はご利用いただけなくなりました

Place Picker は 2019 年 1 月 29 日をもってサポートを終了しました。この機能は 2019 年 7 月 29 日に無効になり、ご利用いただけなくなりました。そのまま使用すると、エラー メッセージが表示されます。新しい SDK は Place Picker に対応していません。