路由至单个目的地

按照本指南,使用 Navigation SDK for Android 在您的应用内绘制前往单个目的地的路线。

概览

  1. 按照配置指南中的说明,将 Navigation SDK 集成到您的应用中。
  2. 向您的应用添加 NavigationFragmentNavigationView。此界面元素可向您的 activity 添加交互式地图和精细导航界面。
  3. 使用 NavigationApi 类初始化 SDK。
  4. 定义用于控制精细导航的 Navigator

  5. 构建并运行您的应用。

查看代码

添加导航 fragment

NavigationFragment 是一个界面组件,用于显示导航的视觉输出,包括互动式地图和精细导航路线。您可以在 XML 布局文件中声明 fragment,如下所示:

<?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 文档中所述。

对于使用 Fragment 支持版本的应用,Navigation SDK 通过 SupportNavigationFragment 提供兼容性。此 fragment 的行为与 NavigationFragment 相同,您可以使用 FragmentActivity.getSupportFragmentManager() 以编程方式管理它。

作为 fragment 的替代方案,界面组件还以 NavigationView 的形式提供。请注意类说明顶部的信息,尤其是有关转发生命周期方法的要求的信息。

请求位置信息权限

您的应用必须请求位置信息权限,才能确定设备的位置。

本教程提供了请求精确的位置信息权限所需的代码。如需了解详情,请参阅有关 Android 权限的指南。

  1. 在 Android 清单中,添加此权限作为 <manifest> 元素的子元素:

    <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;
                }
            }
        }
    }
    

初始化 Navigation SDK 并配置行程

NavigationApi 类提供初始化逻辑,用于授权您的应用使用 Google 导航。Navigator 类可用于控制导航历程的配置和开始/停止。

  1. 初始化 Navigation SDK,并替换 onNavigatorReady() 回调,以便在导航器准备就绪时启动导航。

  2. (可选)设置车牌的最后一位数,以在受支持的国家/地区(目前为巴西和印度尼西亚)启用道路限制。如果将此调用用于任何其他国家/地区代码,则 API 会将其忽略。此调用只需执行一次。后续路线请求将继续使用该地址。

    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);
    
                    // Set the last digit of the car's license plate to get route restrictions
                    // in supported countries. (optional)
                    // 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);
                    }
                }
            });
    
  3. 使用上面获得的 Navigator,为此行程设置目的地 Waypoint。计算路线后,NavigationFragment 会在地图上显示一条表示路线的多段线,并在目的地显示一个标记。

    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 设备连接到您的计算机。按照instructions在您的 Android 设备上启用开发者选项,并配置您的系统,使之检测该设备。您也可以使用 Android 虚拟设备 (AVD) 管理器来配置虚拟设备。选择模拟器时,请务必选择一个包含 Google API 的映像。)
  2. 在 Android Studio 中,点击 Run 菜单选项(或 Play 按钮图标)。按提示选择设备。

改善用户体验的提示

  • 用户必须接受《Google 导航服务条款》,才能使用导航功能。并且只需接受一次。默认情况下,SDK 会在首次调用导航器时提示您接受。如果您愿意,可以使用 showTermsAndConditionsDialog() 在应用用户体验流程的早期阶段(例如注册或登录期间)触发“导航服务条款”对话框。
  • 如果使用地点 ID 初始化航点,而不是纬度/经度目的地,导航质量和预计到达时间精确度会显著提高。
  • 此示例会根据(悉尼歌剧院)的特定地点 ID 派生目的地航点。您可以使用地点 ID 查找工具获取其他特定营业地点的地点 ID。或者,您可以通过向应用添加地点选择器,让用户有机会选择目的地。如需尝试使用 Navigation SDK 运行地点选择器的示例,请参阅简介中所述的演示版应用。

后续步骤

了解如何在一个行程中导航到多个目的地。如果您与 Google 的合同指定了按交易的结算方式,请设置您的可结算交易