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

コレクションでコンテンツを整理 必要に応じて、コンテンツの保存と分類を行います。

このガイドでは、Places Compatibility ライブラリと 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)からの移行に役立つ互換性ライブラリを提供しました。

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

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

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. 現在 Places Compatibility Library を使用している場合:

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

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

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

          implementation 'com.google.android.libraries.places:places:2.7.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:2.7.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 Console で 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. Place オブジェクトを取得します(この例では 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 はサポートされていません。

Autocomplete ウィジェット

オートコンプリート ウィジェットが更新されました:

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

    • アプリケーション コンテキストと 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.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 はサポートされていません。