إنشاء تطبيق تنقّل بسيط لنظام التشغيل Android باستخدام حزمة تطوير البرامج (SDK) لميزة التنقّل في "منصّة خرائط Google"

1. قبل البدء

يعلّمك هذا الدرس التطبيقي حول الترميز كيفية إنشاء تطبيق Android بسيط يستخدم حزمة تطوير البرامج (SDK) الخاصة بخدمة "التنقّل" من "منصة خرائط Google" للتنقّل إلى وجهة تم ضبطها مسبقًا.

سيظهر تطبيقك بهذا الشكل عند الانتهاء.

b6c535afde7abd20.png

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

  • معرفة أساسية بتطوير تطبيقات Android باستخدام لغة Kotlin
  • يجب أن تكون على دراية ببعض المفاهيم الأساسية لحزمة تطوير البرامج (SDK) الخاصة بـ "خرائط Google"، مثل الخرائط والمواقع الجغرافية والإحداثيات.

ما ستتعلمه

  • كيفية إنشاء تطبيق Android بسيط يستخدم حزمة تطوير البرامج للتنقّل للوصول إلى وجهة
  • كيفية دمج حزمة تطوير البرامج (SDK) للتنقّل من مستودع Google Maven البعيد
  • كيفية إدارة أذونات الموقع الجغرافي وموافقة المستخدم على بنود المستخدم النهائي في Navigation SDK
  • كيفية إعداد حزمة تطوير البرامج (SDK)
  • كيفية تحديد وجهة وبدء إرشادات التنقّل

المتطلبات

  • يجب تثبيت أحدث إصدار ثابت من "استوديو Android". تم إنشاء هذا الدرس التطبيقي باستخدام Android Studio Jellyfish. إذا كنت تستخدم إصدارًا مختلفًا، قد يختلف مظهر وتصميم الواجهة والمكوّنات.
  • حساب Google ومشروع تم تفعيل الفوترة فيهما
  • جهاز Android في "وضع مطور البرامج" مع تفعيل تصحيح أخطاء الجهاز عبر USB، أو Android Emulator يجب أن يستوفي أي إصدار تختاره الحد الأدنى من متطلبات Navigation SDK.

2. طريقة الإعداد

إذا لم يكن لديك حساب على Google Cloud Platform ومشروع على السحابة الإلكترونية مفعّل فيه نظام الفوترة، عليك إعداد مشروعك على Google Cloud باتّباع تعليمات "بدء استخدام منصة خرائط Google" https://developers.google.com/maps/gmp-get-started

اختَر مشروع على السحابة الإلكترونية في وحدة التحكّم.

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

قائمة "اختيار المشروع" المنسدلة في Google Cloud Console

تفعيل حزمة تطوير البرامج (SDK) للتنقّل في مشروعك

فعِّل واجهات برمجة التطبيقات وحِزم تطوير البرامج (SDK) المطلوبة لهذا الدرس العملي في Google Cloud Marketplace.

انتقِل إلى "واجهات برمجة التطبيقات والخدمات" > "المكتبة" في Google Cloud Console وابحث عن "Navigation SDK".

من المفترض أن تظهر لك نتيجة بحث واحدة.

شاشة "مكتبة واجهات برمجة التطبيقات" في Google Cloud Console، تعرض صفحة Navigation SDK

انقر على نتيجة Navigation SDK لفتح صفحة التفاصيل. انقر على الزر "تفعيل" لتفعيل حزمة SDK في مشروعك.

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

إنشاء مفتاح واجهة برمجة تطبيقات

أنشئ مفتاح واجهة برمجة تطبيقات في صفحة بيانات الاعتماد في Cloud Console. يمكنك اتّباع الخطوات الواردة في الخطوة 3 من قسم "البدء السريع" في مقالة الخطوات الأولى لاستخدام "منصة خرائط Google". تتطلّب جميع الطلبات المُرسَلة إلى "منصة خرائط Google" مفتاح واجهة برمجة تطبيقات.

