إنشاء أداة اختيار "المكان الحالي" الخاصة بك لنظام التشغيل Android (Java)

1. قبل البدء

تعرَّف على كيفية استخدام "منصة خرائط Google" وPlaces SDK لنظام التشغيل Android من أجل تزويد المستخدمين بقائمة "أماكن" لتحديد مواقعهم الجغرافية الحالية.

bd07a9ad2cb27a06.png

المتطلبات الأساسية

  • مهارات Java الأساسية

الإجراءات التي ستنفذّها

  • إضافة خريطة إلى تطبيق Android
  • استخدِم أذونات تحديد الموقع الجغرافي لتحديد الموقع الجغرافي للمستخدم.
  • استرداد الأماكن القريبة من الموقع الجغرافي الحالي للمستخدم
  • عرض "الأماكن المحتملة" للمستخدم لتحديد موقعه الجغرافي الحالي

ما ستنشئه

يمكنك إنشاء تطبيق Android من البداية، ولكن يمكنك تنزيل نموذج الرمز للمقارنة عند تصحيح الأخطاء. نزِّل نموذج الرمز من GitHub، أو إذا كنت قد أعددت Git للاستخدام من سطر الأوامر، أدخِل ما يلي:

git clone https://github.com/googlecodelabs/current-place-picker-android.git

إذا واجهت أي مشاكل (مثل أخطاء في الرمز أو أخطاء نحوية أو صياغة غير واضحة أو غير ذلك) أثناء العمل على هذا الدرس العملي، يُرجى الإبلاغ عن المشكلة من خلال الرابط الإبلاغ عن خطأ في أسفل يمين الدرس العملي.

2. البدء

قبل البدء في هذا الدرس العملي، عليك إعداد ما يلي:

Android Studio

يمكنك تنزيل "استوديو Android" من https://developer.android.com/studio.

إذا كان لديك Android Studio، تأكَّد من استخدام أحدث إصدار من خلال النقر على Android Studio > البحث عن التحديثات....

1f36bae83b64e33.png

تمت كتابة هذا المختبر باستخدام "استوديو Android" 3.4.

حزمة تطوير البرامج (SDK) لنظام التشغيل Android

في "استوديو Android"، يمكنك ضبط حِزم SDK التي تريدها باستخدام "أداة إدارة حِزم SDK". يستخدم هذا المختبر حزمة تطوير البرامج (SDK) لنظام التشغيل Android Q.

  1. من شاشة الترحيب في Android Studio، انقر على إعداد > مدير حزمة SDK.

d3fa03c269ec231c.png

  1. ضَع علامة في مربّع الاختيار الخاص بحزمة SDK المطلوبة، ثم انقر على تطبيق.

إذا لم تكن حزمة SDK متوفّرة لديك بعد، سيؤدي ذلك إلى بدء تنزيلها على جهازك.

884e0aa1314f70d.png

خدمات Google Play

من "أداة إدارة حزمة تطوير البرامج" (SDK)، عليك أيضًا تثبيت "خدمات Google Play".

  1. انقر على علامة التبويب أدوات حزمة تطوير البرامج (SDK) وضَع علامة في مربّع الاختيار خدمات Google Play.

حدِّث التطبيق إذا كانت الحالة يتوفّر تحديث.

ad6211fd78f3b629.png

3- إعداد المحاكي

لتشغيل التطبيق، يمكنك توصيل جهازك أو استخدام "محاكي Android".

إذا كنت تستخدم جهازك الخاص، انتقِل إلى تعليمات الجهاز الفعلي: تحديث "خدمات Google Play" في نهاية هذه الصفحة.

إضافة محاكي

  1. من شاشة الترحيب في Android Studio، انقر على إعداد > مدير الأجهزة الافتراضية لنظام Android.

5dd2d14c9c56d3f9.png

سيؤدي ذلك إلى فتح مربّع الحوار مدير الأجهزة الافتراضية لنظام Android.

  1. انقر على إنشاء جهاز افتراضي... لفتح قائمة بالأجهزة التي يمكنك الاختيار من بينها.

2d44eada384f8b35.png

  1. اختَر جهازًا يتضمّن رمز Play d5722488d80cd6be.png في عمود متجر Play وانقر على التالي.

e0248f1c6e85ab7c.png

ستظهر لك مجموعة من صور النظام التي يمكنك تثبيتها. إذا كان استهداف نظام التشغيل Android 9 والإصدارات الأحدث (Google Play) الذي يحمل الرمز Q يتضمّن كلمة تنزيل بجانبه، انقر على تنزيل.

316d0d1efabd9f24.png

  1. انقر على التالي لإدخال اسم لجهازك الافتراضي، ثم انقر على إنهاء.

سيتم نقلك إلى قائمة أجهزتك الافتراضية.

  1. انقر على "بدء" ba8adffe56d3b678.png بجانب جهازك الجديد:

7605864ed27f77ea.png

بعد بضع لحظات، سيتم فتح المحاكي.

تعليمات المحاكي: تحديث "خدمات Google Play"

  1. بعد تشغيل المحاكي، انقر على ... في شريط التنقّل الذي يظهر**.**

2e1156e02643d018.png

سيؤدي ذلك إلى فتح مربّع الحوار عناصر التحكّم الموسّعة.

  1. انقر على Google Play في القائمة.

في حال توفّر تحديث، انقر على تحديث.

5afd2686c5cad0e5.png

  1. سجِّل الدخول إلى المحاكي باستخدام حساب Google.

يمكنك استخدام حسابك أو إنشاء حساب جديد مجانًا لإبقاء الاختبار منفصلاً عن معلوماتك الشخصية.

