概述
行程前-相关服务
  • 地图展示
    • 概述
    • 地图组件-Android
    • 地图组件-iOS
  • 展示附近车辆
    • 概述
    • 展示附近车辆-Android
    • 展示附近车辆-iOS
  • 选择上车地点
    • 概述
    • 推荐上车点-Android
    • 推荐上车点-iOS
  • 选择目的地
    • 概述
    • 搜索POI-Android
    • 搜索POI-iOS
    • 拖拽选择目的地-Android
    • 拖拽选择目的地-iOS
  • 圈车服务
    • 批量接驾计算
    • 车辆规避限行
  • 一口价
    • 网约车路径规划-订单估价
    • 行驶路线绑定
行程中-相关服务
  • 网约车路线规划
    • 接驾路径规划
    • 送驾路径规划
  • 司乘同显- iOS
    • 概述
    • 快速接入
    • 基础功能
    • 高级功能
    • 使用工具
    • 开发注意事项
  • 司乘同显 - Andorid
    • 概述
    • 快速接入
    • 基础功能
    • 高级功能
    • 使用工具
    • 开发注意事项
  • 司乘同显- HarmonyOS NEXT
    • 概述
    • 快速接入
    • 基础功能
    • 高级功能
    • 使用工具
    • 开发注意事项
行程后-相关服务
  • 客诉判责
    • 订单绕路判断服务
  • 轨迹服务
    • 订单轨迹查询
    • 行驶轨迹计算
其他服务
  • 信息同步
    • 订单信息同步
    • 车辆信息同步
您现在的位置:出行解决方案开发指南行程中-相关服务司乘同显 - Andorid快速接入

快速接入 最后更新时间: 2022年01月19日

获取key

在初始化前,请确保您已开通高德开发者账号,并且您已为您的 App Key 开通司乘同显服务,App Key的申请及获取请参考:https://lbs.amap.com/api/android-sdk/guide/create-project/get-key

开通权限

您在高德开放平台创建的应用默认不会启用司乘同显服务。在使用高德提供的司乘同显服务前,需要联系与您对接的商务进行开通。

4、配置key

在AndroidManifest.xml 的 application 标签下加入如下内容: 

<meta-data android:name="com.amap.api.v2.apikey" android:value="key">
//开发者申请的key  
</meta-data>

集成SDK

1、添加库文件

拷贝jar+so到工程libs文件夹下:


2、gradle配置

配置so路径,打开build.gradle,找到 sourceSets 标签,在里面添加如下配置:

main {
    jniLibs.srcDirs = ['libs']
}

接入示例

司机端

1、创建DriverRouteManager

1) 初始化资源,更多设置可以参考RouteOverlayOptions的接口说明:

// 实例司乘同显 参数类
RouteOverlayOptions options = new RouteOverlayOptions();
// 设置 小车图标
options.carIcon(BitmapDescriptorFactory.fromResource(R.drawable.icon_car));
// 设置 起点图标
options.startPointIcon(BitmapDescriptorFactory.fromResource(R.drawable.amap_start));
// 设置终点图标
options.endPointIcon(BitmapDescriptorFactory.fromResource(R.drawable.amap_end));

2)创建DriverRouteManager

DriverRouteManager driverRouteManager = new DriverRouteManager(context, aMap, options);

2、设置订单信息

1)创建OrderProperty

//设置订单类型(普通、拼车)及订单ID 
OrderProperty orderProperty = new OrderProperty(SCTXConfig.SCTX_ORDER_TYPE_NORMAL, OrderId);
//设置车辆信息,场景:司机位置VDC同步(可选)
CarInfo carInfo = new CarInfo();
carInfo.setVehicleID("Test100");
carInfo.setCity("010");
carInfo.setVehicleType(CarInfo.VEHICHLE_TYPE_ELECTRIC);
orderProperty.setCarInfo(carInfo);
//设置轨迹服务sid,场景:显示历史轨迹(可选)
orderProperty.setServiceId("1786");

2)设置OrderProperty