3- الحصول على ملفات المشروع النموذجية

يوضّح هذا القسم كيفية إعداد مشروع أساسي فارغ في "استوديو Android" من خلال استنساخ الملفات من مستودع GitHub لهذا الدرس التطبيقي حول الترميز. يحتوي مستودع Github على إصدارات التعليمات البرمجية للدرس التطبيقي حول الترميز قبل وبعد التعديل. سيبدأ الدرس العملي بنموذج مشروع فارغ وسيتضمّن خطوات للوصول إلى الحالة النهائية. يمكنك استخدام المشروع المكتمل في المستودع كمرجع إذا واجهتك مشكلة.

استنسِخ مستودع Github هذا للحصول على الرمز البرمجي لهذا الدرس التطبيقي حول الترميز.

git clone https://github.com/googlemaps-samples/codelab-navigation-101-android-kotlin.git

إذا لم يكن git مثبّتًا، انقر على هذا الزر للحصول على الرمز:

لمساعدتك على البدء بأسرع ما يمكن، يحتوي المستودع على بعض الرموز البرمجية الأولية في المجلد Starter لمساعدتك في متابعة هذا الدرس التطبيقي حول الترميز. يوفّر مشروع البداية واجهة مستخدم أساسية للتطبيق وإعدادات التصميم، ولكن لم تتم إضافة حزمة تطوير البرامج (SDK) الخاصة بخدمة Navigation إليه. يتوفّر أيضًا مشروع Solution مكتمل في حال أردت الانتقال إلى الخطوة التالية أو التحقّق من مستوى تقدّمك في أي وقت.

فتح المستودع الذي تم استنساخه في "استوديو Android"

بعد استنساخ المستودع محليًا، استخدِم "استوديو Android" لفتح المجلد Starter كمشروع حالي.

  1. من مربّع الحوار "مرحبًا بك في استوديو Android"، انقر على الزر "فتح".
  2. انتقِل إلى المجلد الذي حفظت فيه المستودع المستنسخ واختَر المجلد Starter داخل المجلد "codelab-navigation-101-android-kotlin" ذي المستوى الأعلى.
  3. تأكَّد من أنّ المشروع يتم إنشاؤه وتشغيله.

إضافة جهاز افتراضي أو ربط جهاز خارجي

لربط جهاز Android بجهاز الكمبيوتر، اتّبِع تعليمات استوديو Android حول كيفية تشغيل التطبيقات على جهاز خارجي. بدلاً من ذلك، يمكنك ضبط جهاز افتراضي باستخدام أداة إدارة أجهزة Android الافتراضية. عند اختيار محاكي، احرص على اختيار صورة تتضمّن Google APIs.

في استوديو Android، انقر على خيار القائمة "تشغيل" (Run) أو رمز زر التشغيل. اختَر جهازًا حسب التعليمات.

4. إضافة حزمة تطوير البرامج للتنقّل إلى تطبيقك

إضافة مكتبة Navigation SDK ومفتاح واجهة برمجة التطبيقات إلى مشروعك

لإضافة مكتبة Navigation SDK إلى تطبيقك، عليك تعديل ملف الإصدار على مستوى التطبيق build.gradle.kts لجلب حزمة Navigation SDK من مستودع Google Maven وتحديد رقم إصدار.

أنشئ متغيرًا في إعدادات الإصدار لتخزين رقم إصدار Navigation SDK.

اضبط متغيّرًا في build.gradle.kts على مستوى تطبيقك ليحتوي على قيمة إصدار Navigation SDK المستخدَم في تطبيقك، وذلك لتسهيل التغيير إلى أحدث إصدار في المستقبل.

راجِع ملاحظات إصدار Navigation SDK لمعرفة رقم أحدث إصدار.

val navSdkVersion by extra("6.0.0")

يمكنك أيضًا تعديل قيم هذا المتغيّر والمتغيّرات الأخرى باستخدام مربّع الحوار الذي يظهر عند النقر على "ملف" > "بنية المشروع" > "المتغيّرات":