سيتم فتح "متجر Google Play" ثم "خدمات Google Play".

  1. انقر على تحديث للحصول على أحدث إصدار من "خدمات Google Play".

f4bc067e80630b9c.png

إذا طُلب منك إكمال إعداد حسابك وإضافة طريقة دفع، انقر على تخطّي.

ضبط الموقع الجغرافي في المحاكي

  1. بعد تشغيل المحاكي، اكتب "خرائط" في شريط البحث على الشاشة الرئيسية لعرض رمز تطبيق "خرائط Google".

2d996aadd53685a6.png

  1. انقر على الرمز لتشغيل التطبيق.

تظهر لك خريطة تلقائية.

  1. في أسفل يسار الخريطة، انقر على موقعك الجغرافي c5b4e2fda57a7e71.png.

يُطلب منك منح الهاتف أذونات استخدام الموقع الجغرافي.

f2b68044eabca151.png

  1. انقر على ... لفتح قائمة عناصر التحكّم الموسّعة.
  2. انقر على علامة التبويب الموقع الجغرافي.
  3. أدخِل خط العرض وخط الطول.

أدخِل أي شيء تريده هنا، ولكن تأكَّد من أنّه في منطقة تضم الكثير من الأماكن.

(استخدِم خط العرض 20.7818 وخط الطول ‎-156.4624 لمدينة كيهاي في جزيرة ماوي في هاواي لتكرار النتائج من هذا الدرس العملي.)

  1. انقر على إرسال وسيتم تعديل الخريطة بهذا الموقع الجغرافي.

f9576b35218f4187.png

أنت الآن جاهز لتشغيل تطبيقك واختباره باستخدام الموقع الجغرافي.

تعليمات استخدام الجهاز الحقيقي: تعديل "خدمات Google Play"

إذا كنت تستخدم جهاز Android حقيقيًا، اتّبِع الخطوات التالية:

  1. استخدِم شريط البحث على الشاشة الرئيسية للبحث عن خدمات Google Play وفتحها.
  2. انقر على مزيد من التفاصيل.

انقر على تعديل إذا كان متاحًا.

ad16cdb975b5c3f7.png baf0379ef8a9c88c.png

4. إنشاء إطار التطبيق باستخدام نشاط "خرائط Google"

  1. في شاشة الترحيب في "استوديو Android"، اختَر بدء مشروع جديد في "استوديو Android".
  2. في علامة التبويب الهاتف والجهاز اللوحي، اختَر نشاط "خرائط Google".

c9c80aa8211a8761.png

يظهر مربّع الحوار ضبط مشروعك. في هذا القسم، يمكنك تسمية تطبيقك وإنشاء الحزمة استنادًا إلى نطاقك.

في ما يلي إعدادات تطبيق باسم Current Place يتوافق مع الحزمة com.google.codelab.currentplace.

37f5b93b94ee118c.png

  1. اختَر Java كلغة، ثم اختَر استخدام عناصر androidx*.

احتفِظ بالإعدادات التلقائية لبقية الإعدادات.

  1. انقر على إنهاء.

5- إضافة ملحقات "خدمات Google" إلى ملف Gradle البرمجي

للوصول إلى أذونات تحديد الموقع الجغرافي في Android، عليك استخدام واجهة برمجة التطبيقات Google Location and Activity Recognition API من "خدمات Google Play". لمزيد من المعلومات حول إضافة واجهة برمجة التطبيقات هذه وواجهات برمجة التطبيقات الأخرى الخاصة بـ "خدمات Google Play"، يمكنك الاطّلاع على مقالة إعداد "خدمات Google Play".

تحتوي مشاريع "استوديو Android" عادةً على ملفَّي build.gradle. أحدهما للمشروع بشكل عام والآخر للتطبيق. إذا كان لديك مستكشف "مشروع استوديو Android" في طريقة العرض Android، سيظهر كلاهما في المجلد Gradle Scripts. عليك تعديل ملف build.gradle (Module: app) لإضافة خدمات Google.

f3043429cf719c47.png

  1. أضِف سطرَين إلى القسم dependencies لإضافة خدمات Google الخاصة بالموقع الجغرافي وPlaces API ( نموذج الرمز البرمجي في السياق).

build.gradle (الوحدة: التطبيق)

plugins {
  id 'com.android.application'
}

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.google.codelab.currentplace"
        minSdkVersion 19
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.0.2'
    implementation 'com.google.android.gms:play-services-maps:16.1.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test:runner:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'

    implementation 'com.google.android.gms:play-services-location:16.0.0'
    implementation 'com.google.android.libraries.places:places:1.1.0'
}

6. تفعيل واجهات برمجة تطبيقات "منصة خرائط Google" والحصول على مفتاح واجهة برمجة تطبيقات

في خطوة التفعيل التالية، عليك تفعيل حزمة تطوير البرامج بالاستناد إلى بيانات "خرائط Google" لتطبيقات Android وPlaces API.

إعداد Google Maps Platform

إذا لم يكن لديك حساب على Google Cloud Platform ومشروع مفعَّل فيه نظام الفوترة، يُرجى الاطّلاع على دليل البدء باستخدام Google Maps Platform لإنشاء حساب فوترة ومشروع.

  1. في Cloud Console، انقر على القائمة المنسدلة الخاصة بالمشروع واختَر المشروع الذي تريد استخدامه في هذا الدرس العملي.

  1. فعِّل واجهات برمجة التطبيقات وحِزم تطوير البرامج (SDK) في Google Maps Platform المطلوبة لهذا الدرس العملي في Google Cloud Marketplace. لإجراء ذلك، اتّبِع الخطوات الواردة في هذا الفيديو أو هذه المستندات.
  2. أنشئ مفتاح واجهة برمجة التطبيقات في صفحة بيانات الاعتماد في Cloud Console. يمكنك اتّباع الخطوات الواردة في هذا الفيديو أو هذه المستندات. تتطلّب جميع الطلبات إلى "منصة خرائط Google" مفتاح واجهة برمجة تطبيقات.