//设置orderProperty、上车点坐标、目的地坐标
driverRouteManager.setOrderProperty(orderProperty, new LatLng(39.992932, 116.479262), new LatLng(39.993343, 116.474574));

3、切换订单状态

1)订单状态类型,参考(com.amap.sctx.SCTXConfig)

SCTX_ORDER_STATUS_UNSPECIFIED = 0;//未知状态
SCTX_ORDER_STATUS_PICKUPPASSENGER = 1;//去接乘客
SCTX_ORDER_STATUS_WAITPASSENGER = 2;//等待乘客上车
SCTX_ORDER_STATUS_PASSENGERONBOARD = 3;//乘客以上车
SCTX_ORDER_STATUS_ORDERCOMPLETE = 4;//订单结束
SCTX_ORDER_STATUS_OFFLINE = 5;//离线状态,只走降级策略获取司机位置,内部不做其他请求

2)订单状态切换

driverRouteManager.setOrderState(SCTXConfig.SCTX_ORDER_STATUS_PICKUPPASSENGER);

运行效果:

4、调起导航组件

在接乘客和送乘客阶段可以调起高德导航组件进行导航:

1)需要在AndroidManifest.xml里注册AmapRouteActivity

<activity
   android:theme="@android:style/Theme.NoTitleBar"
   android:name="com.amap.api.navi.AmapRouteActivity">
</activity>

2)调用DriverRouteOverlay的startNavi方法开启导航:

DriverRouteManager.NaviParams naviParams = new DriverRouteManager.NaviParams();
naviParams.setNeedCalculateRoute(false);//界面启动是否需要重新算路
naviParams.setTrafficEnable(true);//导航界面是否开启路况
driverRouteManager.startNavi(this, new INaviInfoCallback() {
                @Override
                public void onInitNaviFailure() {
                }
                @Override
                public void onGetNavigationText(String s) {
                }
                @Override
                public void onLocationChange(AMapNaviLocation aMapNaviLocation) {
                }
                @Override
                public void onArriveDestination(boolean b) {
                }
                @Override
                public void onStartNavi(int i) {
                }
                @Override
                public void onCalculateRouteSuccess(int[] ints) {
                }
                @Override
                public void onCalculateRouteFailure(int i) {
                }
                @Override
                public void onStopSpeaking() {
                }
                @Override
                public void onReCalculateRoute(int i) {
                }
                @Override
                public void onExitPage(int i) {
                }
                @Override
                public void onStrategyChanged(int i) {
                }
                @Override
                public View getCustomNaviBottomView() {
                    return null;
                }
                @Override
                public View getCustomNaviView() {
                    return null;
                }
                @Override
                public void onArrivedWayPoint(int i) {
                }
}, naviParams);

5、销毁

driverRouteManager.destroy();//释放资源

乘客端

流程与司机端一一对应:

1、创建PassengerRouteManager

1) 初始化资源,更多设置可以参考RouteOverlayOptions的接口说明:

// 实例司乘同显 参数类
RouteOverlayOptions options = new RouteOverlayOptions();
// 设置 小车图标
options.carIcon(BitmapDescriptorFactory.fromResource(R.drawable.icon_car));
// 设置 起点图标
options.startPointIcon(BitmapDescriptorFactory.fromResource(R.drawable.amap_start));
// 设置终点图标
options.endPointIcon(BitmapDescriptorFactory.fromResource(R.drawable.amap_end));

2)创建PassengerRouteManager

PassengerRouteManager passengerRouteManager = new PassengerRouteManager(this, aMap, options);

2、设置订单信息

1)创建OrderProperty

//设置订单类型(普通、拼车)及订单ID 

OrderProperty orderProperty = new OrderProperty(SCTXConfig.SCTX_ORDER_TYPE_NORMAL, OrderId);
//设置轨迹服务sid,场景:显示历史轨迹(可选)
orderProperty.setServiceId("1786");

2)设置OrderProperty

//设置orderProperty、上车点坐标、目的地坐标
passengerRouteManager.setOrderProperty(orderProperty, new LatLng(39.992932, 116.479262), new LatLng(39.993343, 116.474574));

3、切换订单状态

