本指南說明地點介面集相容性程式庫與新版獨立 Places SDK for Android 之間的變更。如果您一直使用 Places 相容性程式庫,而未遷移至新版獨立的 Places SDK for Android,請參閱本指南,瞭解如何更新專案以使用新版 Places SDK for Android。
接下來只能使用 Places SDK for Android 存取 Places SDK for Android 2.6.0 以上版本的功能和錯誤修正檔。Google 建議您盡快從相容性程式庫更新至新版 Places SDK for Android。
錯誤:9005 PLACES_API_RATE_LIMIT_EXCEEDED
異動內容
主要異動如下:
- 新版 Places SDK for Android 以靜態用戶端程式庫的形式發布,2019 年 1 月前,Places SDK for Android 是透過 Google Play 服務提供。自此,我們提供地點介面集相容性程式庫,方便您遷移至新的 Places SDK for Android。
- 全新方法。
- 現在,傳回地點詳細資料的方法支援欄位遮蓋。您可以使用欄位遮罩指定要傳回的地點資料類型。
- 用於回報錯誤的狀態碼已改善。
- 自動完成功能現已支援工作階段符記。
- 地點挑選程式已停用。
關於地點相容性程式庫
2019 年 1 月,Google 推出獨立式 Places SDK for Android 1.0 版,並提供相容性程式庫,協助從已淘汰的 Google Play 服務版 Places SDK for Android (com.google.android.gms:play-services-places
) 遷移。
這項相容性程式庫是暫時提供,用於重新導向及轉譯以 Google Play 服務版本為目標的 API 呼叫,直到開發人員將程式碼遷移至獨立式 SDK 中的新名稱為止。從 1.0 版到 2.6.0 版,我們為每個版本的 Places SDK for Android 都發布了對應版本的地點介面集相容性程式庫,提供同等功能。
凍結及淘汰地點介面集相容性程式庫
Places SDK for Android 所有版本的相容性程式庫已於 2022 年 3 月 31 日淘汰。2.6.0 版是地點相容性程式庫的最後一個版本。接下來只能使用 Places SDK for Android 存取 Places SDK for Android 2.6.0 以上版本的功能和錯誤修正檔。
Google 建議您遷移至 Places SDK for Android,以便存取 2.6.0 以上版本的新功能和重大錯誤修正檔。如果您目前使用相容性程式庫,請按照「安裝 Places SDK for Android」一節中的步驟,遷移至 Places SDK for Android。
安裝用戶端程式庫
新版 Places SDK for Android 以靜態用戶端程式庫的形式發布。
使用 Maven 將 Places SDK for Android 新增至 Android Studio 專案:
如果您目前使用地點介面集相容性程式庫:
在
dependencies
區段中,取代下列程式碼行:implementation 'com.google.android.libraries.places:places-compat:X.Y.Z'
使用這行程式碼切換至 Places SDK for Android:
implementation("com.google.android.libraries.places:places:4.3.1")
如果您目前使用的是 Play 服務版本的 Places SDK for Android:
在
dependencies
區段中,取代下列程式碼行:implementation 'com.google.android.gms:play-services-places:X.Y.Z'
使用這行程式碼切換至 Places SDK for Android:
implementation("com.google.android.libraries.places:places:4.3.1")
同步處理您的 Gradle 專案。
將應用程式專案的
minSdkVersion
設為 23 以上。更新「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
建構應用程式。如果轉換為 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 限制錯誤的狀態碼已變更。每秒查詢次數限制錯誤現在會透過 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()
類似。
如要擷取地點,請按照下列步驟操作:
呼叫
fetchPlace()
,並傳遞FetchPlaceRequest
物件,指定地點 ID 和欄位清單,用於指定要傳回的地點資料。// 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();
呼叫
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
,不必再另外提出要求。相片的寬度或高度不得超過 1600 像素。函式,與 getPhoto()
類似。fetchPhoto()
請按照下列步驟擷取地點相片:
設定對
fetchPlace()
的呼叫。請務必在要求中加入PHOTO_METADATAS
欄位:List<Place.Field> fields = Arrays.asList(Place.Field.PHOTO_METADATAS);
取得 Place 物件 (本範例使用
fetchPlace()
,但您也可以使用findCurrentPlace()
):FetchPlaceRequest placeRequest = FetchPlaceRequest.builder(placeId, fields).build();
新增
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()
類似。
請按照下列步驟取得使用者裝置的目前位置:
請確認應用程式要求
ACCESS_FINE_LOCATION
和ACCESS_WIFI_STATE
權限。使用者必須授予存取目前裝置位置的權限。詳情請參閱「要求應用程式權限」。建立
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();
呼叫 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());
}
});
工作階段符記
工作階段符記會將使用者搜尋的查詢和選取階段歸入不同的工作階段,以用於計費。建議您在所有自動完成工作階段使用工作階段符記。工作階段是從使用者輸入查詢時開始,到使用者選取地點時結束。在每個工作階段中,使用者可以輸入多筆查詢,最終選擇一個地點。工作階段結束後,符記就會失效。您的應用程式必須為每個工作階段產生新的符記。
欄位遮罩
在傳回地點詳細資料的方法中,您必須為每項要求指定要傳回的地點資料類型。這樣一來,您就能確保只要求 (並支付) 實際會用到的資料。
如要指定要傳回的資料類型,請在 FetchPlaceRequest
中傳遞 Place.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);
如需可在欄位遮罩中使用的欄位清單,請參閱「地點資料欄位 (新版) 」。
進一步瞭解地點介面集資料 SKU。
Place Picker 和 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
前置字元。 - 新增工作階段權杖支援功能。小工具會在背景自動管理權杖。
- 新增支援欄位遮罩,讓您在使用者選取後,選擇要傳回的地點資料類型。
下列各節說明如何在專案中加入 Autocomplete 小工具。
嵌入 AutocompleteFragment
如要新增自動完成片段,請按照下列步驟操作:
在活動的 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" />
如要將自動完成小工具新增至活動,請按照下列步驟操作:
- 初始化
Places
,並傳遞應用程式內容和 API 金鑰。 - 初始化
AutocompleteSupportFragment
。 - 呼叫
setPlaceFields()
即可指出要取得的地點資料類型。 - 新增
PlaceSelectionListener
,以便處理結果,以及處理可能發生的任何錯誤。
以下範例說明如何在活動中新增 Autocomplete 小工具:
/** * 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); } });
- 初始化
使用意圖啟動自動完成活動
- 初始化
Places
,並傳遞應用程式環境和 API 金鑰 - 使用
Autocomplete.IntentBuilder
建立意圖,並傳遞所需的PlaceAutocomplete
模式 (全螢幕或疊加)。意圖必須呼叫startActivityForResult
,並傳遞可識別意圖的要求代碼。 - 覆寫
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.
}
}
}
地點挑選程式已停用
Place Picker 已於 2019 年 1 月 29 日淘汰。這項服務已於 2019 年 7 月 29 日停用,如果繼續使用,系統會顯示錯誤訊息。新版 SDK 不支援地點挑選器。