انسخ مفتاح واجهة برمجة التطبيقات الذي أنشأته للتو. ارجع إلى "استوديو Android" وابحث عن الملف google_maps_api.xml ضمن Android > app > res > values.

استبدِل YOUR_KEY_HERE بمفتاح واجهة برمجة التطبيقات الذي نسخته.

aa576e551a7a1009.png

اكتمل الآن إعداد تطبيقك.

7. تعديل ملف التنسيق

  1. في "مستكشف المشروع"، افتح الملف activity_maps.xml في Android > app > res > layout.

4e0d986480c57efa.png

  1. سيتم فتح واجهة المستخدم الأساسية على يسار الشاشة، مع علامات تبويب في الأسفل تتيح لك اختيار "التصميم" أو "محرّر النصوص" للتصميم. اختَر نص، واستبدِل المحتوى الكامل لملف التصميم بما يلي:

activity_maps.xml

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    android:orientation="vertical">

    <androidx.appcompat.widget.Toolbar
        android:id="@+id/toolbar"
        android:minHeight="?attr/actionBarSize"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:titleTextColor="@android:color/white"
        android:background="@color/colorPrimary" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <fragment
            android:id="@+id/map"
            android:name="com.google.android.gms.maps.SupportMapFragment"
            android:layout_width="match_parent"
            android:layout_height="349dp"
            tools:context=".MapsActivity" />

        <ListView
            android:id="@+id/listPlaces"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>

</LinearLayout>

سيؤدي ذلك إلى ظهور واجهة مستخدم بالشكل التالي:

1bf786808a4697ce.png

8. إعداد شريط التطبيق

لتزويد المستخدم بزر ينقر عليه عندما يريد اختيار مكانه الحالي، أضِف شريط تطبيقات يتضمّن رمزًا يعثر على مكان المستخدم الحالي ويعرض الأماكن المحتملة القريبة. ستظهر

3a17c92b613a26c5.png

على الهاتف، يظهر الرمز فقط. على جهاز لوحي يتضمّن مساحة أكبر، يتم تضمين النص أيضًا.

إنشاء الرمز

  1. في "مستكشف المشاريع"، انقر على Android > التطبيق، ثم انقر بزر الماوس الأيمن على المجلد res واختَر جديد > عنصر صورة.

يفتح استوديو مواد العرض.

  1. في قائمة نوع الرمز، انقر على رموز شريط الإجراءات وعلامات التبويب.
  2. أدخِل اسمًا لمادة العرض ic_geolocate.
  3. اختَر صور قصاصات فنية كنوع مادة العرض**.**
  4. انقر على الرسم بجانب الرسومات الجاهزة.

سيؤدي ذلك إلى فتح نافذة اختيار الرمز.

  1. اختَر رمزًا.

يمكنك استخدام شريط البحث للعثور على رموز ذات صلة بغرضك.

  1. ابحث عن location واختَر رمزًا ذا صلة بالموقع الجغرافي.

رمز موقعي الجغرافي هو الرمز نفسه المستخدَم في تطبيق "خرائط Google" عندما يريد المستخدم توجيه الكاميرا إلى موقعه الجغرافي الحالي.

  1. انقر على موافق > التالي > إنهاء، وتأكَّد من وجود مجلد جديد باسم drawable يحتوي على ملفات الرموز الجديدة.

b9e0196137ed18ae.png

إضافة موارد السلاسل

  1. في "مستكشف المشاريع"، انقر على Android > app > res > values وافتح الملف strings.xml.
  2. أضِف الأسطر التالية بعد <string name="title_activity_maps">Map</string>:

strings.xml

    <string name="action_geolocate">Pick Place</string>
    <string name="default_info_title">Default Location</string>
    <string name="default_info_snippet">No places found, because location permission is disabled.</string>

يُستخدَم السطر الأول في شريط التطبيق عندما تتوفّر مساحة لتضمين تصنيف نصي بجانب الرمز. أما العلامات الأخرى، فتُستخدم لتحديد الأماكن التي تضيفها إلى الخريطة.

سيظهر الرمز البرمجي في الملف على النحو التالي:

<resources>
    <string name="app_name">Current Place</string>
    <string name="title_activity_maps">Map</string>
    <string name="action_geolocate">Pick Place</string>
    <string name="default_info_title">Default Location</string>
    <string name="default_info_snippet">No places found, because location permission is disabled.</string>
</resources>

إضافة شريط التطبيق

  1. في "مستكشف المشاريع"، انقر على Android > app، ثم انقر بزر الماوس الأيمن على المجلد res واختَر جديد > دليل لإنشاء دليل فرعي جديد ضمن app/src/main/res.
  2. أدخِل اسمًا للدليل menu.
  3. انقر بزر الماوس الأيمن على المجلد menu واختَر جديد > ملف.
  4. أدخِل اسم الملف menu.xml.
  5. ألصِق الرمز التالي:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <!-- "Locate me", should appear as action button if possible -->
    <item
        android:id="@+id/action_geolocate"
        android:icon="@drawable/ic_geolocate"
        android:title="@string/action_geolocate"
        app:showAsAction="always|withText" />

</menu>

تعديل نمط شريط التطبيق

  1. في &quot;مستكشف المشاريع&quot;، وسِّع Android > app > res > values وافتح الملف styles.xml بداخله.
  2. في العلامة <style>، عدِّل السمة الرئيسية لتصبح "Theme.AppCompat.NoActionBar".
  3. سجِّل السمة name التي ستستخدمها في الخطوة التالية.

