يشرح هذا الدليل التغييرات بين مكتبة توافق ميزة "الأماكن" والإصدار المستقل الجديد من حزمة SDK لميزة "الأماكن" على Android. إذا كنت تستخدِم مكتبة التوافق مع "أماكن Google" بدلاً من نقل البيانات إلى الإصدار الجديد المستقل من حزمة تطوير البرامج (SDK) لنظام التشغيل Android، يوضّح لك هذا الدليل كيفية تعديل مشاريعك لاستخدام الإصدار الجديد من حزمة تطوير البرامج (SDK) لنظام التشغيل Android.
إنّ الطريقة الوحيدة للوصول إلى الميزات وإصلاح الأخطاء في حزمة تطوير برامج "الأماكن" لنظام التشغيل Android الإصدار 2.6.0 أو الإصدارات الأحدث هي استخدام حزمة تطوير برامج "الأماكن" لنظام التشغيل Android. تنصح Google بالتحديث من مكتبة التوافق إلى الإصدار الجديد من حزمة تطوير البرامج (SDK) لتطبيق "الأماكن" على Android في أقرب وقت ممكن.
ما التغييرات التي أُجريت؟
في ما يلي المجالات الرئيسية للتغيير:
- يتم توزيع الإصدار الجديد من حزمة تطوير البرامج (SDK) لميزة "الأماكن" لنظام التشغيل Android كمكتبة عملاء ثابتة. قبل كانون الثاني (يناير) 2019، كانت حزمة تطوير البرامج (SDK) لتطبيق "الأماكن" لأجهزة Android متوفرة من خلال "خدمات Google Play". ومنذ ذلك الحين، تم توفير مكتبة متوافقة مع "أماكن Google" لتسهيل عملية الانتقال إلى الإصدار الجديد من "حزمة تطوير البرامج (SDK) للأماكن لنظام التشغيل Android".
- هناك طرق جديدة تمامًا.
- أصبحت أقنعة الحقول متاحة الآن للطُرق التي تعرض تفاصيل الأماكن. يمكنك استخدام أقنعة الحقول لتحديد أنواع بيانات الأماكن التي تريد عرضها.
- تم تحسين رموز الحالة المستخدَمة للإبلاغ عن الأخطاء.
- تتيح ميزة الإكمال التلقائي الآن استخدام رموز الجلسات.
- لم تعُد ميزة "أداة اختيار الأماكن" متاحة.
لمحة عن مكتبة توافق "الأماكن"
في كانون الثاني (يناير) 2019، مع إصدار الإصدار 1.0 من حزمة تطوير البرامج (SDK) المستقلة للأماكن لنظام Android، قدمت Google مكتبة توافق للمساعدة في نقل البيانات
من إصدار "خدمات Google Play" المتوقّف نهائيًا من حزمة تطوير البرامج (SDK) للأماكن لنظام Android
(com.google.android.gms:play-services-places
).
تم توفير مكتبة التوافق هذه مؤقتًا لإعادة توجيه وترجمة طلبات البيانات من واجهة برمجة التطبيقات التي تستهدف إصدار "خدمات Google Play" إلى الإصدار الجديد المستقل، إلى أن يتمكّن المطوّرون من نقل رموزهم البرمجية لاستخدام الأسماء الجديدة في حزمة SDK المستقلة. بالنسبة إلى كل إصدار من حزمة تطوير البرامج (SDK) لأماكن Google لنظام التشغيل Android الذي تم إصداره من الإصدار 1.0 إلى الإصدار 2.6.0، تم إصدار إصدار مقابل من مكتبة التوافق مع أماكن Google لتوفير وظائف مماثلة.
إيقاف مكتبة التوافق مع "الأماكن" نهائيًا
تم إيقاف جميع إصدارات مكتبة التوافق لحزمة تطوير برامج "الأماكن" لنظام التشغيل Android نهائيًا اعتبارًا من 31 آذار (مارس) 2022. الإصدار 2.6.0 هو آخر إصدار من مكتبة التوافق باستخدام "خرائط Google". إنّ الطريقة الوحيدة للوصول إلى الميزات وإصلاح الأخطاء في حزمة تطوير البرامج (SDK) لنظام التشغيل Android من Places والإصدارات الأحدث هي استخدام حزمة تطوير البرامج (SDK) لنظام التشغيل Android من Places .
تنصح Google بنقل البيانات إلى حزمة Places SDK لنظام التشغيل Android للوصول إلى الميزات الجديدة وإصلاحات الأخطاء المهمة للإصدارات الأحدث من الإصدار 2.6.0. إذا كنت تستخدم حاليًا مكتبة التوافق، اتّبِع الخطوات الواردة أدناه في القسم تثبيت حزمة تطوير البرامج (SDK) للأماكن لنظام Android لنقل بياناتك إلى حزمة تطوير البرامج (SDK) للأماكن لنظام Android.
تثبيت مكتبة البرامج
يتم توزيع الإصدار الجديد من حزمة تطوير البرامج (SDK) لميزة "الأماكن" على Android كمكتبة ملف برمجي ثابتة للعملاء.
استخدِم Maven لإضافة حزمة تطوير برامج "الأماكن" لنظام التشغيل Android إلى مشروعك على "استوديو Android":
إذا كنت تستخدم حاليًا مكتبة التوافق مع "الأماكن":
استبدِل السطر التالي في قسم
dependencies
:implementation 'com.google.android.libraries.places:places-compat:X.Y.Z'
باستخدام هذا السطر للتبديل إلى حزمة تطوير برامج "الأماكن" لأجهزة Android:
implementation 'com.google.android.libraries.places:places:3.3.0'
إذا كنت تستخدم حاليًا إصدار "خدمات Play" من حزمة تطوير البرامج (SDK) لتطبيق "الأماكن" لنظام التشغيل Android:
استبدِل السطر التالي في قسم
dependencies
:implementation 'com.google.android.gms:play-services-places:X.Y.Z'
باستخدام هذا السطر للتبديل إلى حزمة تطوير برامج "الأماكن" لأجهزة Android:
implementation 'com.google.android.libraries.places:places:3.3.0'
مزامنة مشروع Gradle
اضبط
minSdkVersion
لمشروع تطبيقك على 16 أو إصدار أحدث.تعديل مواد العرض التي تحمل شعار "مزوّد بتكنولوجيا 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 لنظام التشغيل Android، اطّلِع على الأقسام أدناه للحصول على معلومات حول حلّ هذه الأخطاء.
إعداد برنامج Places SDK الجديد
يمكنك إعداد عملاء حزمة تطوير البرامج (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
- تم رفض الطلب. وتشمل الأسباب المحتملة ما يلي:- لم يتم تقديم مفتاح واجهة برمجة التطبيقات.
- تم تقديم مفتاح واجهة برمجة تطبيقات غير صالح.
- لم يتم تفعيل Places API في وحدة تحكّم Cloud.
- تم تقديم مفتاح واجهة برمجة تطبيقات مع قيود مفتاح غير صحيحة.
INVALID_REQUEST
: الطلب غير صالح بسبب عدم توفّر ملف شخصي أو ملف شخصي غير صالح.NOT_FOUND
- لم يتم العثور على أي نتيجة للطلب المقدَّم.
طرق جديدة
يقدّم الإصدار الجديد من حزمة تطوير برامج "الأماكن" لنظام التشغيل Android methods جديدة تمامًا تم تصميمها لتحقيق الاتساق. تلتزم جميع الطرق الجديدة يلي:
- لم تعُد نقاط النهاية تستخدِم الفعل
get
. - تتشارك كائنات الطلب والاستجابة الاسم نفسه المُستخدَم في أسلوب العميل المناظر.
- تحتوي عناصر الطلبات الآن على منشئين، ويتم تمرير المَعلمات المطلوبة كمَعلمات لإنشاء الطلبات.
- لم تعُد أدوات التخزين المؤقت مستخدمة.
يقدّم هذا القسم الطرق الجديدة ويوضّح كيفية عملها.
جلب مكان حسب المعرّف
استخدِم fetchPlace()
للحصول على تفاصيل عن مكان معيّن. تعمل دالة fetchPlace()
بالطريقة نفسها التي تعمل بها دالة
getPlaceById()
.
اتّبِع الخطوات التالية لجلب مكان:
استخدِم
fetchPlace()
مع تمرير عنصر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();
يُرجى الاتصال برقم
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()
تعرِض صورًا لمكان معيّن. تم تبسيط النمط
لطلب صورة. يمكنك الآن طلب PhotoMetadata
مباشرةً من عنصر Place
، ولم يعُد من الضروري تقديم طلب منفصل.
يمكن أن يصل الحد الأقصى لعرض الصور أو ارتفاعها إلى 1600 بكسل. تعمل الدالة fetchPhoto()
بطريقة مشابهة لدالة getPhoto()
.
اتّبِع الخطوات التالية لجلب صور الأماكن:
حدِّد موعدًا لمكالمة مع
fetchPlace()
. احرص على تضمين الحقلPHOTO_METADATAS
في طلبك:List<Place.Field> fields = Arrays.asList(Place.Field.PHOTO_METADATAS);
الحصول على عنصر "مكان" (يستخدم هذا المثال
fetchPlace()
، ولكن يمكنك أيضًا استخدامfindCurrentPlace()
):FetchPlaceRequest placeRequest = FetchPlaceRequest.builder(placeId, fields).build();
أضِف
OnSuccessListener
للحصول على البيانات الوصفية للصورة منPlace
الناتج فيFetchPlaceResponse
، ثم استخدِم البيانات الوصفية للصورة الناتجة للحصول على صورة نقطية ونص الإسناد: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());
}
});
الرموز المميّزة للجلسات
تجمع الرموز المميّزة للجلسات مرحلتي طلب البحث والاختيار في عملية بحث المستخدِم في جلسة متمايزة لأغراض الفوترة. ننصحك باستخدام الرموز المميّزة للجلسات في كل جلسات الإكمال التلقائي. تبدأ الجلسة عندما يبدأ المستخدم كتابة query، وتنتهي عندما يختار مكانًا. يمكن أن تتضمّن كل جلسة عدة طلبات بحث، متبوعة باختيار مكان واحد. بعد انتهاء جلسة، لن يعود الرمز المميّز صالحًا، ويجب أن ينشئ تطبيقك رمزًا مميّزًا جديدًا لكل جلسة.
أقنعة الحقول
في الطرق التي تعرض تفاصيل الأماكن، عليك تحديد أنواع بيانات الأماكن التي تريد عرضها مع كل طلب. ويساعد ذلك في ضمان طلب (ودفع رسوم) البيانات التي ستستخدمها فقط.
لتحديد أنواع البيانات التي تريد عرضها، مرِّر صفيفًا من Place.Field
في
FetchPlaceRequest
، كما هو موضّح في المثال التالي:
// Include address, ID, and phone number.
List<Place.Field> placeFields = Arrays.asList(Place.Field.FORMATTED_ADDRESS,
Place.Field.ID,
Place.Field.INTERNATIONAL_PHONE_NUMBER);
للحصول على قائمة بالحقول التي يمكنك استخدامها في قناع حقل، اطّلِع على حقول بيانات الأماكن (الإصدار الجديد) .
اطّلِع على مزيد من المعلومات عن رموز التخزين التعريفية لبيانات "الأماكن".
تعديلات على "أداة اختيار الأماكن" وميزة "الإكمال التلقائي"
يوضّح هذا القسم التغييرات التي طرأت على التطبيقات المصغّرة "الأماكن" ("أداة اختيار الأماكن" و"الإكمال التلقائي").
الإكمال التلقائي الآلي
تم إجراء التغييرات التالية على الإكمال التلقائي:
- تمت إعادة تسمية
PlaceAutocomplete
إلىAutocomplete
.- تمت إعادة تسمية
PlaceAutocomplete.getPlace
إلىAutocomplete.getPlaceFromIntent
. - تمت إعادة تسمية
PlaceAutocomplete.getStatus
إلىAutocomplete.getStatusFromIntent
.
- تمت إعادة تسمية
- تمت إعادة تسمية
PlaceAutocomplete.RESULT_ERROR
ليصبحAutocompleteActivity.RESULT_ERROR
(لم تتغيّر معالجة الأخطاء في مقتطف الإكمال التلقائي).
أداة اختيار الأماكن
تم إيقاف أداة "أداة اختيار الأماكن" نهائيًا في 29 كانون الثاني (يناير) 2019. وتم إيقافها في 29 تموز (يوليو) 2019، ولم تعُد متاحة. سيؤدي مواصلة الاستخدام إلى ظهور رسالة خطأ. لا تتوافق حزمة تطوير البرامج (SDK) الجديدة مع أداة اختيار الأماكن.
التطبيقات المصغّرة للإكمال التلقائي
تم تعديل التطبيقات المصغّرة للإكمال التلقائي:
- تمت إزالة البادئة
Place
من جميع الصفوف. - تمت إضافة إمكانية استخدام الرموز المميّزة للجلسات. تدير الأداة الرموز المميّزة تلقائيًا في الخلفية.
- تمت إضافة إمكانية استخدام أقنعة الحقول التي تتيح لك اختيار أنواع بيانات الأماكن التي تريد عرضها بعد أن يختار المستخدم أحد الخيارات.
توضِّح الأقسام التالية كيفية إضافة تطبيق مصغّر لإكمال الكلمات إلى مشروعك.
تضمين 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
، مع تمرير سياق التطبيق ومفتاح واجهة برمجة التطبيقات. - فعِّل
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); } });
- اضبط
استخدام نية لبدء نشاط الإكمال التلقائي
- إعداد
Places
، مع تمرير سياق التطبيق ومفتاح واجهة برمجة التطبيقات - استخدِم
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.
}
}
}
لم تعُد ميزة "أداة اختيار الأماكن" متاحة
تم إيقاف أداة "أداة اختيار الأماكن" نهائيًا في 29 كانون الثاني (يناير) 2019. وتم إيقافها في 29 تموز (يوليو) 2019، ولم تعُد متاحة. سيؤدي مواصلة الاستخدام إلى ظهور رسالة خطأ. لا تتوافق حزمة تطوير البرامج (SDK) الجديدة مع أداة اختيار الأماكن.