668332736b67dc82.png

إضافة اعتمادية إلى إعدادات التصميم

الآن، أضِف الاعتمادية التالية لواجهة برمجة التطبيقات إلى قسم التبعيات في ملف build.gradle.kts. على مستوى التطبيق. سيكون الإصدار المستخدَم هو قيمة ${navSdkVersion} التي ضبطتها للتو في ملف build.gradle.kts على مستوى التطبيق:

dependencies {

   // Include the Google Navigation SDK.
   api("com.google.android.libraries.navigation:navigation:${navSdkVersion}")

...

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

استخدام المكوّن الإضافي Secrets Gradle لإدارة مفتاح واجهة برمجة التطبيقات

ننصحك باستخدام مكوّن Secrets Gradle الإضافي لإدارة مفتاح واجهة برمجة التطبيقات بشكل آمن في تطبيقك. تمت إضافة المكوّن الإضافي إلى نموذج المشروع الأوّلي كاعتمادية في ملف build.gradle.kts ذي المستوى الأعلى.

// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
    id("com.google.android.libraries.mapsplatform.secrets-gradle-plugin") version "2.0.1" apply false
    //... other plugin definitions here
}

افتح الملف secrets.properties في الدليل ذي المستوى الأعلى، ثم استبدِل YOUR_API_KEY بمفتاح واجهة برمجة التطبيقات. خزِّن مفتاحك في هذا الملف لأنّ secrets.properties مستبعد من إمكانية تسجيل الدخول إلى نظام التحكم في الإصدارات.

MAPS_API_KEY=YOUR_API_KEY

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

التحقّق من محتوى ملف local.defaults.properties

يحتوي المشروع الفارغ أيضًا على ملف local.defaults.properties في دليل المستوى الأعلى، وهو المجلد نفسه الذي يحتوي على ملف secrets.properties. افتحه ولاحظ الرمز التالي.

MAPS_API_KEY=DEFAULT_API_KEY

تتوفّر هذه السمة لتوفير قيمة احتياطية للخاصية MAPS_API_KEY في حال عدم إضافة secrets.properties إلى المشروع، وذلك لضمان عدم تعذُّر عمليات الإنشاء. ليس عليك تعديل هذا الملف. في حال عدم العثور على تعريف secrets.properties الخاص بـ MAPS_API_KEY، ستؤدي القيمة التلقائية إلى إيقاف التطبيق أثناء التشغيل، مع ظهور خطأ في مفتاح واجهة برمجة التطبيقات.

التأكّد من أنّ ملف AndroidManifest يستخدم مفتاح واجهة برمجة التطبيقات الذي حدّدته

افتح app/src/main/AndroidManifest.xml. ستلاحظ أنّه يتم استخدام السمة MAPS_API_KEY لضبط مفتاح واجهة برمجة التطبيقات للتطبيق:

<meta-data
    android:name="com.google.android.geo.API_KEY"
    android:value="${MAPS_API_KEY}" />

افتح ملف build.gradle.kts على مستوى التطبيق وابحث عن السمة secrets.

يجب ضبط إعداد propertiesFileName للمكوّن الإضافي على secrets.properties، ويجب أن يظهر defaultPropertiesFileName على النحو التالي: local.defaults.properties.

secrets {
    // Optionally specify a different file name containing your secrets.
    // The plugin defaults to "local.properties"
    propertiesFileName = "secrets.properties"

    // A properties file containing default secret values. This file can be
    // checked in version control.
    defaultPropertiesFileName = "local.defaults.properties"
}

احفظ جميع الملفات وزامِن مشروعك مع Gradle.

5- ضبط أذونات التطبيق وإضافة واجهة مستخدم أساسية

طلب إذن تحديد الموقع الجغرافي الدقيق