styles.xml

<style name="AppTheme" parent="Theme.AppCompat.NoActionBar">

تعديل مظهر التطبيق في ملف AndroidManifest.xml

  1. انقر على Android > app > manifests وافتح الملف AndroidManifest.xml.
  2. ابحث عن السطر android:theme وعدِّل القيمة أو أكِّد أنّها @style/AppTheme.

AndroidManifest.xml

   <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

أنت الآن جاهز لبدء الترميز.

9- إعداد التطبيق

  1. في "مستكشف المشروع"، ابحث عن الملف MapsActivity.java.

يكون هذا الملف في المجلد الذي يتوافق مع الحزمة التي أنشأتها لتطبيقك في الخطوة 1.

8b0fa27d417f5f55.png

  1. افتح الملف وسيتم نقلك إلى محرِّر رموز Java البرمجية.

استيراد حزمة تطوير البرامج (SDK) الخاصة بـ Places والتبعيات الأخرى

أضِف هذه الأسطر في أعلى MapsActivity.java، مع استبدال عبارات الاستيراد الحالية.

وهي تتضمّن عمليات الاستيراد الحالية وتضيف العديد من عمليات الاستيراد الأخرى المستخدَمة في الرمز البرمجي في هذا الدرس التطبيقي حول الترميز.

MapsActivity.java

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;

import com.google.android.gms.common.api.ApiException;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;

import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.Task;
import com.google.android.libraries.places.api.Places;
import com.google.android.libraries.places.api.model.Place;
import com.google.android.libraries.places.api.model.PlaceLikelihood;
import com.google.android.libraries.places.api.net.FindCurrentPlaceRequest;
import com.google.android.libraries.places.api.net.FindCurrentPlaceResponse;
import com.google.android.libraries.places.api.net.PlacesClient;

import java.util.Arrays;
import java.util.List;

تعديل توقيع الصف

تستخدِم Places API مكوّنات AndroidX لتوفير توافق مع الإصدارات القديمة، لذا عليك تحديدها لتوسيع نطاق AppCompatActivity. وهي تحلّ محلّ الإضافة FragmentActivity التي يتم تحديدها تلقائيًا لنشاط الخرائط.

public class MapsActivity extends AppCompatActivity implements OnMapReadyCallback {

إضافة متغيّرات الصف

بعد ذلك، عليك تعريف متغيرات الفئة المختلفة المستخدَمة في طرق الفئة المختلفة. وتشمل هذه العناصر عناصر واجهة المستخدم ورموز الحالة. يجب أن تكون هذه السمة أسفل تعريف المتغيّر GoogleMap mMap مباشرةً.

    // New variables for Current Place picker
    private static final String TAG = "MapsActivity";
    ListView lstPlaces;
    private PlacesClient mPlacesClient;
    private FusedLocationProviderClient mFusedLocationProviderClient;

    // The geographical location where the device is currently located. That is, the last-known
    // location retrieved by the Fused Location Provider.
    private Location mLastKnownLocation;

    // A default location (Sydney, Australia) and default zoom to use when location permission is
    // not granted.
    private final LatLng mDefaultLocation = new LatLng(-33.8523341, 151.2106085);
    private static final int DEFAULT_ZOOM = 15;
    private static final int PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION = 1;
    private boolean mLocationPermissionGranted;

    // Used for selecting the Current Place.
    private static final int M_MAX_ENTRIES = 5;
    private String[] mLikelyPlaceNames;
    private String[] mLikelyPlaceAddresses;
    private String[] mLikelyPlaceAttributions;
    private LatLng[] mLikelyPlaceLatLngs;

تعديل طريقة onCreate

عليك تعديل طريقة onCreate للتعامل مع أذونات المستخدم في وقت التشغيل لخدمات الموقع الجغرافي، وإعداد عناصر واجهة المستخدم وإنشاء عميل Places API.

أضِف أسطر الرمز التالية المتعلقة بشريط أدوات الإجراءات وإعداد طرق العرض وعميل Places إلى نهاية طريقة onCreate() الحالية.

MapsActivity.java onCreate()‎

   @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_maps);
        // Obtain the SupportMapFragment and get notified when the map is ready to be used.
        SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
                .findFragmentById(R.id.map);
        mapFragment.getMapAsync(this);

        //
        // PASTE THE LINES BELOW THIS COMMENT
        //
        
        // Set up the action toolbar
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        // Set up the views
        lstPlaces = (ListView) findViewById(R.id.listPlaces);

        // Initialize the Places client
        String apiKey = getString(R.string.google_maps_key);
        Places.initialize(getApplicationContext(), apiKey);
        mPlacesClient = Places.createClient(this);
        mFusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
    }

إضافة رمز لقائمة شريط التطبيق

تضيف هاتان الطريقتان قائمة شريط التطبيق (مع عنصر واحد، وهو رمز "اختيار مكان") وتتعاملان مع نقرة المستخدم على الرمز.

انسخ هاتين الطريقتَين إلى ملفك بعد طريقة onCreate.

‫MapsActivity.java onCreateOptionsMenu() وonOptionsItemSelected()

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu, menu);

        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
           case R.id.action_geolocate:
                
                // COMMENTED OUT UNTIL WE DEFINE THE METHOD
                // Present the current place picker
                // pickCurrentPlace();
                return true;

            default:
                // If we got here, the user's action was not recognized.
                // Invoke the superclass to handle it.
                return super.onOptionsItemSelected(item);

        }
    }

تجربة الميزة

  1. من Android Studio، انقر على تشغيل أو قائمة "تشغيل" > تشغيل "التطبيق".

