یک مسیر چند مقصدی را پیمایش کنید

برای ترسیم مسیری در برنامه خود به چندین مقصد، که به آن نقاط مسیر نیز گفته می‌شود، با استفاده از Navigation SDK برای اندروید، این راهنما را دنبال کنید.

نمای کلی

  1. همانطور که در بخش «راه‌اندازی پروژه» توضیح داده شده است، کیت توسعه نرم‌افزار ناوبری (Navigation SDK) را در برنامه خود ادغام کنید.
  2. یک SupportNavigationFragment یا NavigationView به برنامه خود اضافه کنید. این عنصر رابط کاربری، نقشه تعاملی و رابط کاربری ناوبری گام به گام را به فعالیت شما اضافه می‌کند.
  3. از کلاس NavigationApi برای مقداردهی اولیه SDK استفاده کنید.
  4. یک Navigator برای کنترل ناوبری گام به گام تعریف کنید:

    • با استفاده از setDestinations() ‎ مقصدها را اضافه کنید.
    • ناوبری را با 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"/>

به عنوان یک روش جایگزین، می‌توانید قطعه کد را به صورت برنامه‌نویسی شده، همانطور که در مستندات اندروید توضیح داده شده است، با استفاده از FragmentActivity.getSupportFragmentManager() بسازید.

به عنوان جایگزینی برای یک فرگمنت، کامپوننت رابط کاربری به عنوان یک NavigationView نیز موجود است. در بیشتر موارد، توصیه می‌کنیم به جای تعامل مستقیم با NavigationView ، از SupportNavigationFragment که یک پوشش برای NavigationView است استفاده کنید. برای اطلاعات بیشتر، به بهترین شیوه‌های تعامل با نقشه ناوبری مراجعه کنید.

درخواست مجوز مکان

برنامه شما برای تعیین موقعیت مکانی دستگاه باید درخواست مجوز موقعیت مکانی کند.