تعتمد حزمة تطوير البرامج (SDK) للتنقّل على إشارات نظام تحديد المواقع العالمي (GPS) لتعمل، لذا سيحتاج تطبيقك إلى طلب الإذن من المستخدم للوصول إلى بيانات الموقع الجغرافي الدقيق. أضِف الإذن بالوصول إلى الموقع الجغرافي الدقيق كعنصر فرعي للعنصر <manifest> في ملف AndroidManifest.xml.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" >
   <uses-permission 
      android:name="android.permission.ACCESS_FINE_LOCATION"
   />
</manifest>

يمكنك الاطّلاع على مزيد من المعلومات حول أذونات الموقع الجغرافي على Android في قسم طلب أذونات الموقع الجغرافي ضمن مستندات مطوّري تطبيقات Android.

لتشغيل تطبيقك على جهاز Android 14، اطلب إذن تحديد الموقع الجغرافي للخدمة التي تعمل في المقدّمة عن طريق إضافة علامة uses-permission التالية في الموقع الجغرافي نفسه الذي يتضمّن إذن الوصول إلى الموقع الجغرافي الدقيق:

<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />

إضافة نشاط تشغيل بواجهة مستخدم أساسية

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

افتح الملف MainActivity.kt في أداة تعديل الرموز وافحص الرمز الذي يعرض واجهة مستخدم أساسية.

طلب أذونات الوصول إلى الموقع الجغرافي في وقت التشغيل

يجب أن يفعّل تطبيقك طلب الوصول إلى الموقع الجغرافي الدقيق قبل بدء حزمة تطوير البرامج (SDK) الخاصة بخدمة Navigation.

لضمان إجراء عملية التحقّق هذه عند بدء تشغيل تطبيقك، أضِف بعض الرموز إلى فئة MainActivity، في طريقة onCreate() التي تم إلغاء تعريفها في النشاط.

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

    val permissions =
      if (VERSION.SDK_INT >= VERSION_CODES.TIRAMISU) {
        arrayOf(permission.ACCESS_FINE_LOCATION, permission.POST_NOTIFICATIONS)
      } else {
        arrayOf(permission.ACCESS_FINE_LOCATION)
      }

    if (permissions.any { !checkPermissionGranted(it) }) {

      if (permissions.any { shouldShowRequestPermissionRationale(it) }) {
        // Display a dialogue explaining the required permissions.
      }

      val permissionsLauncher =
        registerForActivityResult(
          RequestMultiplePermissions(),
          { permissionResults ->
            if (permissionResults.getOrDefault(permission.ACCESS_FINE_LOCATION, false)) {
              onLocationPermissionGranted()
            } else {
              finish()
            }
          },
        )

      permissionsLauncher.launch(permissions)
    } else {
      android.os.Handler(Looper.getMainLooper()).postDelayed({ onLocationPermissionGranted() }, SPLASH_SCREEN_DELAY_MILLIS)
    }
  }

  private fun checkPermissionGranted(permissionToCheck: String): Boolean =
    ContextCompat.checkSelfPermission(this, permissionToCheck) == PackageManager.PERMISSION_GRANTED

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

private fun onLocationPermissionGranted() {
   //code to initialize Navigation SDK will go here
}

أنشئ مشروعك. إذا ظهرت لك أي أخطاء في الإنشاء، ابحث عنها وأصلِحها.

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

6. إضافة واجهة مستخدم للتنقّل

هناك طريقتان لإضافة واجهة مستخدم Navigation: SupportNavigationFragment أو NavigationView.

لتبسيط الأمر، يستخدم الدرس التطبيقي NavigationView.

تعديل التنسيق

عدِّل res/layout/activity_main.xml لإضافة تصميم إلى NavigationView.

  1. افتح الملف وانتقِل إلى "طريقة عرض الرمز".
  2. استبدِل محتوى الملف بالكامل بتصميم جديد NavigationView داخل RelativeLayout كما في المثال أدناه. بما أنّك ستضيف فقط طريقة عرض للتنقّل إلى التطبيق، سيكون التصميم البسيط مناسبًا.
  3. امنح NavigationView رقم التعريف "@+id/navigation_view".
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="match_parent"
   android:layout_height="match_parent">
 <com.google.android.libraries.navigation.NavigationView
     android:id="@+id/navigation_view"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
      />