28bea91c68c36fb2.png

  1. يُطلب منك اختيار هدف النشر. من المفترض أن يظهر المحاكي قيد التشغيل في هذه القائمة. اختَرها، وسينشر Android Studio التطبيق على المحاكي.

f44658ca91f6f41a.png

بعد بضع لحظات، يتم فتح التطبيق. تظهر الخريطة في وسطها مدينة سيدني في أستراليا، مع الزرّ الفردي وقائمة الأماكن غير المعبّأة.

68eb8c70f4748350.png

لا ينتقل تركيز الخريطة إلى الموقع الجغرافي للمستخدم إلا إذا طلبت الإذن بالوصول إلى الموقع الجغرافي للجهاز.

10. طلب أذونات تحديد الموقع الجغرافي والتعامل معها

طلب أذونات تحديد الموقع الجغرافي بعد أن تصبح الخريطة جاهزة

  1. حدِّد طريقة باسم getLocationPermission تطلب أذونات المستخدم.

ألصِق هذا الرمز أسفل طريقة onOptionsSelected التي أنشأتها للتو.

MapsActivity.java getLocationPermission()

    private void getLocationPermission() {
        /*
         * Request location permission, so that we can get the location of the
         * device. The result of the permission request is handled by a callback,
         * onRequestPermissionsResult.
         */
        mLocationPermissionGranted = false;
        if (ContextCompat.checkSelfPermission(this.getApplicationContext(),
                android.Manifest.permission.ACCESS_FINE_LOCATION)
                == PackageManager.PERMISSION_GRANTED) {
            mLocationPermissionGranted = true;
        } else {
            ActivityCompat.requestPermissions(this,
                    new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION},
                    PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION);
        }
    }
  1. أضِف سطرَين إلى نهاية طريقة onMapReady الحالية لتفعيل عناصر التحكّم في التكبير/التصغير وطلب أذونات الموقع الجغرافي من المستخدم.

MapsActivity.java onMapReady()

   @Override
    public void onMapReady(GoogleMap googleMap) {
        mMap = googleMap;

        // Add a marker in Sydney and move the camera
        LatLng sydney = new LatLng(-34, 151);
        mMap.addMarker(new MarkerOptions().position(sydney).title("Marker in Sydney"));
        mMap.moveCamera(CameraUpdateFactory.newLatLng(sydney));

        //
        // PASTE THE LINES BELOW THIS COMMENT
        //

        // Enable the zoom controls for the map
        mMap.getUiSettings().setZoomControlsEnabled(true);

        // Prompt the user for permission.
        getLocationPermission();

    }

التعامل مع نتيجة الأذونات المطلوبة

عندما يردّ المستخدم على مربّع حوار طلب الإذن، يستدعي نظام التشغيل Android وظيفة رد الاتصال هذه.

الصِق هذا الرمز بعد طريقة getLocationPermission():

MapsActivity.java onRequestPermissionsResult()

   /**
     * Handles the result of the request for location permissions
     */
    @Override
    public void onRequestPermissionsResult(int requestCode,
                                           @NonNull String permissions[],
                                           @NonNull int[] grantResults) {
        mLocationPermissionGranted = false;
        switch (requestCode) {
            case PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION: {
                // If request is cancelled, the result arrays are empty.
                if (grantResults.length > 0
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    mLocationPermissionGranted = true;
                }
            }
        }
    }

11. الحصول على الموقع الجغرافي الحالي واسترداد الأماكن المحتملة

عندما ينقر المستخدم على اختيار مكان في شريط التطبيق، يستدعي التطبيق الطريقة pickCurrentPlace()، التي تستدعي الطريقة getDeviceLocation() التي حدّدتها سابقًا. تستدعي الطريقة getDeviceLocation طريقة أخرى، وهي getCurrentPlaceLikelihoods,، بعد استرداد آخر موقع جغرافي للجهاز.

استدعاء واجهة برمجة التطبيقات findCurrentPlace والتعامل مع الردّ

تنشئ getCurrentPlaceLikelihoods findCurrentPlaceRequest وتستدعي مهمة findCurrentPlace في Places API. إذا كانت المهمة ناجحة، ستعرض findCurrentPlaceResponse، الذي يحتوي على قائمة بعناصر placeLikelihood. يتضمّن كلّ منها عددًا من الخصائص، بما في ذلك اسم المكان وعنوانه، واحتمالية وجودك في هذا المكان (قيمة مزدوجة من 0 إلى 1). تتعامل هذه الطريقة مع الردّ من خلال إنشاء قوائم بتفاصيل الأماكن من placeLikelihoods.

يتكرّر هذا الرمز خلال خمسة أماكن يُرجّح أن تكون هي الأنسب، ويضيف الأماكن التي تزيد احتمالية أن تكون هي الأنسب عن 0 إلى قائمة يتم عرضها بعد ذلك. إذا أردت عرض أكثر من خمسة أو أقل، عدِّل الثابت M_MAX_ENTRIES.

الصِق هذا الرمز بعد طريقة onMapReady.

