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

このガイドでは、Places 互換性ライブラリと、新しいスタンドアロン バージョンの Places SDK for Android の変更点について説明します。新しいスタンドアロン バージョンの Maps SDK for Android に移行する代わりに、Places 互換性ライブラリを使用していた場合は、このガイドで、新しいバージョンの Maps 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 への移行を容易にするために、Places 互換性ライブラリが提供されています。
  • まったく新しいメソッドがあります。
  • 場所の詳細を返すメソッドでフィールド マスクがサポートされるようになりました。フィールドマスクを使用すると、返される場所データの種類を指定できます。
  • エラーの報告に使用されるステータス コードが改善されました。
  • 自動入力でセッション トークンがサポートされるようになりました。
  • Place Picker はご利用いただけなくなりました

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

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

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

プレイス互換性ライブラリの凍結と非推奨化

Places SDK for Android の互換性ライブラリのすべてのバージョンは、2022 年 3 月 31 日をもってサポートが終了します。バージョン 2.6.0 は、Places 互換性ライブラリの最終バージョンです。バージョン 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 を使用して、Android Studio プロジェクトに Places SDK for Android を追加します。

  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. 現在、Play 開発者サービス バージョンの Places SDK for Android を使用している場合:

    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. アプリをビルドします。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 - 指定されたリクエストに一致する結果は見つかりませんでした。

新しい方法

新しいバージョンの Places SDK for Android では、一貫性を保つように設計されたまったく新しいメソッドが導入されています。新しいメソッドはすべて、次の要件を満たしています。

  • エンドポイントで get 動詞が使用されなくなりました。
  • リクエスト オブジェクトとレスポンス オブジェクトは、対応するクライアント メソッドと同じ名前を共有します。
  • リクエスト オブジェクトにビルダーが追加されました。必須パラメータはリクエスト ビルダーのパラメータとして渡されます。
  • バッファは使用されなくなりました。

このセクションでは、新しいメソッドとその動作について説明します。

ID で場所を取得する

fetchPlace() を使用して、特定の場所の詳細を取得します。fetchPlace()getPlaceById() と同様の方法で機能します。

場所を取得する手順は次のとおりです。

  1. fetchPlace() を呼び出し、Place ID を指定する FetchPlaceRequest オブジェクトと、返される Place データを指定するフィールドのリストを渡します。

    // 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. 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.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());
   }
});

セッション トークン

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

フィールド マスク

場所の詳細を返すメソッドでは、リクエストごとに返す場所データの種類を指定する必要があります。これにより、実際に使用するデータのみをリクエスト(および支払い)できます。

返すデータ型を指定するには、次の例に示すように、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 に変更されました(自動入力フラグメントのエラー処理は変更されていません)。

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

    • アプリケーション コンテキストと 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);
        }
    });
    

インテントを使用して Autocomplete アクティビティを起動する

  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 では、Place Picker はサポートされていません。