</RelativeLayout>

إعداد نشاط "التنقّل"

في "استوديو Android"، افتح ملف MainActivity.kt في المحرِّر.

أضِف بعض رموز الإعداد الأساسية لضمان عمل تجربة التنقّل بشكلٍ سليم في تطبيقك. في ملف MainActivity.kt، أدخِل التغييرات التالية:

  1. عرِّف متغيّرًا في فئة MainActivity للإشارة إلى NavigationView:
private lateinit var navView: NavigationView
  1. أضِف بعض الرموز إلى طريقة onCreate() للحصول على مرجع إلى NavigationView:
navView = findViewById(R.id.navigation_view)
navView.onCreate(savedInstanceState)
  1. أضِف بعض الرموز إلى طريقة onCreate() للتأكّد من بقاء الشاشة مضاءة أثناء عرض إرشادات التنقّل:
// Ensure the screen stays on during nav.
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
  1. عدِّل الرمز الذي يستدعي ViewCompat.setOnApplyWindowInsetsListener للإشارة إلى معرّف NavigationView.
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.navigation_view)) { v, insets ->
  val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
  v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
  insets
}
  1. أضِف طريقة showToast() إلى الفئة لعرض الملاحظات للمستخدم:
private fun showToast(errorMessage: String) {
   Toast.makeText(this@MainActivity, errorMessage, Toast.LENGTH_LONG).show()
}

7. إعداد حزمة تطوير البرامج للتنقّل

بعد إكمال عملية إعداد نشاط Navigation الأساسي، يمكنك إعداد حزمة تطوير البرامج (SDK) الخاصة بخدمة Navigation. لإجراء ذلك، أضِف الرمز التالي إلى ملف MainActivity.kt:

/** Starts the Navigation API, capturing a reference when ready. */
@SuppressLint("MissingPermission")
private fun initializeNavigationApi() {
   NavigationApi.getNavigator(
       this,
       object : NavigatorListener {
           override fun onNavigatorReady(navigator: Navigator) {
               // store a reference to the Navigator object
               mNavigator = navigator
               // code to start guidance will go here
           }

           override fun onError(@NavigationApi.ErrorCode errorCode: Int) {
               when (errorCode) {
                   NavigationApi.ErrorCode.NOT_AUTHORIZED -> {
                       // Note: If this message is displayed, you may need to check that
                       // your API_KEY is specified correctly in AndroidManifest.xml
                       // and is been enabled to access the Navigation API
                       showToast(
                           "Error loading Navigation API: Your API key is " +
                                   "invalid or not authorized to use Navigation."
                       )
                   }
                   NavigationApi.ErrorCode.TERMS_NOT_ACCEPTED -> {
                       showToast(
                           "Error loading Navigation API: User did not " +
                                   "accept the Navigation Terms of Use."
                       )
                   }
                   else -> showToast("Error loading Navigation API: $errorCode")
               }
           }
       },
   )

}

تنشئ هذه التعليمة البرمجية طريقة جديدة باسم initializeNavigationApi(). يحصل هذا الإجراء على مرجع إلى عنصر Navigator من خلال استدعاء NavigationApi.getNavigator() وينفّذ NavigatorListener للتعامل مع رد الاتصال.

يُرجى العِلم أنّه عند تهيئة Navigation API، سيتم استدعاء الطريقة NavigationListener.onNavigatorReady، مع تمرير العنصر Navigator كمعلَمة. سيعدّل الرمز أعلاه المتغيّر mNavigator الذي سبق أن عرّفته باستخدام العنصر Navigator الذي تمّت تهيئته والذي يتمّ تمريره إلى هذه الطريقة.

أخيرًا، أضِف طلبًا إلى طريقتك initializeNavigationApi من الطريقة onLocationPermissionGranted.