MapsActivity.java getCurrentPlaceLikelihoods()

   private void getCurrentPlaceLikelihoods() {
        // Use fields to define the data types to return.
        List<Place.Field> placeFields = Arrays.asList(Place.Field.NAME, Place.Field.ADDRESS,
                Place.Field.LAT_LNG);

        // Get the likely places - that is, the businesses and other points of interest that
        // are the best match for the device's current location.
        @SuppressWarnings("MissingPermission") final FindCurrentPlaceRequest request =
                FindCurrentPlaceRequest.builder(placeFields).build();
        Task<FindCurrentPlaceResponse> placeResponse = mPlacesClient.findCurrentPlace(request);
        placeResponse.addOnCompleteListener(this,
                new OnCompleteListener<FindCurrentPlaceResponse>() {
                    @Override
                    public void onComplete(@NonNull Task<FindCurrentPlaceResponse> task) {
                        if (task.isSuccessful()) {
                            FindCurrentPlaceResponse response = task.getResult();
                            // Set the count, handling cases where less than 5 entries are returned.
                            int count;
                            if (response.getPlaceLikelihoods().size() < M_MAX_ENTRIES) {
                                count = response.getPlaceLikelihoods().size();
                            } else {
                                count = M_MAX_ENTRIES;
                            }

                            int i = 0;
                            mLikelyPlaceNames = new String[count];
                            mLikelyPlaceAddresses = new String[count];
                            mLikelyPlaceAttributions = new String[count];
                            mLikelyPlaceLatLngs = new LatLng[count];

                            for (PlaceLikelihood placeLikelihood : response.getPlaceLikelihoods()) {
                                Place currPlace = placeLikelihood.getPlace();
                                mLikelyPlaceNames[i] = currPlace.getName();
                                mLikelyPlaceAddresses[i] = currPlace.getAddress();
                                mLikelyPlaceAttributions[i] = (currPlace.getAttributions() == null) ?
                                        null : TextUtils.join(" ", currPlace.getAttributions());
                                mLikelyPlaceLatLngs[i] = currPlace.getLatLng();

                                String currLatLng = (mLikelyPlaceLatLngs[i] == null) ?
                                        "" : mLikelyPlaceLatLngs[i].toString();

                                Log.i(TAG, String.format("Place " + currPlace.getName()
                                        + " has likelihood: " + placeLikelihood.getLikelihood()
                                        + " at " + currLatLng));

                                i++;
                                if (i > (count - 1)) {
                                    break;
                                }
                            }


                            // COMMENTED OUT UNTIL WE DEFINE THE METHOD
                            // Populate the ListView
                            // fillPlacesList();
                        } else {
                            Exception exception = task.getException();
                            if (exception instanceof ApiException) {
                                ApiException apiException = (ApiException) exception;
                                Log.e(TAG, "Place not found: " + apiException.getStatusCode());
                            }
                        }
                    }
                });
    }

تحريك كاميرا الخريطة إلى الموقع الجغرافي الحالي للجهاز

في حال منح المستخدم الإذن، يجلب التطبيق آخر موقع جغرافي للمستخدم وينقل الكاميرا إلى منتصف هذا الموقع الجغرافي.

إذا رفض المستخدم منح الإذن، ينقل التطبيق الكاميرا ببساطة إلى الموقع الجغرافي التلقائي المحدّد بين الثوابت في بداية هذه الصفحة (في نموذج الرمز البرمجي، يكون الموقع الجغرافي التلقائي هو سيدني، أستراليا).

الصِق هذا الرمز بعد طريقة getPlaceLikelihoods():

MapsActivity.java getDeviceLocation()

    private void getDeviceLocation() {
        /*
         * Get the best and most recent location of the device, which may be null in rare
         * cases when a location is not available.
         */
        try {
            if (mLocationPermissionGranted) {
                Task<Location> locationResult = mFusedLocationProviderClient.getLastLocation();
                locationResult.addOnCompleteListener(this, new OnCompleteListener<Location>() {
                    @Override
                    public void onComplete(@NonNull Task<Location> task) {
                        if (task.isSuccessful()) {
                            // Set the map's camera position to the current location of the device.
                            mLastKnownLocation = task.getResult();
                            Log.d(TAG, "Latitude: " + mLastKnownLocation.getLatitude());
                            Log.d(TAG, "Longitude: " + mLastKnownLocation.getLongitude());
                            mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(
                                    new LatLng(mLastKnownLocation.getLatitude(),
                                            mLastKnownLocation.getLongitude()), DEFAULT_ZOOM));
                        } else {
                            Log.d(TAG, "Current location is null. Using defaults.");
                            Log.e(TAG, "Exception: %s", task.getException());
                            mMap.moveCamera(CameraUpdateFactory
                                    .newLatLngZoom(mDefaultLocation, DEFAULT_ZOOM));
                        }

                       getCurrentPlaceLikelihoods();
                    }
                });
            }
        } catch (SecurityException e)  {
            Log.e("Exception: %s", e.getMessage());
        }
    }

التحقّق من أذونات تحديد الموقع الجغرافي عندما ينقر المستخدم على "اختيار مكان"

عندما ينقر المستخدم على اختيار مكان، تتحقّق هذه الطريقة من أذونات الموقع الجغرافي وتطلب من المستخدم منح الإذن إذا لم يتم منحه.

إذا منح المستخدم الإذن، ستطلب الطُرق getDeviceLocation لبدء عملية الحصول على الأماكن المحتملة الحالية.

  1. أضِف الطريقة التالية بعد getDeviceLocation():

‫MapsActivity.java pickCurrentPlace()

   private void pickCurrentPlace() {
        if (mMap == null) {
            return;
        }

        if (mLocationPermissionGranted) {
            getDeviceLocation();
        } else {
            // The user has not granted permission.
            Log.i(TAG, "The user did not grant location permission.");

            // Add a default marker, because the user hasn't selected a place.
            mMap.addMarker(new MarkerOptions()
                    .title(getString(R.string.default_info_title))
                    .position(mDefaultLocation)
                    .snippet(getString(R.string.default_info_snippet)));

            // Prompt the user for permission.
            getLocationPermission();
        }
    }
  1. بعد تحديد pickCurrentPlace، ابحث عن السطر في onOptionsItemSelected() الذي يستدعي pickCurrentPlace وأزِل التعليق منه.

