ניווט במסלול עם יעד אחד

תוכלו להיעזר במדריך הזה כדי להציג מסלול בתוך האפליקציה באמצעות ה-Navigation SDK ל-Android. המדריך הזה מבוסס על ההנחה שכבר שילבתם את Navigation SDK באפליקציה, כפי שמתואר במאמר הגדרת הפרויקט.

סיכום

  1. מוסיפים לאפליקציה רכיב בממשק המשתמש, כמקטע ניווט או כתצוגת ניווט. הרכיב הזה בממשק המשתמש מוסיף לפעילות שלכם את המפה האינטראקטיבית ואת ממשק המשתמש לניווט המפורט.
  2. מבקשים הרשאות מיקום. האפליקציה צריכה לבקש הרשאת מיקום כדי לקבוע את מיקום המכשיר.
  3. מפעילים את ה-SDK באמצעות המחלקה NavigationApi.
  4. אפשר להגדיר יעד ולשלוט בניווט מסלול מפורט באמצעות המחלקה Navigator. התהליך הזה כולל שלושה שלבים:

    • מגדירים יעד באמצעות setDestination().
    • מתחילים בניווט באמצעות startGuidance().
    • אפשר להשתמש ב-getSimulator() כדי לדמות את התקדמות הרכב במסלול לצורך בדיקה, ניפוי באגים והדגמה של האפליקציה.
  5. יצירה והפעלה של האפליקציה.

להצגת הקוד

הוספת רכיב של ממשק משתמש לאפליקציה

בקטע הזה מתוארות שתי דרכים שבהן ניתן להוסיף את המפה האינטראקטיבית ואת ממשק המשתמש להצגת ניווט מסלול מפורט.

SupportNavigationFragment הוא הרכיב בממשק המשתמש שמציג את הפלט החזותי של הניווט, כולל מפה אינטראקטיבית ומסלול מפורט. אפשר להצהיר על המקטע בקובץ פריסת ה-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.SupportNavigationFragment"
    android:id="@+id/navigation_fragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

לחלופין, אפשר ליצור את המקטע באופן פרוגרמטי, כמו שמתואר במסמכי התיעוד של Android, באמצעות FragmentActivity.getSupportFragmentManager().

במקום מקטע, רכיב ממשק המשתמש להצגת מפה לניווט זמין גם בתור NavigationView.

שליחת בקשה להרשאת מיקום

בקטע הזה מוסבר איך לבקש הרשאת מיקום מדויק. מידע נוסף מופיע במדריך להרשאות ב-Android.

  1. מוסיפים את ההרשאה כצאצא של הרכיב <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>
    
  2. לבקש הרשאות בתחילת ההפעלה באפליקציה, כדי לתת למשתמש הזדמנות להעניק או לדחות הרשאת מיקום. הקוד הבא בודק אם המשתמש העניק הרשאת מיקום מדויקת. אם לא, היא מבקשת את ההרשאה:

    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;
    }
    
  3. כדי לטפל בתוצאה של בקשת ההרשאה, צריך לבטל את הקריאה החוזרת של 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;
                }
            }
        }
    }
    

אתחול ה-SDK לניווט

המחלקה NavigationApi מספקת לוגיקת אתחול שמאפשרת לאפליקציה להשתמש בניווט של Google. בקטע הזה נסביר איך לאתחל את כלי הניווט, ומפורטות כמה הגדרות אחרות שאפשר להפעיל באפליקציה:

  1. כדי להתחיל בניווט כשהניווט מוכן, מפעילים את ה-SDK לניווט ומבטלים את הקריאה החוזרת של onNavigatorReady().

  2. זה שינוי אופציונלי. צריך להגדיר את האפליקציה כך שהתראות ההדרכה ושירותי הרקע יושבתו כשהמשתמש סוגר את האפליקציה מהמכשיר. הבחירה הזו תלויה במודל העסקי שלכם. יכול להיות שתרצו להשתמש בהתנהגות ברירת המחדל של הניווט, אשר תמשיך להציג הנחיות פנייה ועדכוני מיקום גם לאחר סגירת האפליקציה. אם רוצים במקום זאת להשבית את הניווט ואת עדכוני המיקום כשמשתמש הקצה סגר את האפליקציה, תשתמשו בהגדרה הזו.

  3. זה שינוי אופציונלי. הפעלת הגבלות בכבישים במדינות נתמכות. הגדירו את הספרה האחרונה של לוחית הרישוי. צריך לשלוח את הקריאה הזו רק פעם אחת: בבקשות הבאות לקבלת מסלול ממשיכים להשתמש בה. השיחה הזו פועלת רק באזורים נתמכים. מדינות נתמכות ב-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) getFragmentManager()
                            .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 לתהליך הזה. אחרי חישוב המסלול, ב-SupportNavigationFragment מוצג קו פוליגוני שמייצג את המסלול במפה וסַמָּן ביעד.

    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).
                                mNavigator.setAudioGuidance(
                                        Navigator.AudioGuidance.VOICE_ALERTS_AND_GUIDANCE);

                                // 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;
                            default:
                                displayMessage("Error starting navigation: "
                                        + String.valueOf(code));
                        }
                    }
                });
    }

יצירה והפעלה של אפליקציה

  1. מחברים מכשיר Android למחשב. פועלים לפי ההוראות להפעלת אפליקציות במכשיר חומרה לפי ההוראות ל-Android Studio. לחלופין, אפשר להגדיר מכשיר וירטואלי באמצעות מנהל המכשיר הווירטואלי (AVD) של Android. כשבוחרים אמולטור, חשוב לבחור תמונה שכוללת את Google APIs.
  2. ב-Android Studio, לוחצים על אפשרות התפריט הפעלה או על סמל לחצן ההפעלה. בוחרים מכשיר בהתאם להנחיה.

טיפים לשיפור חוויית המשתמש

  • המשתמש חייב לאשר את התנאים וההגבלות של ניווט Google כדי שהניווט יהיה זמין. האישור הזה נדרש רק פעם אחת. כברירת מחדל, ה-SDK מבקש לאשר בפעם הראשונה שניווט מופעל. אם אתם מעדיפים, תוכלו להפעיל את תיבת הדו-שיח של התנאים וההגבלות של הניווט בשלב מוקדם בתהליך חוויית המשתמש של האפליקציה, למשל במהלך ההרשמה או ההתחברות, באמצעות TermsAndConditionsCheckOption.
  • כדי לשפר משמעותית את איכות הניווט ואת הדיוק של זמן ההגעה המשוער, כדאי להשתמש במזהי מקומות כדי לאתחל ציון דרך במקום קואורדינטות של קווי אורך ורוחב.
  • הדוגמה הזו נגזרת מציון הדרך ליעד מתוך מזהה מקום ספציפי של בית האופרה של סידני. אפשר להשתמש בכלי לאיתור מזהי מקומות כדי לקבל מזהים של מיקומים ספציפיים אחרים.