این آموزش کدی را که برای درخواست مجوز موقعیت مکانی دقیق نیاز دارید، ارائه می‌دهد. برای جزئیات بیشتر، به راهنمای مجوزهای اندروید مراجعه کنید.

  1. این مجوز را به عنوان فرزند عنصر <manifest> در فایل مانیفست اندروید خود اضافه کنید:

        <manifest xmlns:android="http://schemas.android.com/apk/res/android"
            package="com.example.navsdkmultidestination">
            <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.", DISPLAY_BOTH);
            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 منطق مقداردهی اولیه‌ای را ارائه می‌دهد که به برنامه شما اجازه می‌دهد از ناوبری گوگل استفاده کند. کلاس Navigator کنترل پیکربندی، شروع و توقف یک سفر ناوبری را فراهم می‌کند.

  1. یک متد کمکی برای نمایش پیام روی صفحه و در لاگ ایجاد کنید.

        private void displayMessage(String errorMessage, String displayMedium) {
            if (displayMedium.equals(DISPLAY_BOTH) || displayMedium.equals(DISPLAY_TOAST)) {
                Toast.makeText(this, errorMessage, Toast.LENGTH_LONG).show();
            }
    
            if (displayMedium.equals(DISPLAY_BOTH) || displayMedium.equals(DISPLAY_LOG)) {
                Log.d(TAG, errorMessage);
            }
        }
    
  2. کیت توسعه نرم‌افزار ناوبری (Navigator SDK) را مقداردهی اولیه کنید و تابع فراخوانی onNavigatorReady() را برای شروع ناوبری پس از آماده شدن ناوبری، لغو کنید:

        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.", DISPLAY_BOTH);
                        mNavigator = navigator;
                        mNavFragment = (SupportNavigationFragment) getFragmentManager()
                                .findFragmentById(R.id.navigation_fragment);
    
                        // Set the camera to follow the device location with 'TILTED' driving view.
                        mNavFragment.getCamera().followMyLocation(Camera.Perspective.TILTED);
    
                        // Navigate to the specified places.
                        navigateToPlaces();
                    }
    
                    /**
                     * 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.",
                                        DISPLAY_BOTH);
                                break;
                            case NavigationApi.ErrorCode.TERMS_NOT_ACCEPTED:
                                displayMessage("Error loading Navigation SDK: User did not accept "
                                        + "the Navigation Terms of Use.", DISPLAY_BOTH);
                                break;
                            case NavigationApi.ErrorCode.NETWORK_ERROR:
                                displayMessage("Error loading Navigation SDK: Network error.",
                                        DISPLAY_BOTH);
                                break;
                            case NavigationApi.ErrorCode.LOCATION_PERMISSION_MISSING:
                                displayMessage("Error loading Navigation SDK: Location permission "
                                        + "is missing.", DISPLAY_BOTH);
                                break;
                            default:
                                displayMessage("Error loading Navigation SDK: " + errorCode,
                                        DISPLAY_BOTH);
                        }
                    }
                });
    
  3. روشی برای ایجاد یک شیء Waypoint از یک شناسه و عنوان مکان مشخص اضافه کنید.

        private void createWaypoint(String placeId, String title) {
            try {
                mWaypoints.add(
                  Waypoint.builder()
                         .setPlaceIdString(placeId)
                         .setTitle(title)
                         .build()
                );
            } catch (Waypoint.UnsupportedPlaceIdException e) {
                displayMessage("Error starting navigation: Place ID is not supported: " + placeId,
                        DISPLAY_BOTH);
            }
        }
    
  4. روشی برای نمایش زمان سفر و مسافت محاسبه شده تا هر نقطه مسیر اضافه کنید.

        private void displayTimesAndDistances() {
            List<TimeAndDistance> timesAndDistances = mNavigator.getTimeAndDistanceList();
            int leg = 1;
            String message = "You're on your way!";
            for (TimeAndDistance timeAndDistance : timesAndDistances) {
                message = message + "\nRoute leg: " + leg++
                        + ": Travel time (seconds): " + timeAndDistance.getSeconds()
                        + ". Distance (meters): " + timeAndDistance.getMeters();
            }
            displayMessage(message, DISPLAY_BOTH);
        }
    
  5. تمام نقاط مسیر را برای این سفر تنظیم کنید. (توجه داشته باشید که اگر از شناسه‌های مکانی استفاده کنید که ناوبر نتواند مسیری را برای آنها ترسیم کند، ممکن است با خطا مواجه شوید. برنامه نمونه در این آموزش از شناسه‌های مکانی برای نقاط مسیر در استرالیا استفاده می‌کند. به نکات زیر در مورد دریافت شناسه‌های مکانی مختلف مراجعه کنید.) پس از محاسبه مسیرها، SupportNavigationFragment یک چندخطی را نشان می‌دهد که مسیر را روی نقشه نشان می‌دهد، با یک نشانگر در هر نقطه مسیر.

        private void navigateToPlaces() {
    
            // Set up a waypoint for each place that we want to go to.
            createWaypoint("ChIJq6qq6jauEmsRJAf7FjrKnXI", "Sydney Star");
            createWaypoint("ChIJ3S-JXmauEmsRUcIaWtf4MzE", "Sydney Opera House");
            createWaypoint("ChIJLwgLFGmuEmsRzpDhHQuyyoU", "Sydney Conservatorium of Music");
    
            // If this journey is already in progress, no need to restart navigation.
            // This can happen when the user rotates the device, or sends the app to the background.
            if (mSavedInstanceState != null
                    && mSavedInstanceState.containsKey(KEY_JOURNEY_IN_PROGRESS)
                    && mSavedInstanceState.getInt(KEY_JOURNEY_IN_PROGRESS) == 1) {
                return;
            }
    
            // Create a future to await the result of the asynchronous navigator task.
            ListenableResultFuture<Navigator.RouteStatus> pendingRoute =
                    mNavigator.setDestinations(mWaypoints);
    
            // 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:
                                    mJourneyInProgress = true;
                                    // Hide the toolbar to maximize the navigation UI.
                                    if (getActionBar() != null) {
                                        getActionBar().hide();
                                    }
    
                                    // Register some listeners for navigation events.
                                    registerNavigationListeners();
    
                                    // Display the time and distance to each waypoint.
                                    displayTimesAndDistances();
    
                                    // 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.",
                                            DISPLAY_BOTH);
                                    break;
                                case NETWORK_ERROR:
                                    displayMessage("Error starting navigation: Network error.",
                                            DISPLAY_BOTH);
                                    break;
                                case ROUTE_CANCELED:
                                    displayMessage("Error starting navigation: Route canceled.",
                                            DISPLAY_BOTH);
                                    break;
                                default:
                                    displayMessage("Error starting navigation: "
                                            + String.valueOf(code), DISPLAY_BOTH);
                            }
                        }
                    });
        }
    

برنامه خود را بسازید و اجرا کنید

  1. یک دستگاه اندروید را به رایانه خود متصل کنید. دستورالعمل‌ها را دنبال کنید تا گزینه‌های توسعه‌دهنده را در دستگاه اندروید خود فعال کنید و سیستم خود را برای شناسایی دستگاه پیکربندی کنید. (همچنین می‌توانید از Android Virtual Device Manager (AVD) Manager برای پیکربندی یک دستگاه مجازی استفاده کنید. هنگام انتخاب یک شبیه‌ساز، مطمئن شوید که تصویری را انتخاب می‌کنید که شامل APIهای گوگل باشد.)
  2. در اندروید استودیو، روی گزینه‌ی منوی Run (یا آیکون دکمه‌ی پخش) کلیک کنید. دستگاهی را که از شما خواسته می‌شود انتخاب کنید.

نکاتی برای بهبود تجربه کاربری

  • کاربر باید قبل از اینکه ناوبری در دسترس قرار گیرد، شرایط خدمات ناوبری گوگل را بپذیرد. این پذیرش فقط یک بار لازم است. به طور پیش‌فرض، SDK در اولین باری که ناوبری فراخوانی می‌شود، درخواست پذیرش می‌کند. در صورت تمایل، می‌توانید کادر محاوره‌ای شرایط خدمات ناوبری را در نقطه‌ای اولیه از جریان UX برنامه خود، مانند هنگام ثبت نام یا ورود، با استفاده از showTermsAndConditionsDialog() فعال کنید.
  • اگر از شناسه‌های مکان برای مقداردهی اولیه یک نقطه مسیر، به جای طول/عرض جغرافیایی مقصد، استفاده کنید، کیفیت ناوبری و دقت ETA به طور قابل توجهی بهبود می‌یابد.
  • این نمونه، نقاط مسیر را از شناسه‌های مکان خاص استخراج می‌کند. روش‌های دیگر برای دریافت شناسه مکان شامل موارد زیر است:

  • برای دریافت شناسه مکان برای مکان‌های خاص، از یابنده شناسه مکان استفاده کنید.

  • از API مربوط به Geocoding برای یافتن شناسه مکان برای یک آدرس مشخص استفاده کنید. اگر آدرس‌های کامل و بدون ابهام برای نقاط مسیر داشته باشید، API مربوط به Geocoding به خوبی کار می‌کند. به راهنمای بهترین شیوه‌های Geocoding مراجعه کنید.

  • از جستجوی متنی Places API برای یافتن شناسه مکان برای یک آدرس مشخص استفاده کنید. Places API در صورتی که آدرس‌های ناقص یا مبهمی برای نقاط مسیر دارید، به خوبی کار می‌کند. به راهنمای بهترین شیوه‌های کدگذاری جغرافیایی مراجعه کنید.