private fun onLocationPermissionGranted() {
   initializeNavigationApi()
}

8. إضافة أدوات معالجة لأحداث التنقّل الرئيسية

عندما يتّبع المستخدمون الإرشادات، ستطلق حزمة Navigation SDK أحداثًا يمكنها إعلام التطبيق بالتغييرات الرئيسية في الحالة أثناء الرحلة، مثل عندما يعيد المستخدم التوجيه أو يصل إلى وجهته. في ملف MainActivity.kt، أضِف أدوات معالجة للتعامل مع الأحداث التالية:

  1. ضِمن الفئة MainActivity، عرِّف متغيّرَين للإشارة إلى عناصر متتبِّع الأحداث:
private var arrivalListener: Navigator.ArrivalListener? = null
private var routeChangedListener: Navigator.RouteChangedListener? = null
  1. أضِف طريقة registerNavigationListeners() لإعداد أدوات الاستماع عند تهيئة Navigator. تستدعي هذه الطريقة Navigator.clearDestinations() لإعادة ضبط NavigationView عند تشغيل حدث Arrival:
/**
* Registers a number of example event listeners that show an on screen message when certain
* navigation events occur (e.g. the driver's route changes or the destination is reached).
*/
private fun registerNavigationListeners() {
   withNavigatorAsync {
       arrivalListener =
           Navigator.ArrivalListener { // Show an onscreen message
               showToast("User has arrived at the destination!")
               mNavigator?.clearDestinations()
           }
       mNavigator?.addArrivalListener(arrivalListener)

       routeChangedListener =
           Navigator.RouteChangedListener { // Show an onscreen message when the route changes
               showToast("onRouteChanged: the driver's route changed")
           }
       mNavigator?.addRouteChangedListener(routeChangedListener)
   }
}
  1. أضِف طلبًا إلى registerNavigationListeners() من رمز معاودة الاتصال onNavigatorReady في الطريقة initializeNavigationApi:
override fun onNavigatorReady(navigator: Navigator) {
   // store a reference to the Navigator object
   mNavigator = navigator

   //listen for events en route
   registerNavigationListeners()


}
  1. ضبط واجهة المستخدم يمكنك التحكّم في جوانب مختلفة من واجهة مستخدم التنقّل أثناء عرض الإرشادات. أحد أهم خيارات التخصيص هو موضع الكاميرا. أضِف طلبًا إلى طريقة setTaskRemovedBehaviour الخاصة بعنصر navigator الذي تم عرضه في onNavigatorReady على النحو التالي. سيؤدي ذلك إلى إنهاء الإرشادات والإشعارات في حال تم إغلاق التطبيق عن طريق التمرير سريعًا:
// Disables the guidance notifications and shuts down the app and background service
// when the user dismisses/swipes away the app from Android's recent tasks.
navigator.setTaskRemovedBehavior(Navigator.TaskRemovedBehavior.QUIT_SERVICE)
  1. أضِف طلبًا إلى GoogleMap.followMyLocation لتحديد CameraPerspective. يمكن الوصول إلى GoogleMap من خلال الطريقة NavigatorView.getMapAsync() على النحو التالي:
navView.getMapAsync {
   googleMap  ->
   googleMap.followMyLocation(GoogleMap.CameraPerspective.TILTED)
}
  1. لضمان عمل وظائف التنقّل بسلاسة طوال دورة حياة التطبيق، نفِّذ الطرق التالية في فئة MainActivity:
override fun onSaveInstanceState(savedInstanceState: Bundle) {
   super.onSaveInstanceState(savedInstanceState)

   navView.onSaveInstanceState(savedInstanceState)
}

override fun onTrimMemory(level: Int) {
   super.onTrimMemory(level)
   navView.onTrimMemory(level)
}

override fun onStart() {
   super.onStart()
   navView.onStart()
}

override fun onResume() {
   super.onResume()
   navView.onResume()
}

override fun onPause() {
   navView.onPause()
   super.onPause()
}