passengerRouteManager.setOrderState(SCTXConfig.SCTX_ORDER_STATUS_PICKUPPASSENGER);

 4、销毁

passengerRouteManager.destroy();//释放资源

运行效果:

 

覆盖物样式自定义

司乘同显覆盖物(车、路线、起终点)样式均通过RouteOverlayOptions来控制,具体参数介绍:

/**
 * 设置起点图标
 * @param bitmapDescriptor
 * @return
 * @since 1.0.0
 */
public RouteOverlayOptions startPointIcon(BitmapDescriptor bitmapDescriptor)
/**
 * 设置终点图标
 * @param bitmapDescriptor
 * @return
 * @since 1.0.0
 */
public RouteOverlayOptions endPointIcon(BitmapDescriptor bitmapDescriptor)
/**
 * 设置小车图标
 * @param bitmapDescriptor
 * @return
 * @since 1.0.0
 */
public RouteOverlayOptions carIcon(BitmapDescriptor bitmapDescriptor)
/**
 * 设置默认轨迹线填充纹理
 * @param bitmapDescriptor
 * @return
 * @since 1.0.0
 */
public RouteOverlayOptions defaultRouteRes(BitmapDescriptor bitmapDescriptor)
/**
 * 设置步行轨迹线填充纹理
 * @param bitmapDescriptor
 * @return
 * @since 1.0.0
 */
public RouteOverlayOptions walkRouteRes(BitmapDescriptor bitmapDescriptor)
/**
 * 设置路况轨迹线填充纹理--畅通
 * @param bitmapDescriptor
 * @return
 * @since 1.0.0
 */
public RouteOverlayOptions smoothTrafficRes(BitmapDescriptor bitmapDescriptor)
/**
 * 设置路况轨迹线填充纹理--缓慢
 * @param bitmapDescriptor
 * @return
 * @since 1.0.0
 */
public RouteOverlayOptions slowTrafficRes(BitmapDescriptor bitmapDescriptor)
/**
 * 设置路况轨迹线填充纹理--拥堵
 * @param bitmapDescriptor
 * @return
 * @since 1.0.0
 */
public RouteOverlayOptions jamTrafficRes(BitmapDescriptor bitmapDescriptor)
/**
 * 设置路况轨迹线填充纹理--严重拥堵
 * @param bitmapDescriptor
 * @return
 * @since 1.0.0
 */
public RouteOverlayOptions veryJamTrafficRes(BitmapDescriptor bitmapDescriptor)
/**
 * 设置路况轨迹线填充纹理--未知路况
 * @param bitmapDescriptor
 * @return
 * @since 1.0.0
 */
public RouteOverlayOptions unknownTrafficRes(BitmapDescriptor bitmapDescriptor)
/**
 * 设置路况轨迹线填充纹理--畅通,未选中状态
 *
 * @param bitmapDescriptor
 * @return
 * @since 2.4.0
 */
public RouteOverlayOptions smoothTrafficUnSelectRes(BitmapDescriptor bitmapDescriptor)
/**
 * 设置路况轨迹线填充纹理--缓慢,未选中状态
 *
 * @param bitmapDescriptor
 * @return
 * @since 2.4.0
 */
public RouteOverlayOptions slowTrafficUnSelectRes(BitmapDescriptor bitmapDescriptor)
/**
 * 设置路况轨迹线填充纹理--拥堵,未选中状态
 *
 * @param bitmapDescriptor
 * @return
 * @since 2.4.0
 */
public RouteOverlayOptions jamTrafficUnSelectRes(BitmapDescriptor bitmapDescriptor)
/**
 * 设置路况轨迹线填充纹理--严重拥堵,未选中状态
 *
 * @param bitmapDescriptor
 * @return
 * @since 2.4.0
 */
public RouteOverlayOptions veryJamTrafficUnSelectRes(BitmapDescriptor bitmapDescriptor)
/**
 * 设置路况轨迹线填充纹理--未知路况,未选中状态
 *
 * @param bitmapDescriptor
 * @return
 * @since 2.4.0
 */