MapsActivity.java onOptionItemSelected()

           case R.id.action_geolocate:

                // COMMENTED OUT UNTIL WE DEFINE THE METHOD
                // Present the Current Place picker
                pickCurrentPlace();
                return true;

تجربة الميزة

إذا شغّلت التطبيق الآن ونقرت على اختيار مكان، من المفترض أن يطلب منك منح أذونات الوصول إلى الموقع الجغرافي.

  • إذا منحت الإذن، سيتم حفظ هذا الخيار المفضّل ولن يُطلب منك منحه مرة أخرى. إذا رفضت منح الإذن، سيُطلب منك ذلك في المرة التالية التي تنقر فيها على الزر.
  • على الرغم من أنّ getPlaceLikelihoods قد استردّ الأماكن الحالية المحتملة، إلا أنّ ListView لا يعرضها بعد. في "استوديو Android"، يمكنك النقر على ⌘6 للاطّلاع على السجلات في Logcat للعبارات التي تم وضع علامة MapsActivity عليها للتحقّق من أنّ الطرق الجديدة تعمل بشكل صحيح.
  • في حال منح الإذن، ستتضمّن السجلات بيانًا خاصًا بتطبيق Latitude: وبيانًا خاصًا بتطبيق Longitude: يعرضان الموقع الجغرافي الذي تم رصده للجهاز. إذا كنت قد استخدمت "خرائط Google" والقائمة الموسّعة للمحاكي سابقًا لتحديد موقع جغرافي للمحاكي، ستعرض هذه العبارات هذا الموقع الجغرافي.
  • إذا نجح طلب findCurrentPlace، ستتضمّن السجلات خمس عبارات تطبع أسماء المواقع الجغرافية الخمسة الأكثر احتمالاً.

d9896a245b81bf3.png

12. ملء أداة اختيار "المكان الحالي"

إعداد معالج للأماكن المحدّدة

لنفكّر في ما نريد أن يحدث عندما ينقر المستخدم على عنصر في ListView. لتأكيد اختيار المستخدم للمكان الذي يتواجد فيه حاليًا، يمكنك إضافة علامة إلى الخريطة في ذلك المكان. إذا نقر المستخدم على هذا العلامة، ستظهر نافذة معلومات تعرض اسم المكان وعنوانه.

ألصِق معالج النقر هذا بعد طريقة pickCurrentPlace.

MapsActivity.java listClickedHandler

    private AdapterView.OnItemClickListener listClickedHandler = new AdapterView.OnItemClickListener() {
        public void onItemClick(AdapterView parent, View v, int position, long id) {
            // position will give us the index of which place was selected in the array
            LatLng markerLatLng = mLikelyPlaceLatLngs[position];
            String markerSnippet = mLikelyPlaceAddresses[position];
            if (mLikelyPlaceAttributions[position] != null) {
                markerSnippet = markerSnippet + "\n" + mLikelyPlaceAttributions[position];
            }

            // Add a marker for the selected place, with an info window
            // showing information about that place.
            mMap.addMarker(new MarkerOptions()
                    .title(mLikelyPlaceNames[position])
                    .position(markerLatLng)
                    .snippet(markerSnippet));

           // Position the map's camera at the location of the marker.
            mMap.moveCamera(CameraUpdateFactory.newLatLng(markerLatLng));
        }
    };

تعبئة ListView

بعد أن أصبحت لديك قائمة بالأماكن التي من المرجّح أنّ المستخدم يزورها حاليًا، يمكنك عرض هذه الخيارات للمستخدم في ListView. يمكنك أيضًا ضبط أداة معالجة النقرات ListView لاستخدام أداة معالجة النقرات التي حدّدتها للتو.

ألصِق هذه الطريقة بعد معالج النقر:

MapsActivity.java fillPlacesList()

    private void fillPlacesList() {
        // Set up an ArrayAdapter to convert likely places into TextViews to populate the ListView
        ArrayAdapter<String> placesAdapter =
                new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mLikelyPlaceNames);
        lstPlaces.setAdapter(placesAdapter);
        lstPlaces.setOnItemClickListener(listClickedHandler);
    }

بعد تحديد fillPlacesList، ابحث عن السطر بالقرب من نهاية findPlaceLikelihoods الذي يستدعي fillPlacesList وأزِل التعليق منه.

MapsActivity.java fillPlaceLikelihoods()

               // COMMENTED OUT UNTIL WE DEFINE THE METHOD
                // Populate the ListView
                fillPlacesList();

هذا كل الرمز البرمجي المطلوب لأداة اختيار "الموقع الجغرافي الحالي".

13. تشغيل التطبيق

اختبار اختيار مكان

  1. تشغيل التطبيق مرة أخرى

عند النقر على اختيار مكان هذه المرة، سيملأ التطبيق القائمة بأماكن مسماة قريبة من الموقع الجغرافي. بالقرب من هذا الموقع في "ماوي"، تقع أماكن مثل Ululani's Hawaiian Shave Ice وSugar Beach Bake Shop. بما أنّ الأماكن المتعدّدة قريبة جدًا من إحداثيات الموقع الجغرافي، هذه قائمة بالأماكن المحتملة التي قد تكون فيها.

  1. انقر على اسم مكان في ListView.

سيظهر لك محدّد تمت إضافته إلى الخريطة.

  1. انقر على العلامة.

يمكنك الاطّلاع على تفاصيل المكان.

e52303cc0de6a513.png 864c74342fb52a01.png

تجربة موقع جغرافي مختلف

إذا أردت تغيير موقعك الجغرافي وكنت تستخدم المحاكي، لن يتم تعديل الموقع الجغرافي للجهاز تلقائيًا عند تعديل إحداثيات الموقع الجغرافي في القائمة الموسّعة للمحاكي.

