يوضّح هذا الدليل التغييرات بين مكتبة التوافق مع الأماكن والإصدار المستقل الجديد من الأماكن الخاصة بخدمة SDK لأجهزة Android. إذا كنت تستخدم مكتبة توافق الأماكن بدلاً من نقل البيانات إلى الإصدار المستقل الجديد من حزمة تطوير البرامج (SDK) للأماكن المتوفّرة لنظام التشغيل Android، يوضّح لك هذا الدليل كيفية تحديث مشاريعك لاستخدام الإصدار الجديد من حزمة تطوير برامج الأماكن الأماكن لأجهزة Android.
إن الطريقة الوحيدة للوصول إلى الميزات وإصلاح الأخطاء في حزمة تطوير البرامج (SDK) للأماكن في نظام التشغيل Android أكثر من الإصدار 2.6.0 هي استخدام حزمة تطوير البرامج (SDK) للأماكن في نظام التشغيل Android. تنصح Google بالتحديث من مكتبة التوافق إلى الإصدار الجديد من حزمة تطوير البرامج (SDK) للأماكن في نظام التشغيل Android في أقرب وقت ممكن.
ما التغييرات التي أُجريت؟
في ما يلي المناطق الرئيسية للتغيير:
- يتم توزيع الإصدار الجديد من الأماكن بإصدار Android كمكتبة ثابتة للعميل. قبل كانون الثاني (يناير) 2019، تمت إتاحة حِزمة تطوير البرامج (SDK) للأماكن في نظام التشغيل Android من خلال خدمات Google Play. ومنذ ذلك الحين، تم توفير مكتبة متوافقة للأماكن لتسهيل عملية الانتقال إلى حزمة تطوير البرامج (SDK) للأماكن الجديدة لنظام التشغيل Android.
- تتوفّر طرق جديدة تمامًا.
- أصبح ارتداء الكمامات الميدانية متاحًا للطرق التي تعرض تفاصيل المكان. يمكنك استخدام أقنعة الحقل لتحديد أنواع بيانات المكان التي تعرضها.
- تم تحسين رموز الحالة المُستخدَمة للإبلاغ عن الأخطاء.
- يتيح الإكمال التلقائي الآن الرموز المميّزة للجلسة.
- لم تعُد "أداة اختيار الأماكن" متوفّرة
لمحة عن "مكتبة التوافق"
في كانون الثاني (يناير) 2019، مع إطلاق الإصدار 1.0 من حزمة تطوير البرامج (SDK) للأماكن المستقلة لأجهزة Android،
وفّرت Google مكتبة توافق للمساعدة في عملية نقل البيانات
من إصدار "خدمات Google Play" الذي تم إيقافه عن العمل والمستند إلى حزمة تطوير برامج الأماكن لأجهزة Android
(com.google.android.gms:play-services-places
).
تم توفير "مكتبة التوافق" هذه مؤقتًا لإعادة توجيه طلبات البيانات من واجهة برمجة التطبيقات الموجّهة إلى خدمات Google Play إلى الإصدار المستقل الجديد الجديد حتى يتمكّن مطوّرو البرامج من نقل رموزهم لاستخدام الأسماء الجديدة في حزمة تطوير البرامج (SDK) المستقلة. لكل إصدار من حزمة تطوير البرامج (SDK) للأماكن التي تعمل بنظام التشغيل Android وتم إصدارها من الإصدار 1.0 إلى الإصدار 2.6.0، تم طرح إصدار مقابل من مكتبة التوافق مع الأماكن لتوفير وظائف مكافئة.
إيقاف مكتبة التوافق مع "الأماكن" نهائيًا
سيتم إيقاف جميع إصدارات مكتبة التوافق مع حزمة تطوير البرامج (SDK) للأماكن في Android اعتبارًا من 31 آذار (مارس) 2022. الإصدار 2.6.0 هو آخر إصدار من مكتبة التوافق مع الأماكن. إن الطريقة الوحيدة للوصول إلى الميزات وإصلاحات الأخطاء في حزمة تطوير البرامج (SDK) للأماكن لنظام التشغيل Android أعلى من الإصدار 2.6.0 هي استخدام حزمة تطوير البرامج (SDK) للأماكن في نظام التشغيل Android.
تنصح Google بنقل البيانات إلى حزمة تطوير البرامج (SDK) للأماكن في نظام التشغيل Android للوصول إلى الميزات الجديدة وإصلاحات الأخطاء المهمة للإصدارات الأحدث من الإصدار 2.6.0. إذا كنت تستخدم حاليًا مكتبة التوافق، اتبع الخطوات التالية الواردة في قسم تثبيت حزمة تطوير البرامج (SDK) للأماكن في نظام التشغيل Android لنقل البيانات إلى حزمة تطوير برامج الأماكن لأجهزة Android.
تثبيت مكتبة البرامج
يتم توزيع الإصدار الجديد من الأماكن لخدمة Android كمكتبة ثابتة للعميل.
استخدم Maven لإضافة حزمة تطوير البرامج (SDK) للأماكن في Android إلى مشروع Android Studio:
إذا كنت تستخدم حاليًا مكتبة التوافق مع الأماكن:
استبدال السطر التالي في القسم
dependencies
:implementation 'com.google.android.libraries.places:places-compat:X.Y.Z'
باستخدام هذا السطر للتبديل إلى حزمة تطوير برامج الأماكن لأجهزة Android:
implementation 'com.google.android.libraries.places:places:3.1.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.1.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
أنشئ تطبيقك. إذا ظهرت لك أي أخطاء في الإصدار بسبب الإحالة الناجحة إلى حزمة تطوير البرامج (SDK) للأماكن في نظام التشغيل Android، يُرجى الاطّلاع على الأقسام أدناه للحصول على معلومات حول حل هذه الأخطاء.
إعداد عميل 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
: تم رفض الطلب. وتشمل الأسباب المحتملة ما يلي:- لم يتم تقديم مفتاح واجهة برمجة التطبيقات.
- تم تقديم مفتاح واجهة برمجة تطبيقات غير صالح.
- لم يتم تفعيل واجهة برمجة تطبيقات الأماكن في وحدة تحكم Cloud.
- تم تقديم مفتاح واجهة برمجة التطبيقات مع فرض قيود غير صحيحة على المفاتيح.
INVALID_REQUEST
— الطلب غير صالح بسبب وسيطة مفقودة أو غير صالحة.NOT_FOUND
: لم يتم العثور على أي نتائج للطلب المعني.
طرق جديدة
يقدّم الإصدار الجديد من حزمة تطوير البرامج (SDK) للأماكن لأجهزة Android طرقًا جديدة تم تصميمها لتحقيق الاتساق. وتتّبع جميع الطرق الجديدة ما يلي:
- لم تعد نقاط النهاية تستخدم فعل
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.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.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());
}
});
الرموز المميزة للجلسة
تعمل الرموز المميّزة للجلسات على تجميع طلبات البحث ومراحل الاختيار في بحث المستخدم في جلسة منفصلة لأغراض الفوترة. ننصح باستخدام الرموز المميزة للجلسة في جميع جلسات الإكمال التلقائي. وتبدأ الجلسة عندما يبدأ المستخدم في كتابة طلب بحث، وتنتهي عند اختيار مكان. يمكن أن تحتوي كل جلسة على طلبات بحث متعددة، يليها اختيار مكان واحد. بعد انتهاء الجلسة، يصبح الرمز المميّز غير صالح، ويجب أن ينشئ تطبيقك رمزًا مميّزًا جديدًا لكل جلسة.
أقنعة ميدانية
في الطرق التي تعرض تفاصيل المكان، عليك تحديد أنواع بيانات المكان التي سيتم عرضها مع كل طلب. يساعدك ذلك في ضمان عدم طلب سوى البيانات التي ستستخدمها (والدفع مقابل) البيانات.
لتحديد أنواع البيانات التي يتم عرضها، مرِّر صفيفًا من Place.Field
في
FetchPlaceRequest
، كما هو موضّح في المثال التالي:
// Include address, ID, and phone number.
List<Place.Field> placeFields = Arrays.asList(Place.Field.ADDRESS,
Place.Field.ID,
Place.Field.PHONE_NUMBER);
يمكنك استخدام حقل واحد أو أكثر من الحقول التالية:
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
يمكنك قراءة المزيد من المعلومات عن رموز التخزين التعريفية لبيانات الأماكن.
إشعارات أداة اختيار الأماكن والإكمال التلقائي
يوضّح هذا القسم التغييرات التي طرأت على التطبيقات المصغّرة في "الأماكن" (أداة اختيار الأماكن والإكمال التلقائي).
الإكمال التلقائي الآلي
تم إجراء التغييرات التالية على ميزة الإكمال التلقائي:
- تمت إعادة تسمية
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.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
المطلوب (ملء الشاشة أو التراكب). يجب أن يطلب intentstartActivityForResult
رمز الاستجابة السريعة الذي يحدّد نية الشراء. - يمكنك إلغاء معاودة الاتصال من
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.
}
}
}
لم تعُد أداة اختيار المكان متاحة
تم إيقاف "منتقي المكان" في 29 كانون الثاني (يناير) 2019. تم إيقافها في 29 تموز (يوليو) 2019، ولم يعُد متوفّرة. وسيؤدي الاستخدام المستمر إلى ظهور رسالة خطأ. لا تتوافق حزمة تطوير البرامج (SDK) الجديدة مع "أداة اختيار الأماكن".