สร้างแอปการนำทางแบบง่ายสำหรับ Android ด้วย Navigation SDK ของแพลตฟอร์ม Google Maps
เกี่ยวกับ Codelab นี้
1 ก่อนเริ่มต้น
โค้ดแล็บนี้จะสอนวิธีสร้างแอป Android แบบง่ายที่ใช้ Google Maps Platform Navigation SDK เพื่อไปยังปลายทางที่กำหนดค่าไว้ล่วงหน้า
นี่คือหน้าตาของแอปเมื่อคุณดำเนินการเสร็จสิ้น
ข้อกำหนดเบื้องต้น
- ความรู้เกี่ยวกับการพัฒนาแอป Android ขั้นพื้นฐานใน Kotlin
- มีความรู้พื้นฐานเกี่ยวกับแนวคิดของ Google Maps SDK เช่น แผนที่ ตำแหน่ง พิกัด
สิ่งที่คุณจะได้เรียนรู้
- วิธีสร้างแอป Android แบบง่ายที่ใช้ Navigation SDK เพื่อนำทางไปยังปลายทาง
- วิธีผสานรวม Navigation SDK จากที่เก็บของ Google Maven ระยะไกล
- วิธีจัดการสิทธิ์เข้าถึงตำแหน่งและข้อตกลงของผู้ใช้กับข้อกำหนดของผู้ใช้ปลายทางของ Navigation SDK
- วิธีเริ่มต้น SDK
- วิธีกำหนดจุดหมายและเริ่มคำแนะนำการนำทาง
สิ่งที่ต้องมี
- ติดตั้ง Android Studio เวอร์ชันเสถียรล่าสุด Codelab นี้สร้างขึ้นโดยใช้ Android Studio Jellyfish หากคุณใช้เวอร์ชันอื่น ลักษณะและเลย์เอาต์ของอินเทอร์เฟซและคอมโพเนนต์อาจแตกต่างกันไป
- บัญชี Google และโปรเจ็กต์ที่เปิดใช้การเรียกเก็บเงิน
- อุปกรณ์ Android ในโหมดนักพัฒนาซอฟต์แวร์ที่เปิดใช้การแก้ไขข้อบกพร่อง USB หรือโปรแกรมจำลอง Android บริการใดก็ตามที่คุณเลือกต้องเป็นไปตามข้อกำหนดขั้นต่ำสำหรับ Navigation SDK
2 ตั้งค่า
หากยังไม่มีบัญชี Google Cloud Platform และโปรเจ็กต์ที่เปิดใช้การเรียกเก็บเงิน ให้ตั้งค่าโปรเจ็กต์ Google Cloud โดยทําตามวิธีการเริ่มต้นใช้งาน Google Maps Platform ที่ https://developers.google.com/maps/gmp-get-started
เลือกโปรเจ็กต์ Google Cloud ในคอนโซล
ใน Cloud Console ให้คลิกเมนูแบบเลื่อนลงของโปรเจ็กต์และเลือกโปรเจ็กต์ที่ต้องการใช้สำหรับ Codelab นี้
เปิดใช้ Navigation SDK ในโปรเจ็กต์
เปิดใช้ Google Maps Platform API และ SDK ที่จำเป็นสำหรับ Codelab นี้ใน Google Cloud Marketplace
ไปที่ API และ บริการ > ไลบรารีใน Google Cloud Console และค้นหา "Navigation SDK"
คุณจะเห็นผลการค้นหา 1 รายการ
คลิกผลการค้นหา Navigation SDK เพื่อเปิดหน้ารายละเอียดผลิตภัณฑ์ คลิกปุ่ม "เปิดใช้" เพื่อเปิดใช้ SDK ในโปรเจ็กต์
ทําขั้นตอนนี้ซ้ำสําหรับ Google Maps SDK สําหรับ Android
สร้างคีย์ API
สร้างคีย์ API ในหน้าข้อมูลเข้าสู่ระบบของ Cloud Console คุณสามารถทำตามขั้นตอนในขั้นตอนที่ 3 ของส่วนการเริ่มต้นอย่างรวดเร็วในการเริ่มต้นใช้งาน Google Maps Platform คำขอไปยัง Google Maps Platform ทั้งหมดต้องใช้คีย์ API
3 รับไฟล์โปรเจ็กต์ตัวอย่าง
ส่วนนี้จะอธิบายวิธีตั้งค่าโปรเจ็กต์ Android Studio พื้นฐานที่ว่างเปล่าโดยการโคลนไฟล์จากที่เก็บ GitHub สำหรับ Codelab นี้ ที่เก็บ GitHub จะมีโค้ด Codelab ทั้งก่อนและหลังเวอร์ชัน Codelab จะเริ่มต้นด้วยเทมเพลตโปรเจ็กต์ที่ว่างเปล่า และสร้างเป็นสถานะที่เสร็จสมบูรณ์แล้ว คุณใช้โปรเจ็กต์ที่เสร็จแล้วในรีโปเป็นข้อมูลอ้างอิงได้หากพบปัญหา
โคลนที่เก็บ GitHub นี้เพื่อรับโค้ดสําหรับ Codelab นี้
git clone https://github.com/googlemaps-samples/codelab-navigation-101-android-kotlin.git
หากไม่ได้ติดตั้ง git ให้คลิกปุ่มนี้เพื่อรับรหัส
เพื่อช่วยให้คุณเริ่มต้นใช้งานได้เร็วที่สุด ที่เก็บจะมีโค้ดเริ่มต้นบางส่วนในโฟลเดอร์ Starter
เพื่อช่วยให้คุณทำตามขั้นตอนไปพร้อมกันด้วย Codelab นี้ โปรเจ็กต์เริ่มต้นมี UI ของแอปพื้นฐานและการกำหนดค่าบิลด์ แต่ไม่มีการเพิ่ม Navigation SDK นอกจากนี้ยังมีโปรเจ็กต์ Solution
ที่เสร็จแล้วในกรณีที่คุณต้องการข้ามไปข้างหน้าหรือตรวจสอบความคืบหน้าได้ทุกเมื่อ
เปิดที่เก็บที่โคลนใน Android Studio
เมื่อโคลนที่เก็บข้อมูลในเครื่องแล้ว ให้ใช้ Android Studio เพื่อเปิดโฟลเดอร์ Starter
เป็นโปรเจ็กต์ที่มีอยู่
- จากกล่องโต้ตอบ "ยินดีต้อนรับสู่ Android Studio" ให้คลิกปุ่ม "เปิด"
- ไปยังโฟลเดอร์ที่คุณบันทึกไว้ที่เก็บที่โคลนและเลือกโฟลเดอร์
Starter
ภายในระดับบนสุด "codelab-navigation-101-android-kotlin
" โฟลเดอร์ - ตรวจสอบว่าโปรเจ็กต์สร้างและทํางานได้
เพิ่มอุปกรณ์เสมือนหรือเชื่อมต่ออุปกรณ์ฮาร์ดแวร์
หากต้องการเชื่อมต่ออุปกรณ์ Android กับคอมพิวเตอร์ ให้ทำตามวิธีการของ Android Studio ในวิธีเรียกใช้แอปในอุปกรณ์ฮาร์ดแวร์ หรือจะกำหนดค่าอุปกรณ์เสมือนโดยใช้โปรแกรมจัดการอุปกรณ์เสมือน (AVD) ของ Android ก็ได้ เมื่อเลือกโปรแกรมจำลอง ให้ตรวจสอบว่าคุณเลือกภาพที่มี Google APIs
ใน Android Studio ให้คลิกตัวเลือกเมนู "เรียกใช้" หรือไอคอนปุ่มเล่น เลือกอุปกรณ์ตามข้อความแจ้ง
4 เพิ่ม Navigation SDK ลงในแอป
เพิ่มไลบรารี Navigation SDK และคีย์ API ลงในโปรเจ็กต์ของคุณ
หากต้องการเพิ่มไลบรารี Navigation SDK ลงในแอป คุณต้องแก้ไข app-level build.gradle.kts
เพื่อดึงข้อมูล Navigation SDK จากที่เก็บ Maven ของ Google และกำหนดค่าหมายเลขเวอร์ชัน
สร้างตัวแปรในการกำหนดค่าบิลด์เพื่อจัดเก็บหมายเลขเวอร์ชัน Navigation SDK
ตั้งค่าตัวแปรใน build.gradle.kts
ระดับแอปเพื่อเก็บค่าของเวอร์ชัน Navigation SDK ที่ใช้ในแอป คุณจึงเปลี่ยนไปใช้เวอร์ชันล่าสุดในอนาคตได้ง่ายๆ
ตรวจสอบบันทึกประจำรุ่น SDK การนำทางเพื่อดูหมายเลขเวอร์ชันล่าสุด
val navSdkVersion by extra("6.0.0")
นอกจากนี้ คุณยังแก้ไขค่าของตัวแปรนี้และตัวแปรอื่นๆ โดยใช้กล่องโต้ตอบที่แสดงในเมนูไฟล์ > โครงสร้างโปรเจ็กต์ > ตัวแปร
เพิ่มทรัพยากร Dependency ในการกำหนดค่าบิลด์
ตอนนี้ให้เพิ่มทรัพยากร Dependency ของ API ต่อไปนี้ไปยังบล็อกทรัพยากร Dependency ในระดับแอป build.gradle.kts.
เวอร์ชันที่ใช้จะเป็นค่า ${navSdkVersion}
ซึ่งคุณเพิ่งตั้งค่าใน build.gradle.kts
ระดับแอป
dependencies {
// Include the Google Navigation SDK.
api("com.google.android.libraries.navigation:navigation:${navSdkVersion}")
...
เพิ่มคีย์ API
ใช้ปลั๊กอินข้อมูลลับ Gradle เพื่อจัดการคีย์ API
เราขอแนะนำให้ใช้ปลั๊กอิน Secrets Gradle เพื่อจัดการคีย์ API ในแอปอย่างปลอดภัย เพิ่มปลั๊กอินลงในเทมเพลตโปรเจ็กต์เริ่มต้นเป็นทรัพยากร Dependency ในไฟล์ 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
ด้วยคีย์ API จัดเก็บคีย์ในไฟล์นี้เนื่องจาก secrets.properties
ได้รับการยกเว้นไม่ให้ตรวจสอบในระบบควบคุมเวอร์ชัน
MAPS_API_KEY=YOUR_API_KEY
ดูข้อมูลเพิ่มเติมเกี่ยวกับหัวข้อนี้ได้ที่เพิ่มคีย์ API ลงในแอปในเอกสารประกอบของ 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
ค่าเริ่มต้นจะหยุดแอปไม่ให้ทํางานขณะรันไทม์ โดยมีข้อผิดพลาดเกี่ยวกับคีย์ API
ตรวจสอบว่าไฟล์ Manifest ของ Android ใช้คีย์ API ที่คุณระบุ
เปิดแอป/src/main/AndroidManifest.xml คุณจะเห็นว่ามีการใช้พร็อพเพอร์ตี้ MAPS_API_KEY
เพื่อตั้งค่าคีย์ API สำหรับแอปพลิเคชัน
<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 กำหนดค่าสิทธิ์ของแอปและเพิ่ม UI พื้นฐาน
ขอสิทธิ์เข้าถึงตำแหน่งที่แน่นอน
Navigation 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" />
เพิ่มกิจกรรมการเปิดตัวด้วย UI พื้นฐาน
เมื่อแอปทำงาน จะต้องมีโค้ดที่ทำงานในช่วงเริ่มต้นเพื่อตรวจสอบว่าผู้ใช้ได้ให้สิทธิ์เข้าถึงตำแหน่งของตนหรือไม่ และจัดการกับแต่ละสถานการณ์ที่เป็นไปได้ รวมถึงขอสิทธิ์ในกรณีที่ยังไม่ได้รับการให้สิทธิ์ โดยให้เพิ่มอินเทอร์เฟซผู้ใช้พื้นฐานลงในแอป Codelab นี้ใช้ UI ที่สร้างขึ้นเมื่อคุณสร้างกิจกรรม Views ใหม่ที่ไม่มีข้อมูลใน Android Studio คุณจะปรับเปลี่ยนการตั้งค่านี้เพื่อตรวจสอบสิทธิ์เข้าถึงตำแหน่งก่อนเพิ่มโค้ดลงในกิจกรรมสำหรับ UI การนำทาง
เปิดไฟล์ MainActivity.kt
ในโปรแกรมแก้ไขโค้ดและตรวจสอบโค้ด ซึ่งจะแสดง UI พื้นฐาน
ขอสิทธิ์เข้าถึงตำแหน่งขณะรันไทม์
แอปของคุณจะต้องทริกเกอร์คำขอเข้าถึงตำแหน่งที่แน่นอนก่อนที่ Navigation SDK จะเริ่มต้น
โปรดเพิ่มโค้ดลงในคลาส 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 เพิ่มอินเทอร์เฟซผู้ใช้สำหรับการนําทาง
การเพิ่ม UI การนําทางทำได้ 2 วิธี ได้แก่ SupportNavigationFragment
หรือ NavigationView
Codelab จะใช้ NavigationView
เพื่อความง่าย
แก้ไขเลย์เอาต์
แก้ไข res/layout/activity_main.xml
เพื่อเพิ่มเลย์เอาต์สําหรับ NavigationView
- เปิดไฟล์และเปลี่ยนเป็นมุมมองโค้ด
- แทนที่เนื้อหาทั้งหมดของไฟล์ด้วยเลย์เอาต์ใหม่ของ
NavigationView
ภายในRelativeLayout
ดังตัวอย่างด้านล่าง เนื่องจากคุณจะเพิ่มมุมมองการนำทางลงในแอปเท่านั้น เลย์เอาต์แบบง่ายก็เพียงพอแล้ว - กำหนดรหัส 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 Studio ให้เปิดไฟล์ MainActivity.kt ในเครื่องมือแก้ไข
เพิ่มโค้ดการตั้งค่าพื้นฐานบางอย่างเพื่อให้แน่ใจว่าประสบการณ์การนำทางในแอปทำงานได้อย่างถูกต้อง ในไฟล์ MainActivity.kt ให้ทำการเปลี่ยนแปลงต่อไปนี้
- ประกาศตัวแปรในคลาส
MainActivity
เพื่ออ้างอิงNavigationView
private lateinit var navView: NavigationView
- เพิ่มโค้ดลงในเมธอด
onCreate()
เพื่อรับการอ้างอิงNavigationView
navView = findViewById(R.id.navigation_view)
navView.onCreate(savedInstanceState)
- เพิ่มโค้ดบางส่วนลงในเมธอด
onCreate()
เพื่อให้หน้าจอติดสว่างระหว่างการแนะนำการนำทาง
// Ensure the screen stays on during nav.
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
- แก้ไขโค้ดที่เรียก
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
}
- เพิ่มเมธอด
showToast()
ในชั้นเรียนเพื่อแสดงความคิดเห็นให้กับผู้ใช้:
private fun showToast(errorMessage: String) {
Toast.makeText(this@MainActivity, errorMessage, Toast.LENGTH_LONG).show()
}
7 เริ่มต้น Navigation SDK
เมื่อตั้งค่ากิจกรรมการนำทางขั้นพื้นฐานเสร็จแล้ว คุณจะเริ่มต้น Navigation SDK ได้ โดยเพิ่มโค้ดต่อไปนี้ลงในไฟล์ 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 เพิ่ม Listener สําหรับเหตุการณ์การนําทางที่สําคัญ
เมื่อผู้ใช้ทําตามคําแนะนํา Navigation SDK จะเรียกเหตุการณ์ที่แจ้งให้แอปทราบเกี่ยวกับการเปลี่ยนแปลงสถานะที่สําคัญระหว่างเส้นทาง เช่น เมื่อผู้ใช้เปลี่ยนเส้นทางหรือไปถึงจุดหมาย ในไฟล์ MainActivity.kt ให้เพิ่ม Listener เพื่อจัดการเหตุการณ์เหล่านี้
- ภายในคลาส
MainActivity
ให้ประกาศตัวแปร 2 รายการเพื่ออ้างอิงออบเจ็กต์ Listener เหตุการณ์ ดังนี้
private var arrivalListener: Navigator.ArrivalListener? = null
private var routeChangedListener: Navigator.RouteChangedListener? = null
- เพิ่มเมธอด
registerNavigationListeners()
เพื่อตั้งค่า Listeners เมื่อเริ่มต้นใช้งาน 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)
}
}
- เพิ่มการเรียก
registerNavigationListeners()
จากโค้ดการเรียกกลับonNavigatorReady
ในเมธอดinitializeNavigationApi
ดังนี้
override fun onNavigatorReady(navigator: Navigator) {
// store a reference to the Navigator object
mNavigator = navigator
//listen for events en route
registerNavigationListeners()
}
- กำหนดค่าอินเทอร์เฟซผู้ใช้ คุณสามารถควบคุมแง่มุมต่างๆ ของอินเทอร์เฟซผู้ใช้การนำทางได้เมื่อการแนะนำกําลังทํางาน การปรับแต่งที่สำคัญอย่างหนึ่งคือตำแหน่งของกล้อง เพิ่มการเรียกใช้เมธอด
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)
- เพิ่มการเรียกใช้
GoogleMap.followMyLocation
เพื่อระบุCameraPerspective
GoogleMap
มีการเข้าถึงผ่านเมธอดNavigatorView.getMapAsync()
ดังนี้
navView.getMapAsync {
googleMap ->
googleMap.followMyLocation(GoogleMap.CameraPerspective.TILTED)
}
- โปรดใช้เมธอดต่อไปนี้ในชั้นเรียน
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 ให้ทำการเปลี่ยนแปลงต่อไปนี้
- เพิ่มเมธอด
navigateToPlace()
ใหม่ซึ่งตั้งค่าปลายทางการนำทางและยอมรับพารามิเตอร์placeId
/**
* Requests directions from the user's current location to a specific place (provided by the
* Place ID).
*/
private fun navigateToPlace(placeId: String) {
}
- ในเมธอด
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
}
- เพิ่มโค้ดต่อไปนี้ลงในเมธอด
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
ซึ่งเหมาะสำหรับรถยนต์ 4 ล้อ เมธอด setDestinations()
จะแสดงผลออบเจ็กต์ ListenableResultFuture
ที่มีออบเจ็กต์ RouteStatus
RouteStatus
จะระบุว่าพบเส้นทางไปยังปลายทางหรือไม่ และช่วยให้คุณจัดการสถานะข้อผิดพลาดต่างๆ ได้หากไม่พบเส้นทาง
- เปลี่ยนแปลงการกำหนดค่าเพิ่มเติมเพื่อปรับปรุงประสบการณ์การนำทางของผู้ใช้ ดังนี้
// 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)
)
}
การเปลี่ยนแปลงเหล่านี้รวมถึงการปรับปรุงต่อไปนี้
- การซ่อนแถบการทำงานเพื่อเพิ่มพื้นที่สูงสุดสำหรับ UI การนำทาง
- การเปิดใช้การนำทางด้วยเสียงเพื่อพูดการแจ้งเตือนและคำแนะนำการนำทาง
- การตั้งค่าเครื่องจำลองสำหรับการแก้ไขข้อบกพร่องโดยระบุตัวคูณความเร็ว
- ค้นหารหัสสถานที่ที่จะใช้เป็นปลายทาง ทางที่ดีที่สุดคือไม่ไกลจากสถานที่ตั้งของผู้ใช้จนเกินไป ใช้ยูทิลิตีเครื่องมือค้นหารหัสสถานที่ของ Google Maps Platform หรือรับรหัสสถานที่จากการเรียก Places API
หากกำลังจำลองการนำทาง คุณสามารถตั้งค่าตำแหน่งของผู้ใช้ในโค้ดหรือนำมาจากอุปกรณ์ที่เชื่อมต่อได้ Codelab จะถือว่าคุณกำลังจำลองสถานที่ตั้งในลอนดอน สหราชอาณาจักร
- เพิ่มออบเจ็กต์ที่แสดงร่วมกันลงในคลาส
MainActivity
เพื่อจัดเก็บตำแหน่งเริ่มต้นและรหัสสถานที่ Codelab จะใช้สถานที่เริ่มต้นในลอนดอนและรหัสสถานที่ของ Trafalgar Square
companion object{
const val TRAFALGAR_SQUARE ="ChIJH-tBOc4EdkgRJ8aJ8P1CUxo" //London, UK
val startLocation = LatLng(51.345678, -0.1234456)
}
- เพิ่มการเรียกใช้เมธอด
navigateToPlace()
จาก Callback ของ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 รายการแรก โปรดดูข้อมูลเพิ่มเติมที่การใช้งานและการเรียกเก็บเงิน
การตั้งค่าตำแหน่ง
โดยค่าเริ่มต้น อุปกรณ์จำลองอาจตั้งค่าตำแหน่งเป็นวิทยาเขตของ Google ในเมืองเมาน์เทนวิว รัฐแคลิฟอร์เนีย เว้นแต่คุณจะตั้งค่าตำแหน่งในโค้ดหรือใช้กล่องโต้ตอบพร็อพเพอร์ตี้โปรแกรมจำลอง
หากเป็นเช่นนั้น คุณอาจพบว่าแอปไม่พบเส้นทางไปยังรหัสสถานที่ที่คุณกำหนดค่าไว้ (โดยค่าเริ่มต้นคือ Sydney Opera House, Sydney, Australia) ซึ่งจะมีการระบุโดยข้อความที่ระบุว่า "ไม่พบเส้นทาง" ซึ่งแสดงตามเมธอด showToast()
การเขียนโค้ดตำแหน่งเริ่มต้นแบบฮาร์ดโค้ด
หากต้องการตั้งค่าตำแหน่งอื่นในโค้ด ให้เพิ่มบรรทัดต่อไปนี้ในเมธอด navigateToPlace()
ใน MainActivity.kt ก่อนเรียก mNavigator.startGuidance()
:
mNavigator?.simulator?.setUserLocation(startLocation)
การเริ่มโปรแกรมจำลองในตำแหน่งเริ่มต้นที่คุณเลือก
หากต้องการตั้งค่าตำแหน่งอื่นในโปรแกรมจำลองอุปกรณ์ ให้เปิดโปรแกรมจำลองหากยังไม่ได้เปิดอยู่ แล้วคลิกเมนู 3 จุดที่มีเคล็ดลับเครื่องมือ "การควบคุมแบบขยาย" กล่องโต้ตอบที่เปิดขึ้นจะมีตัวเลือกเมนูสำหรับ "ตำแหน่ง"
ตัวอย่างเช่น หากคุณใช้รหัสสถานที่ของโรงอุปรากรซิดนีย์เป็นปลายทาง ให้เลือกสถานที่ในซิดนีย์ ออสเตรเลีย เช่น ค้นหา "หาดนพรัตน์" เลือกคำแนะนำและคลิก "บันทึกตำแหน่ง" ที่ด้านล่างขวาของกล่องโต้ตอบ คุณยังสามารถคลิก "บันทึกจุด" เพื่อเพิ่มสถานที่ตั้งลงในรายการที่บันทึกไว้เพื่อใช้ในอนาคต
หากคุณตั้งค่ารหัสสถานที่อื่นเป็นปลายทาง ให้เลือกสถานที่ใกล้เคียงกับรหัสนั้นเพื่อให้เส้นทางจำลองเป็นเส้นทางที่สมจริงและไม่ยาวจนเกินไปเพื่อให้แก้ไขข้อบกพร่องได้ง่าย
รีสตาร์ทแอป แล้วระบบจะนําไปยังปลายทาง
12 สู่ขั้นต่อไป
หากต้องการพัฒนาแอปให้ก้าวไปอีกขั้น ลองดูหัวข้อต่อไปนี้เพื่อเป็นแรงบันดาลใจ
- ฟังเหตุการณ์การนำทางเพิ่มเติม เพิ่มโค้ดเพื่อแสดงข้อความหากคนขับเปลี่ยนเส้นทางหรือเมื่อคนขับมาถึง
- ปรับแต่งอินเทอร์เฟซการนำทาง
- หากต้องการลองทำโจทย์ที่ยากขึ้น ให้ลองดูว่าคุณเพิ่มตัวควบคุมเครื่องมือเลือกสถานที่ของ Places API เพื่ออนุญาตให้ผู้ใช้กำหนดปลายทางได้หรือไม่ เคล็ดลับ: แอปเดโม Navigation SDK ใน GitHub มีตัวอย่างการใช้งาน
- ป้องกันปัญหาที่อาจเกิดขึ้นในการเรียกใช้ออบเจ็กต์ Navigator และ GoogleMap แบบไม่พร้อมกันโดยใช้แนวทางที่ใช้ในแอปสาธิตการนำทาง SDK ใน GitHub ในสถานการณ์แอปที่ซับซ้อนมากขึ้น ออบเจ็กต์เหล่านี้อาจเริ่มต้นไม่เสร็จสิ้นเมื่อโค้ดทำงาน เคล็ดลับ: คุณสามารถเพิ่มคลาส InitializedNavScope ที่ท้ายไฟล์ MainActivity.kt เพื่อการติดตั้งใช้งานที่รวดเร็ว