public RouteOverlayOptions unknownTrafficUnSelectRes(BitmapDescriptor bitmapDescriptor)
/**
 * 设置走过的路填充纹理
 *
 * @param bitmapDescriptor
 * @return
 * @since 2.0.0
 */
public RouteOverlayOptions passedTraceRes(BitmapDescriptor bitmapDescriptor)
/**
 * 设置普通途经点图片资源
 * @param normalWayPointDescriptor
 * @return
 * @since 2.3.0
 */
public RouteOverlayOptions setNormalWayPointDescriptor(BitmapDescriptor normalWayPointDescriptor)
/**
 * 设置上车途经点图片资源(拼车)
 *
 * @param startWayPointDescriptor
 * @since 2.0.0
 */
public RouteOverlayOptions setStartWayPointDescriptor(BitmapDescriptor startWayPointDescriptor)
/**
 * 设置下车途经点图片资源(拼车)
 *
 * @param endWayPointDescriptor
 * @since 2.0.0
 */
public RouteOverlayOptions setEndWayPointDescriptor(BitmapDescriptor endWayPointDescriptor)

注意:如果有司乘同显地图界面退出重新进入的场景,建议在调用 DriverRouteManager.setMap前重新初始化一下RouteOverlayOptions里的图片资源,因为地图在退出销毁时同时会销毁这些图片;

使用注意事项

用司机端SDK时,避免外部同时使用导航SDK或者导航组件

导航SDK是单例的,司乘同显SDK内部功能也依赖于导航功能,当使用司乘同显SDK时,如果外部再调用导航组件或者导航路径规划功能会影响司机端的功能运行。如果在初始化司乘同显SDK之前已经有使用导航SDK的功能建议在初始化司乘同显SDK之前,先销毁导航SDK,再初始化司乘同显SDK。

避免重复设置订单信息

当订单信息没有变化时,只需要设置一次就可以了,重复设置会造成司乘同显内部信息重复上传、初始化,造成流量浪费和一些意外情况出现。

代码示例:

private boolean hasInitOrderInfo = false;
private OrderProperty orderProperty = null;
private void initOrderInfo() {
    if(!hasInitOrderInfo || null == orderProperty) {
        orderProperty = new OrderProperty(SCTXConfig.SCTX_ORDER_TYPE_NORMAL, 
                                          mOrderId);
        if(null != mDriverRouteManager) {
            try {
                mDriverRouteManager.setOrderProperty(orderProperty,
                                                     new LatLng(39.985507, 116.400596),
                                                     new LatLng(39.971864, 116.318945));
                hasInitOrderInfo = true;
            } catch (AMapException e) {
                e.printStackTrace();
            }
        }
    }
}

修改订单起终点

司乘同显司机端和乘客端SDK均允许修改订单起终点,当通过乘客端SDK修改起终点时需要保证司机端在线,有一定的条件要求,所以建议通过司机端接口修改起终点(可以乘客端发起之后通知服务端然后服务端再通知司机端SDK进行修改),注意:修改订单起点只能在接驾阶段设置。

司机端修改代码示例如下:

//修改订单终点
private void changeOrderPosition() {
    if(null != mDriverRouteManager) {
        try {
            //司机端修改起终点的接口和设置订单信息的接口是一个,如果需要修改起终点,修改一下这个接口的起终点参数就可以了
            mDriverRouteManager.setOrderProperty(orderProperty, new LatLng(39.985507, 116.400596),
                                                 new LatLng(39.971864, 116.318945));
            //注意:修改完起终点之后,如果是在接驾或者送驾状态一定要调用一下重新算路接口
            //这里以修改订单终点为例,如果当前处于送驾状态,需要调用一次重新算路接口,否则不需要重新算路
            if (mOrderState == SCTXConfig.SCTX_ORDER_STATUS_PASSENGERONBOARD) {
                mDriverRouteManager.reCalculateRoute();
            }
        } catch (AMapException e) {
            e.printStackTrace();
        }
    }

乘客端提供了两个接口,分别用于修改订单起点和终点。注意:修改起点之后在送驾阶段设置,当通过乘客端修改起终点的时候有可能会失败(如果是通过乘客端修改起终点,注意根据乘客端SDK的onError错误码判断是否要重复设置,修改成功之后2分钟内不再允许修改,会一直返回失败)。

乘客端SDK修改起终点代码示例:

//乘客端回调
private void initPassengerCallback() {
    mPassengerRouteManager.setPassengerOverlayRouteCallback(new PassengerRouteManager.PassengerRouteCallback() {
        @Override
        public void onRouteStatusChange(int status, float distance, long time, float remainingDistance,
                                        long estimatedTime) {
        }
        @Override
        public void onDriverPositionChange(LatLng position) {
        }
        @Override
        public void onError(int errorCode, String message) {
            if (errorCode == SCTXConfig.SCTX_ERROR_STARTPOSITION_UPDATE_SUCCESS) {
                //代表修改上车点成功
            }
            if (errorCode == SCTXConfig.SCTX_ERROR_STARTPOSITION_UPDATE_FAILED) {
                //代表修改上车点失败,需要根据当时的订单状态和上一次修改成功的时间间隔判断是否需要重新设置
            }
            if (errorCode == SCTXConfig.SCTX_ERROR_ENDPOSITION_UPDATE_SUCCESS) {
                //代表修改下车点成功
            }
            if (errorCode == SCTXConfig.SCTX_ERROR_ENDPOSITION_UPDATE_FAILED) {
                //代表修改下车点失败,需要根据当时的订单状态和上一次修改成功的时间间隔判断是否需要重新设置
            }
        }
    });
}
//乘客端SDK修改上车点
private void changeStartPoint() {
    if(null != mPassengerRouteManager) {
        //修改起终点
        mPassengerRouteManager.setStartPosition(new LatLng(23.118226,113.300605));
    }
}
//乘客端修改下车点
private void changeEndPoint() {
    if(null != mPassengerRouteManager) {
        //修改起终点
        mPassengerRouteManager.setEndPosition(new LatLng(23.118226,113.300605));
    }
}

正确设置订单状态

   1.避免重复设置订单状态

司乘同显SDK对外提供接口改变当前的订单状态,可以和业务更好的融合,在设置为接驾和送驾状态的时候,司乘同显SDK内部分别会以司机当前位置和订单起点、终点进行算路、导航,并且会上传订单信息、状态和导航路线信息,当重复订单状态时会造成重复的上传订单信息和路线信息,会造成乘客端路线显示不正常或者消失(在最新版本司乘同显SDK内部已经做了重复设置的规避,但是为了业务逻辑更加合理,建议业务层也做一下重复设置的保护)

  1. 在设置订单状态只有如果收到算路失败的回调,需要调用一次重新算路
  2. 重新算路的时候增加时间判断,避免短时间内大量重复算路

代码实现示例:

//当前订单状态
private int currentOrderState = SCTXConfig.SCTX_ORDER_STATUS_UNSPECIFIED;
//是否算成功过
private boolean hasCalcRouteSuccess = false;
//上次重新算路的时间戳
private volatile  long mLastRecalcRoute = 0;
//设置订单状态
private void setOderState(int orderState) {
    //当订单状态不一致时再重新设置订单状态
    if (currentOrderState != orderState) {
        currentOrderState = orderState;
        //订单状态改变时对应的标识变量重置
        hasCalceRouteSuccess = false;
        mLastRecalcRoute = 0;
        mDriverRouteManager.setOrderState(currentOrderState);
    }
}
private Handler myHandelr = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case 0:
                //执行重新算路
                if(null != mDriverRouteManager) {
                    mLastRecalcRoute = System.currentTimeMillis();
                    mDriverRouteManager.reCalculateRoute();
                }
                break;
            default:
                break;
        }
    }
};
//司机端回调信息这里仅为示例代码,演示配合司机端SDK回调信息调起导航组件,实际使用过程中根据业务情况进行处理
private void demoDriverCallback() {
    mDriverRouteManager.setDriverRouteCallback(new DriverRouteManager.DriverRouteCallback() {
        @Override
        public void onRouteStatusChange(float distance, long time, float remainingDistance, long estimatedTime) {
        }
        @Override
        public void onArriveWayPoint(WayPointInfo wayPointInfo) {
        }
        @Override
        public void onArrivePickUpPosition() {
        }
        @Override
        public void onArriveDestination() {
        }
        @Override
        public void onCalculateRouteFailure() {
        }
        @Override
        public void onError(int errorCode, String message) {
            //如果在切换订单状态之后,并且没有收到算路成功回调,则需要调用重现算路接口
            if (errorCode == SCTXConfig.SCTX_ERROR_DRIVER_CACULATE_ROUTE_FAILED
                && !hasCalcRouteSuccess) {
                if(null != mDriverRouteManager) {
                    Message msg = Message.obtain();
                    msg.what = 0;
                    //如果和上次重新算路的间隔小于30秒,增加延时
                    if(System.currentTimeMillis() - mLastRecalcRoute > 30 * 1000) {
                        myHandelr.sendMessageDelayed(msg,
                                                     30 * 1000 - (System.currentTimeMillis() - mLastRecalcRoute));
                    } else {
                        myHandelr.sendMessage(msg);
                    }
                }
            }
        }
        @Override
        public void onCalculateRouteSuccess(int[] ints) {
            hasCalcRouteSuccess = true;
        }
        @Override
        public boolean onSelectRoute(List<NaviPathInfo> naviPathInfos) {
            return false;
        }
    });
}