override fun onConfigurationChanged(configuration: Configuration) {
   super.onConfigurationChanged(configuration)
   navView.onConfigurationChanged(configuration)
}

override fun onStop() {
   navView.onStop()
   super.onStop()
}

override fun onDestroy() {
   navView.onDestroy()
   withNavigatorAsync {
       // Unregister event listeners to avoid memory leaks.
       if (arrivalListener != null) {
           navigator.removeArrivalListener(arrivalListener)
       }
       if (routeChangedListener != null) {
           navigator.removeRouteChangedListener(routeChangedListener)
       }

       navigator.simulator?.unsetUserLocation()
       navigator.cleanup()
   }
   super.onDestroy()
}

9- تحديد وجهة

أنت الآن جاهز لضبط وجهة وبدء إرشادات التنقّل. في ملف MainActivity.kt، نفِّذ التغييرات التالية:

  1. أضِف طريقة navigateToPlace() جديدة تحدّد وجهة التنقّل وتقبل المَعلمة placeId.
/**
* Requests directions from the user's current location to a specific place (provided by the
* Place ID).
*/
private fun navigateToPlace(placeId: String) {

}
  1. في طريقتك navigateToPlace()، استخدِم الطريقة Waypoint.builder() لإنشاء Waypoint من رقم تعريف المكان الذي تم تمريره إلى الطريقة. تعامَل مع الخطأ UnsupportedPlaceIdException الذي يمكن أن يحدث في الحالات التي لا يؤدي فيها رقم تعريف المكان إلى عنوان دقيق:
val waypoint: Waypoint? =
// Set a destination by using a Place ID (the recommended method)
try {
   Waypoint.builder().setPlaceIdString(placeId).build()
} catch (e: Waypoint.UnsupportedPlaceIdException) {
   showToast("Place ID was unsupported.")
   return
}
  1. أضِف الرمز التالي إلى طريقتك navigateToPlace() لضبط وجهة باستخدام Waypoint:
val pendingRoute = mNavigator?.setDestination(waypoint)

// Set an action to perform when a route is determined to the destination
pendingRoute?.setOnResultListener { code ->
   when (code) {
       RouteStatus.OK -> {
           // Code to start guidance will go here
       }

       RouteStatus.ROUTE_CANCELED -> showToast("Route guidance canceled.")
       RouteStatus.NO_ROUTE_FOUND,
       RouteStatus.NETWORK_ERROR ->
           // TODO: Add logic to handle when a route could not be determined
           showToast("Error starting guidance: $code")

       else -> showToast("Error starting guidance: $code")
   }
}

يحتوي العنصر Navigator على الطريقة setDestinations() التي يمكن أن تأخذ مجموعة متنوعة من المَعلمات. الخيار الأساسي هو تقديم Waypoint. سيتم ضبط وضع التنقّل تلقائيًا على DRIVING، وهو مناسب للسيارات ذات الأربع عجلات. تعرض الطريقة setDestinations() عنصر ListenableResultFuture يحتوي على عنصر RouteStatus. سيشير RouteStatus إلى ما إذا تم العثور على مسار إلى الوجهة، وسيسمح لك بالتعامل مع حالات الخطأ المختلفة في حال عدم العثور على مسار.

  1. إجراء تغييرات إضافية على الإعدادات لتحسين تجربة المستخدم في التنقّل:
// Hide the toolbar to maximize the navigation UI
supportActionBar?.hide()

// Enable voice audio guidance (through the device speaker)
mNavigator?.setAudioGuidance(Navigator.AudioGuidance.VOICE_ALERTS_AND_GUIDANCE)


// Simulate vehicle progress along the route (for demo/debug builds)
if (BuildConfig.DEBUG) {
   mNavigator?.simulator?.simulateLocationsAlongExistingRoute(
       SimulationOptions().speedMultiplier(5f)
   )
}