لحلّ هذه المشكلة، اتّبِع الخطوات التالية لاستخدام تطبيق "خرائط Google" الأصلي لفرض تحديثات على الموقع الجغرافي للمحاكي:

  1. افتح خرائط Google.
  2. انقر على ... > الموقع الجغرافي لتغيير خطوط الطول والعرض إلى إحداثيات جديدة، ثم انقر على إرسال.
  3. على سبيل المثال، يمكنك استخدام خط العرض: 49.2768 وخط الطول: -123.1142 لضبط الموقع الجغرافي على وسط مدينة فانكوفر، كندا.
  4. تأكَّد من أنّ "خرائط Google" قد أعادت التوسّط في إحداثياتك الجديدة. قد تحتاج إلى النقر على زر موقعي الجغرافي في تطبيق "خرائط Google" لطلب إعادة التوسيط.
  5. ارجع إلى تطبيق "مكاني الحالي" وانقر على اختيار مكان للحصول على الخريطة بالإحداثيات الجديدة والاطّلاع على قائمة جديدة بالأماكن الحالية المحتملة.

9adb99d1ce25c184.png

هذا كل ما في الأمر! لقد أنشأت تطبيقًا بسيطًا يتحقّق من الأماكن في الموقع الجغرافي الحالي ويقدّم لك احتمالًا للأماكن التي تتواجد فيها. استمتعوا بالمشاهدة.

الآن، يمكنك تشغيل التطبيق مع التعديلات التي أجريتها لإكمال خطوة المكافأة هذه.

14. الخطوات التالية

لمنع سرقة مفتاح واجهة برمجة التطبيقات، عليك تأمينه لكي لا يتمكّن من استخدامه سوى تطبيق Android الخاص بك. في حال عدم فرض قيود على المفتاح، يمكن لأي مستخدم لديه المفتاح استخدامه لاستدعاء واجهات برمجة التطبيقات في "منصة خرائط Google"، ما يؤدي إلى تحصيل رسوم منك.

الحصول على شهادة SHA-1

ستحتاج إلى ذلك لاحقًا عند فرض قيود على مفاتيح واجهة برمجة التطبيقات. في ما يلي مجموعة من التعليمات للحصول على شهادة تصحيح الأخطاء.

في نظام التشغيل Linux أو macOS، افتح نافذة المحطة الطرفية وأدخِل ما يلي:

keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android

بالنسبة إلى Windows Vista وWindows 7، شغِّل الأمر التالي:

keytool -list -v -keystore "%USERPROFILE%\.android\debug.keystore" -alias androiddebugkey -storepass android -keypass android

من المفترَض أن تظهر لك نتيجة مثل هذه:

Alias name: androiddebugkey
Creation date: Jan 01, 2013
Entry type: PrivateKeyEntry
Certificate chain length: 1
Certificate[1]:
Owner: CN=Android Debug, O=Android, C=US
Issuer: CN=Android Debug, O=Android, C=US
Serial number: 4aa9b300
Valid from: Mon Jan 01 08:04:04 UTC 2013 until: Mon Jan 01 18:04:04 PST 2033
Certificate fingerprints:
     MD5:  AE:9F:95:D0:A6:86:89:BC:A8:70:BA:34:FF:6A:AC:F9
     SHA1: BB:0D:AC:74:D3:21:E1:43:07:71:9B:62:90:AF:A1:66:6E:44:5D:75
     Signature algorithm name: SHA1withRSA
     Version: 3

يحتوي السطر الذي يبدأ بـ SHA1 على الملف المرجعي لشهادة SHA-1. البصمة هي تسلسل من 20 رقمًا سداسيًا عشريًا مزدوجًا مفصولاً بنقطتين.

عندما تكون مستعدًا لإصدار تطبيق، اتّبِع التعليمات الواردة في هذه المستندات لاسترداد شهادة الإصدار.

إضافة قيود إلى مفتاح واجهة برمجة التطبيقات

  1. في Cloud Console، انتقِل إلى واجهات برمجة التطبيقات والخدمات > بيانات الاعتماد.

يجب أن يكون المفتاح الذي استخدمته لهذا التطبيق مُدرَجًا ضمن "مفاتيح واجهة برمجة التطبيقات".

  1. انقر على 6454a04865d551e6.png لتعديل إعدادات المفتاح.

316b052c621ee91c.png

  1. في صفحة مفتاح واجهة برمجة التطبيقات، بعد قيود المفتاح، اضبط قيود التطبيق باتّباع الخطوات التالية:
  2. اختَر تطبيقات Android واتّبِع التعليمات.
  3. انقر على إضافة سؤال.
  4. أدخِل اسم الحزمة والملف المرجعي لشهادة SHA-1 (تم استرداده في القسم السابق).

على سبيل المثال:

com.google.codelab.currentplace
BB:0D:AC:74:D3:21:E1:43:07:71:9B:62:90:AF:A1:66:6E:44:5D:75s
  1. للحصول على حماية إضافية، اضبط قيود واجهة برمجة التطبيقات باتّباع الخطوات التالية.
  2. بعد القيود المفروضة على واجهة برمجة التطبيقات، اختَر حصر المفتاح.
  3. اختَر "حزمة تطوير البرامج بالاستناد إلى بيانات خرائط Google" لتطبيقات Android وPlaces API.
  4. انقر على تم وحفظ.

15. تهانينا

لقد أنشأت تطبيقًا بسيطًا يتحقّق من الأماكن الأكثر احتمالاً في الموقع الجغرافي الحالي ويضيف علامة إلى الخريطة للمكان الذي يختاره المستخدم.

مزيد من المعلومات