正确使用导航组件

司乘同显司机端SDK为开发者提供了导航组件,使用导航组件可以让用户的导航体验比较好(接近于使用高德地图导航),建议开发者直接使用司乘同显SDK提供的接口调起导航组件,不要直接使用导航SDK的接口调起导航组件

调起导航组件时注意一下几点:

  1. 在等驾状态时不需要调起导航组件,司机端SDK在等驾状态不会开启导航,调起导航组件之后有可能不显示路线或者报错,给用户使用带来不好的体验
  2. 为了避免调起导航组件时重新算路,建议在收到司乘同显SDK算路成功的回调之后再调起导航组件

调起导航组件代码示例:

 private boolean hasCalcRouteSuccess = false;
    //司机端回调信息这里仅为示例代码,演示配合司机端SDK回调信息调起导航组件,实际使用过程中根据业务情况进行处理
    private void demoDriverCallback() {
        mDriverRouteManager.setDriverRouteCallback(new DriverRouteManager.DriverRouteCallback() {
            @Override
            public void onRouteStatusChange(float distance, long time, float remainingDistance, long estimatedTime) {
            }
            @Override
            public void onArriveWayPoint(WayPointInfo wayPointInfo) {
            }
            @Override
            public void onArrivePickUpPosition() {
            }
            @Override
            public void onArriveDestination() {
            }
            @Override
            public void onCalculateRouteFailure() {
            }
            @Override
            public void onError(int errorCode, String message) {
            }
            @Override
            public void onCalculateRouteSuccess(int[] ints) {
                hasCalcRouteSuccess = true;
            }
            @Override
            public boolean onSelectRoute(List<NaviPathInfo> naviPathInfos) {
                return false;
            }
        });
    }
    /**
     * 起导航组件
     */
    public void startNavi(View view) {
        if (mDriverRouteManager != null && hasCalcRouteSuccess) {
            //创建导航组件参数类
            DriverRouteManager.NaviParams naviParams = new DriverRouteManager.NaviParams();
            //调起导航是否重新算路,建议设置为不需要重新算路, 重新算路有可能造成和第一次显示的路线不一致
            naviParams.setNeedCalculateRoute(false);
            //是否开启路况
            naviParams.setTrafficEnable(true);
            //是否使用内置语音
            naviParams.setUseInnerVoice(true);
            //是否绘制备选路线
            naviParams.setDrawBackUpOverlay(true);
            //调起导航组件,开启导航,  context - 上下文  callback - 信息回调  params - 导航组件初始化参数
            mDriverRouteManager.startNavi(this, new DemoNaviInfoCallback(), naviParams);
        }
    }