تشمل هذه التغييرات التحسينات التالية:

  • إخفاء شريط الإجراءات لتوفير أكبر مساحة لواجهة مستخدم التنقّل
  • تفعيل الإرشاد الصوتي لقول التنبيهات وتعليمات التنقّل
  • إعداد المحاكي لتصحيح الأخطاء من خلال تحديد مضاعِف السرعة
  1. ابحث عن رقم تعريف المكان الذي سيعمل كوجهتك. من المفترض أن يكون هذا الموقع الجغرافي ليس بعيدًا جدًا عن الموقع الجغرافي للمستخدم. استخدِم أداة البحث عن رقم تعريف المكان في منصة خرائط Google أو احصل على رقم تعريف مكان من خلال طلب بيانات من واجهة برمجة التطبيقات في Places API.

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

  1. أضِف عنصرًا مصاحبًا إلى فئة MainActivity لتخزين موقع جغرافي للبدء ومعرّف مكان. سيستخدم الدرس التطبيقي حول الترميز موقعًا جغرافيًا في لندن ورقم تعريف المكان الخاص بساحة ترافلغار:
companion object{
   const val TRAFALGAR_SQUARE ="ChIJH-tBOc4EdkgRJ8aJ8P1CUxo" //London, UK
   val startLocation = LatLng(51.345678, -0.1234456)
}
  1. أضِف طلبًا إلى طريقتك navigateToPlace() من معاودة الاتصال onNavigatorReady داخل الطريقة initializeNavigationApi، وأضِف فرعًا من المنطق سيتم تنفيذه في "وضع تصحيح الأخطاء"، والذي يضبط الموقع الجغرافي للمستخدم:
// Disables the guidance notifications and shuts down the app and background service
// when the user dismisses/swipes away the app from Android's recent tasks.
navigator.setTaskRemovedBehavior(Navigator.TaskRemovedBehavior.QUIT_SERVICE)

mNavigator = navigator

if (BuildConfig.DEBUG) {
   mNavigator?.simulator?.setUserLocation(MainActivity.startLocation)
}
//listen for events en route
registerNavigationListeners()

navView.getMapAsync {
   googleMap  ->
   googleMap.followMyLocation(GoogleMap.CameraPerspective.TILTED)
}

//navigate to a destination
navigateToPlace(MainActivity.TRAFALGAR_SQUARE)

10. إنشاء الرمز البرمجي وتشغيله

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

ملاحظة: سيؤدي تشغيل التطبيق إلى استدعاء طريقة setDestinations() التي تتكبّد رسومًا بعد استخدام أول 1,000 وجهة. يمكنك الاطّلاع على مقالة الاستخدام والفوترة لمزيد من المعلومات.

93aa433000a14dfc.png

مربّع الحوار الخاص ببنود الخدمة للمستخدمين النهائيين في حزمة Navigation SDK

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

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

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

طريقة عرض الخريطة في تطبيق &quot;التنقّل&quot; تعرض مكتب Google في ماونتن فيو، كاليفورنيا

الترميز الثابت لموقع البداية

لضبط موقع جغرافي مختلف في الرمز، أضِف السطر التالي في طريقة navigateToPlace() في ملف MainActivity.kt، قبل طلب mNavigator.startGuidance():

mNavigator?.simulator?.setUserLocation(startLocation)

بدء المحاكي في موقع جغرافي تلقائي من اختيارك

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

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

مربّع الحوار &quot;عناصر التحكّم الموسّعة&quot; في &quot;مدير جهاز Android&quot;، والذي يعرض أداة اختيار مكان وخريطة في وسط شاطئ بوندي في أستراليا

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

أعِد تشغيل التطبيق، وسيتم نقلك الآن إلى الوجهة.

لقطة شاشة لتطبيق &quot;خرائط Google&quot; يقدّم إرشادات إلى الوجهة

11. تهانينا!

لقد أكملت هذا الدرس التطبيقي حول الترميز. أحسنت، لقد وصلت إلى وجهتك. مع أطيب التحيّات :-)

55812f33256c0596.png

12. الاستخدام المتقدم

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