במדריך הזה מוסבר איך לתכנן מסלול באפליקציה באמצעות Navigation SDK ל-Android. המדריך הזה מבוסס על ההנחה שכבר שילבתם את Navigation SDK באפליקציה, כמו שמתואר במאמר הגדרת הפרויקט.
סיכום
- מוסיפים רכיב בממשק המשתמש לאפליקציה, כקטע ניווט או כתצוגת ניווט. הרכיב הזה בממשק המשתמש מוסיף לפעילות את המפה האינטראקטיבית ואת ממשק המשתמש של הניווט המפורט.
- בקשת הרשאות מיקום. האפליקציה צריכה לבקש הרשאת מיקום כדי לקבוע את מיקום המכשיר.
- מפעילים את ה-SDK באמצעות המחלקה
NavigationApi. מגדירים יעד ושולטים בניווט המפורט באמצעות המחלקה
Navigator. התהליך כולל שלושה שלבים:- מגדירים יעד באמצעות
setDestination(). - מתחילים בניווט באמצעות
startGuidance(). - אפשר להשתמש ב-
getSimulator()כדי לדמות את התקדמות הרכב לאורך המסלול, לצורך בדיקה, ניפוי באגים והדגמה של האפליקציה.
- מגדירים יעד באמצעות
יוצרים ומריצים את האפליקציה.
הצגת הקוד
הוספת רכיב בממשק המשתמש לאפליקציה
בקטע הזה מוסברות שתי דרכים להוספת המפה האינטראקטיבית וממשק המשתמש להצגת ניווט מפורט. ברוב המקרים, מומלץ להשתמש ב-NavigationFragment, שהוא wrapper של NavigationView, במקום לבצע אינטראקציה ישירות עם NavigationView. מידע נוסף זמין במאמר שיטות מומלצות לאינטראקציה עם מפת הניווט
.
שימוש ב-Navigation Fragment
NavigationFragment הוא רכיב ממשק המשתמש שמציג את הפלט החזותי של הניווט, כולל מפה אינטראקטיבית והוראות מפורטות. אפשר להצהיר על ה-fragment בקובץ הפריסה ב-XML, כמו שמוצג כאן:
<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:name="com.google.android.libraries.navigation.NavigationFragment"
android:id="@+id/navigation_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
לחלופין, אפשר ליצור את ה-fragment באופן פרוגרמטי, כמו שמתואר במסמכי התיעוד של Android, באמצעות FragmentActivity.getSupportFragmentManager().
שימוש בתצוגת ניווט
כחלופה ל-fragment, רכיב ממשק המשתמש להצגת מפה לניווט זמין גם בתור NavigationView.
שליחת בקשה להרשאת מיקום
בקטע הזה מוסבר איך לבקש הרשאת מיקום מדויק. פרטים נוספים זמינים במדריך בנושא הרשאות ב-Android.
מוסיפים את ההרשאה כצאצא של הרכיב
<manifest>במניפסט של Android:<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.navsdksingledestination"> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> </manifest>לבקש הרשאות בתחילת ההפעלה של האפליקציה, כדי לתת למשתמשים הזדמנות לאשר או לדחות את הרשאת המיקום. קטע הקוד הבא בודק אם המשתמש העניק הרשאת מיקום מדויק. אם לא, היא מבקשת את ההרשאה:
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); } if (!mLocationPermissionGranted) { displayMessage("Error loading Navigation SDK: " + "The user has not granted location permission."); return; }מבטלים את הקריאה החוזרת (callback) של
onRequestPermissionsResult()כדי לטפל בתוצאה של בקשת ההרשאה:@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 canceled, the result arrays are empty. if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { mLocationPermissionGranted = true; } } } }
הפעלה של Navigation SDK
הכיתה NavigationApi מספקת לוגיקת אתחול שמאשרת לאפליקציה להשתמש בניווט של Google. בקטע הזה מוסבר איך להפעיל את הניווט, וגם כמה הגדרות אחרות שאפשר להפעיל באפליקציה:
מפעילים את Navigation SDK ומבטלים את הקריאה החוזרת (callback) של
onNavigatorReady()כדי להתחיל את הניווט כשהמכשיר מוכן.אופציונלי: מגדירים את האפליקציה כך שהתראות ההדרכה והשירותים שפועלים ברקע ייסגרו כשהמשתמש יסגור את האפליקציה במכשיר. הבחירה הזו תלויה במודל העסקי שלכם. יכול להיות שתרצו להשתמש בהתנהגות ברירת המחדל של הניווט, שבה ממשיכים להופיע עדכונים לגבי המיקום והנחיות לפניות גם כשהאפליקציה נסגרת. אם אתם רוצים להפסיק את הניווט ואת עדכוני המיקום כשמשתמש הקצה סוגר את האפליקציה, אתם צריכים להשתמש בהגדרה הזו.
אופציונלי: מפעילים הגבלות על כבישים במדינות נתמכות. מגדירים את הספרה האחרונה של לוחית הרישוי. צריך לבצע את הקריאה הזו רק פעם אחת: בקשות המסלול הבאות ימשיכו להשתמש בה. הקריאה הזו פועלת רק באזורים נתמכים. רשימת המדינות שבהן יש תמיכה ב-Navigation SDK
NavigationApi.getNavigator(this, new NavigationApi.NavigatorListener() { /** * Sets up the navigation UI when the navigator is ready for use. */ @Override public void onNavigatorReady(Navigator navigator) { displayMessage("Navigator ready."); mNavigator = navigator; mNavFragment = (NavigationFragment) getSupportFragmentManager() .findFragmentById(R.id.navigation_fragment); // Optional. Disable the guidance notifications and shut down the app // and background service when the user closes the app. // mNavigator.setTaskRemovedBehavior(Navigator.TaskRemovedBehavior.QUIT_SERVICE) // Optional. Set the last digit of the car's license plate to get // route restrictions for supported countries. // mNavigator.setLicensePlateRestrictionInfo(getLastDigit(), "BZ"); // Set the camera to follow the device location with 'TILTED' driving view. mNavFragment.getCamera().followMyLocation(Camera.Perspective.TILTED); // Set the travel mode (DRIVING, WALKING, CYCLING, TWO_WHEELER, or TAXI). mRoutingOptions = new RoutingOptions(); mRoutingOptions.travelMode(RoutingOptions.TravelMode.DRIVING); // Navigate to a place, specified by Place ID. navigateToPlace(SYDNEY_OPERA_HOUSE, mRoutingOptions); } /** * Handles errors from the Navigation SDK. * @param errorCode The error code returned by the navigator. */ @Override public void onError(@NavigationApi.ErrorCode int errorCode) { switch (errorCode) { case NavigationApi.ErrorCode.NOT_AUTHORIZED: displayMessage("Error loading Navigation SDK: Your API key is " + "invalid or not authorized to use the Navigation SDK."); break; case NavigationApi.ErrorCode.TERMS_NOT_ACCEPTED: displayMessage("Error loading Navigation SDK: User did not accept " + "the Navigation Terms of Use."); break; case NavigationApi.ErrorCode.NETWORK_ERROR: displayMessage("Error loading Navigation SDK: Network error."); break; case NavigationApi.ErrorCode.LOCATION_PERMISSION_MISSING: displayMessage("Error loading Navigation SDK: Location permission " + "is missing."); break; default: displayMessage("Error loading Navigation SDK: " + errorCode); } } });
הגדרת יעד
הכיתה Navigator מאפשרת לשלוט בהגדרה, בהתחלה ובעצירה של מסלול הניווט.
משתמשים ב-Navigator שקיבלתם בקטע הקודם כדי להגדיר יעד Waypoint לנסיעה הזו. אחרי חישוב המסלול, NavigationFragment מציג קו פוליגוני שמייצג את המסלול במפה, וסמן ביעד.
```none
private void navigateToPlace(String placeId, RoutingOptions travelMode) {
Waypoint destination;
try {
destination = Waypoint.builder().setPlaceIdString(placeId).build();
} catch (Waypoint.UnsupportedPlaceIdException e) {
displayMessage("Error starting navigation: Place ID is not supported.");
return;
}
// Create a future to await the result of the asynchronous navigator task.
ListenableResultFuture<Navigator.RouteStatus> pendingRoute =
mNavigator.setDestination(destination, travelMode);
// Define the action to perform when the SDK has determined the route.
pendingRoute.setOnResultListener(
new ListenableResultFuture.OnResultListener<Navigator.RouteStatus>() {
@Override
public void onResult(Navigator.RouteStatus code) {
switch (code) {
case OK:
// Hide the toolbar to maximize the navigation UI.
if (getActionBar() != null) {
getActionBar().hide();
}
// Enable voice audio guidance (through the device speaker).
AudioGuidanceSettings audioSettings =
AudioGuidanceSettings.builder()
.setGuidanceMode(
AudioGuidanceSettings.GuidanceMode
.VOICE_ALERTS_AND_GUIDANCE)
.build();
mNavigator.setAudioGuidanceSettings(audioSettings);
// Simulate vehicle progress along the route for demo/debug builds.
if (BuildConfig.DEBUG) {
mNavigator.getSimulator().simulateLocationsAlongExistingRoute(
new SimulationOptions().speedMultiplier(5));
}
// Start turn-by-turn guidance along the current route.
mNavigator.startGuidance();
break;
// Handle error conditions returned by the navigator.
case NO_ROUTE_FOUND:
displayMessage("Error starting navigation: No route found.");
break;
case NETWORK_ERROR:
displayMessage("Error starting navigation: Network error.");
break;
case ROUTE_CANCELED:
displayMessage("Error starting navigation: Route canceled.");
break;
case ROUTING_TIMEOUT:
displayMessage("Error starting navigation: Routing timed out.");
break;
default:
displayMessage("Error starting navigation: "
+ String.valueOf(code));
}
}
});
}
```
הגדרת ההנחיות הקוליות
כדי לשנות את ההגדרות של ההנחיות הקוליות (כולל מצב ההנחיות ועוצמת הקול), מעבירים אובייקט AudioGuidanceSettings אל ה-navigator.
הניווט משתמש בהגדרות האחרונות שנשמרו, או כברירת מחדל בעוצמת קול רגילה ובהתראות קוליות עם הנחיות.
בדוגמה הבאה מוסבר איך להגדיר את הניווט כך שישתמש בעוצמת קול נמוכה, ואיך להפעיל גם התראות קוליות וגם הנחיות קוליות מפורטות:
// Configure audio guidance settings.
AudioGuidanceSettings audioSettings = AudioGuidanceSettings.builder()
.setGuidanceMode(AudioGuidanceSettings.GuidanceMode.VOICE_ALERTS_AND_GUIDANCE)
.setVolumeLevel(AudioGuidanceSettings.VolumeLevel.LOW)
.build();
mNavigator.setAudioGuidanceSettings(audioSettings);
יוצרים ומריצים את האפליקציה
- מחברים מכשיר Android למחשב. פועלים לפי ההוראות של Android Studio בנושא הפעלת אפליקציות במכשיר חומרה. לחלופין, אתם יכולים להגדיר מכשיר וירטואלי באמצעות Android Virtual Device (AVD) Manager. כשבוחרים אמולטור, חשוב לבחור קובץ אימג' שכולל את Google APIs.
- ב-Android Studio, לוחצים על האפשרות Run (הפעלה) בתפריט או על Run (הפעלה). בוחרים מכשיר לפי ההנחיות.
רמזים לשיפור חוויית המשתמש
- המשתמש צריך לאשר את התנאים וההגבלות של Google Navigation כדי שהניווט יהיה זמין. צריך לאשר את התנאים רק פעם אחת. כברירת מחדל, ה-SDK מבקש אישור בפעם הראשונה שמפעילים את הניווט. אם אתם מעדיפים, אתם יכולים להפעיל את תיבת הדו-שיח של התנאים וההגבלות של ה-Navigation בשלב מוקדם בתהליך חוויית השימוש של האפליקציה, למשל במהלך ההרשמה או ההתחברות, באמצעות
TermsAndConditionsCheckOption. - כדי לשפר משמעותית את איכות הניווט ואת הדיוק של זמן ההגעה המשוער, כדאי להשתמש במזהי מקומות כדי לאתחל נקודת דרך, במקום בקואורדינטות של קו רוחב/קו אורך.
- בדוגמה הזו, נקודת הציון של היעד נגזרת ממזהה מקום ספציפי של בית האופרה של סידני. אתם יכולים להשתמש בכלי לאיתור מזהי מקומות כדי לקבל מזהי מקומות של מיקומים ספציפיים אחרים.