开发 出行解决方案参考手册 客户端相关服务 行程中 司乘同显-iOS

司乘同显-iOS 最后更新时间: 2020年12月15日

快速接入

1.获取Key

1.创建新应用

进入控制台,创建一个新应用。如果您之前已经创建过应用,可直接跳过这个步骤。

 

2.添加新key

在创建的应用上点击"添加新Key"按钮,在弹出的对话框中,依次输入应用名名称,选择绑定的服务为“iOS平台SDK”,输入您的key名称Bundle ID,如下图所示:

需要注意的是: 1个KEY只能用于一个应用,1个Key在多个应用上使用会出现服务调用失败。

 在阅读完高德地图API服务条款后,勾选此选项,点击“提交”,完成 Key 的申请,此时您可以在所创建的应用下面看到刚申请的 Key 了。


如何获取 Bundle Identifier?

以下为您提供两种获取 Bundle Identifier 的方法。 

  • 方法一

通过代码获取,代码如下所示:

NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier];
  • 方法二

Xcode 切换到 General 标签,查看 Bundle Identifier,如下图所示:


3.开通权限

需要联系高德对应接口人开通司乘同显权限。

4.配置key

引入基础SDK头文件#import <AMapFoundationKit/AMapFoundationKit.h>并添加如下示例代码,配置之前在官申请的高德Key。

[AMapServices sharedServices].apiKey = @"您的Key";


2.集成SDK包

1.CocoaPods配置

配置podfile, 在里面添加如下配置:

1)司机端:

platform :ios, '8.0'
target '您的工程名' do
pod 'AMap3DMap'
pod 'AMapNavi'
pod 'AMapSearch'
end


2)乘客端:  

platform :ios, '8.0'
target '您的工程名' do
pod 'AMap3DMap'
pod 'AMapSearch'
end

 

2.手动配置

参考http://lbs.amap.com/api/ios-sdk/guide/create-project/manual-configuration

 

3.快速接入

1.司机端

1.1.创建MADriverRouteManager

1) 初始化MADriverRouteManager

///创建司机端manager
_sctxDriverManager = [[MADriverRouteManager alloc] init];
_sctxDriverManager.mapView = self.mapView;
//设置司乘代理
_sctxDriverManager.delegate = self;
//是否打开log
_sctxDriverManager.enableDebugLog = YES;
//轨迹id
_sctxDriverManager.traceSID = [[SCTXAppSettings sharedInstance] sid];
///设置初始化参数
//是否自动调整地图
_sctxDriverManager.automaticAdjustMapRegion = YES;
//自动调整地图时间间隔
_sctxDriverManager.autoAdjustMapTimeInterval = 10;
//是否显示历史轨迹
_sctxDriverManager.showsPassedTrace = YES;
//发生偏航或者重新算路情况下,是否显示历史轨迹
_sctxDriverManager.showHistoryTraceWhileDiverged = YES;
//等客状态下,是否显示送客路线
_sctxDriverManager.showRouteWhileWaitingPassenger = YES;
//小车图标
_sctxDriverManager.carImage = [UIImage imageNamed:@"taxi_car"];
//起点图标
_sctxDriverManager.startImage = [UIImage imageNamed:@"startPoint"];
//终点图标
_sctxDriverManager.endImage = [UIImage imageNamed:@"endPoint"];
///导航相关配置
//导航策略
_sctxDriverManager.drivingStrategy = AMapNaviDrivingStrategyMultipleDefault;
//导航是否开启多备选
[_sctxDriverManager.driveManager setMultipleRouteNaviMode:YES];
//允许后台定位
_sctxDriverManager.driveManager.allowsBackgroundLocationUpdates = YES;
_sctxDriverManager.driveManager.pausesLocationUpdatesAutomatically = NO;


2)地图多代理功能

iOS司乘SDK新增了地图多代理功能,如下接口所示:

推荐用户直接使用地图多代理接口来处理地图的代理事件

@interface MAMapView (MultiDelegate)

/// 添加地图代理事件监听,注意:内部是弱引用,listener需要外部持有,不强制调用removeEventListener:方法
/// 注意,如果使用add接口后,有强制不接收代理事件的需求,设置self.mapView.delegate = nil 无效,请使用对应的remove接口
/// @param aListener 事件监听器
- (void)sctx_addEventListener:(id<MAMapViewDelegate>)aListener;

/// 移除地图代理事件监听
/// @param aListener 事件监听器
- (void)sctx_removeEventListener:(id<MAMapViewDelegate>)aListener;

@end

 

  • 地图多代理方法不需要用户做地图代理的转发工作,地图delegale代理接口不再强制实现和回调给司乘SDK 
  • 地图多代理方法可以代替地图delegale代理接口;如果用户升级使用地图多代理功能改动代码量太大,也可暂时不修改,SDK内部会做兼容处理;
/**
 * @brief 在mapView对应的delegate方法内调用此方法
 * @param mapView 地图View
 * @param animated 是否动画
 */
- (void)mapView:(MAMapView *)mapView regionWillChangeAnimated:(BOOL)animated
{
  [_driverManger mapView:mapView regionWillChangeAnimated:animated];
}

/**
 * @brief 在mapView对应的delegate方法内调用此方法
 * @param mapView 地图View
 * @param animated 是否动画
 */
- (void)mapView:(MAMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
  [_driverManger mapView:mapView regionDidChangeAnimated:animated];
}

/**
 * @brief 在mapView对应的delegate方法内调用此方法
 * @param mapView 地图View
 * @param wasUserAction 标识是否用户动作
 */
- (void)mapView:(MAMapView *)mapView mapWillMoveByUser:(BOOL)wasUserAction
{
  [_driverManger mapView:mapView mapWillMoveByUser:wasUserAction];
}

/**
 * @brief 在mapView对应的delegate方法内调用此方法
 * @param mapView 地图View
 * @param wasUserAction 标识是否用户动作
 */
- (void)mapView:(MAMapView *)mapView mapDidMoveByUser:(BOOL)wasUserAction
{
  [_driverManger mapView:mapView mapDidMoveByUser:wasUserAction];
}

/**
 * @brief 在mapView对应的delegate方法内调用此方法
 * @param mapView 地图View
 * @param wasUserAction 标识是否用户动作
 */
- (void)mapView:(MAMapView *)mapView mapWillZoomByUser:(BOOL)wasUserAction
{
  [_driverManger mapView:mapView mapWillZoomByUser:wasUserAction];
}

/**
 * @brief 在mapView对应的delegate方法内调用此方法
 * @param mapView 地图View
 * @param wasUserAction 标识是否用户动作
 */
- (void)mapView:(MAMapView *)mapView mapDidZoomByUser:(BOOL)wasUserAction
{
  [_driverManger mapView:mapView mapDidZoomByUser:wasUserAction];
}

/**  
 * @brief 在mapView对应的delegate方法内调用此方法,需要判断是否为内部overlay 
 * @param mapView 地图对象  
 * @param overlay   
 * @return 对于属于当前controller的overlay,返回相应的MAOverlayRenderer对象,否则返回nil  
 */ 
- (MAOverlayRenderer *)mapView:(MAMapView *)mapView rendererForOverlay:(id <MAOverlay>)overlay
{
    if ([_driverManger isInternalOverlay:overlay]) {
      return [_driverManger mapView:mapView rendererForOverlay:overlay];
    }
    //您自己的overlay处理
    return nil;
}

/**  
 * @brief 在对应的地图delegate方法内调用此方法,需要判断是否为内部annotation(carAnnotation,beginAnnot,ation,endAnnotation) 
 * @param mapView 地图对象  
 * @param annotation 标   
 * @return 对于属于当前controller的annotation,返回相应的annotationview,否则返回nil  
 */ 
- (MAAnnotationView *)mapView:(MAMapView *)mapView viewForAnnotation:(id <MAAnnotation>)annotation {
    if (annotation == _driverManger.carAnnotation || annotation == _driverManger.beginAnnotation || annotation == _driverManger.endAnnotation) {
      return [_driverManger mapView:mapView viewForAnnotation:annotation];
    }
    //您自己的annotation处理
    return nil;
}


1.2.设置订单信息

//经纬度创建订单(不带途经点)
[_driverManger setOrderInfoWith:[self getOrderIdText] 
                  beginPosition:_selectedStartPoint.coordinate 
                    endPosition:_selectedEndPoint.coordinate];
//POI创建订单(带途经点)
AMapNaviPOIInfo *beginInfo = [[AMapNaviPOIInfo alloc]init];
beginInfo.locPoint = [AMapNaviPoint locationWithLatitude:self.selectedBeginPoint.coordinate.latitude 
                                    longitude:self.selectedBeginPoint.coordinate.longitude];
beginInfo.mid = self.selectedBeginPOIID;
AMapNaviPOIInfo *endInfo = [[AMapNaviPOIInfo alloc]init];
endInfo.locPoint = [AMapNaviPoint locationWithLatitude:self.selectedEndPoint.coordinate.latitude 
                                  longitude:self.selectedEndPoint.coordinate.longitude];
endInfo.mid = self.selectedEndPOIID;
[_sctxDriverManager setOrderInfoWith:[self getOrderIdText] 
                         viaPOIInfos:[self getViaPoints]
                        beginPOIInfo:beginInfo 
                          endPOIInfo:endInfo];


1.3.切换订单状态

1)订单状态类型

///行程状态
typedef NS_ENUM(NSInteger, MASCTXDRouteStatus)
{
    MASCTXDRouteStatusUnspecified = 0,     ///<未指定状态
    MASCTXDRouteStatusPickupPassenger = 1, ///<去接乘客
    MASCTXDRouteStatusWaitPassenger = 2,   ///<等待乘客上车
    MASCTXDRouteStatusPassengerOnBoard = 3, ///<乘客已上车
    MASCTXDRouteStatusOrderComplete = 4,    ///<订单已结束
};


2)订单状态切换 

_driverManger.status = MASCTXDRouteStatusXXX;


1.4.调起导航组件

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

/**
 * @brief 调起导航组件。内部默认添加设置:setStartNaviDirectly:YES、
                    setNeedCalculateRouteWhenPresent:NO、
                          setNeedDestoryDriveManagerInstanceWhenDismiss:NO
 * @param compositeManager 导航组件manager
 * @param compositeUserConfig config
 * @since 3.1.0
 */
- (void)startNaviWithCompositeManager:(AMapNaviCompositeManager *)compositeManager 
                compositeUserConfig:(AMapNaviCompositeUserConfig *)compositeUserConfig;
AMapNaviCompositeUserConfig *config = [[AMapNaviCompositeUserConfig alloc] init];
[_sctxDriverManager startNaviWithCompositeManager:_naviCompositeManager compositeUserConfig:config];


2.乘客端

2.1.创建MAPassengerRouteManager

1) 初始化:

//创建乘客端
_routeManager = [[MAPassengerRouteManager alloc] initWithMapView:self.mapView delegate:self];
///初始化配置
//是否打开log输出
_routeManager.enableDebugLog = YES;
//是否展示乘客步行路线
_routeManager.showsWalkPolyline = YES;
//是否展示历史轨迹
_routeManager.showsPassedTrace = NO;
//发生偏航或者重新算路情况下,是否显示历史轨迹
_routeManager.showHistoryTraceWhileDiverged = YES;
//是否自动调整地图
_routeManager.automaticAdjustMapRegion = YES;
//轨迹key、sid
_routeManager.traceKey = [[SCTXAppSettings sharedInstance] appKey];
_routeManager.traceSID = [[SCTXAppSettings sharedInstance] sid];
//途经点图标
_routeManager.viaPointImage = [UIImage imageNamed:@"viaPoint"];
//小车图标
_routeManager.carImage = [UIImage imageNamed:@"taxi_car"];
//起点图标
_routeManager.startImage = [UIImage imageNamed:@"startPoint"];
//终点图标
_routeManager.endImage = [UIImage imageNamed:@"endPoint"];


 2)地图多代理功能

iOS司乘SDK新增了地图多代理功能,如下接口所示:

推荐用户直接使用地图多代理接口来处理地图的代理事件 

@interface MAMapView (MultiDelegate)

/// 添加地图代理事件监听,注意:内部是弱引用,listener需要外部持有,不强制调用removeEventListener:方法
/// 注意,如果使用add接口后,有强制不接收代理事件的需求,设置self.mapView.delegate = nil 无效,请使用对应的remove接口
/// @param aListener 事件监听器
- (void)sctx_addEventListener:(id<MAMapViewDelegate>)aListener;

/// 移除地图代理事件监听
/// @param aListener 事件监听器
- (void)sctx_removeEventListener:(id<MAMapViewDelegate>)aListener;

@end


  • 地图多代理方法不需要用户做地图代理的转发工作,地图delegale代理接口不再强制实现和回调给司乘SDK 
  • 地图多代理方法可以代替地图delegale代理接口;如果用户升级使用地图多代理功能改动代码量太大,也可暂时不修改,SDK内部会做兼容处理; 
/**
 * @brief 在mapView对应的delegate方法内调用此方法
 * @param mapView 地图View
 * @param animated 是否动画
 */
- (void)mapView:(MAMapView *)mapView regionWillChangeAnimated:(BOOL)animated
{
  [_routeManager mapView:mapView regionWillChangeAnimated:animated];
}

/**
 * @brief 在mapView对应的delegate方法内调用此方法
 * @param mapView 地图View
 * @param animated 是否动画
 */
- (void)mapView:(MAMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
  [_routeManager mapView:mapView regionDidChangeAnimated:animated];
}

/**
 * @brief 在mapView对应的delegate方法内调用此方法
 * @param mapView 地图view
 * @param wasUserAction 标识是否是用户动作
 */
- (void)mapView:(MAMapView *)mapView mapWillMoveByUser:(BOOL)wasUserAction
{
  [_routeManager mapView:mapView mapWillMoveByUser:wasUserAction];
}

/**
 * @brief 在mapView对应的delegate方法内调用此方法
 * @param mapView 地图view
 * @param wasUserAction 标识是否是用户动作
 */
- (void)mapView:(MAMapView *)mapView mapDidMoveByUser:(BOOL)wasUserAction
{
  [_routeManager mapView:mapView mapDidMoveByUser:wasUserAction];
}

/**
 * @brief 在mapView对应的delegate方法内调用此方法
 * @param mapView 地图view
 * @param wasUserAction 标识是否是用户动作
 */
- (void)mapView:(MAMapView *)mapView mapWillZoomByUser:(BOOL)wasUserAction
{
  [_routeManager mapView:mapView mapWillZoomByUser:wasUserAction];
}

/**
 * @brief 在mapView对应的delegate方法内调用此方法
 * @param mapView 地图view
 * @param wasUserAction 标识是否是用户动作
 */
- (void)mapView:(MAMapView *)mapView mapDidZoomByUser:(BOOL)wasUserAction
{
  [_routeManager mapView:mapView mapDidZoomByUser:wasUserAction];
}

/**  
 * @brief 在mapView对应的delegate方法内调用此方法,需要判断是否为内部overlay 
 * @param mapView 地图对象  
 * @param overlay   
 * @return 对于属于当前controller的overlay,返回相应的MAOverlayRenderer对象,否则返回nil  
 */ 
- (MAOverlayRenderer *)mapView:(MAMapView *)mapView rendererForOverlay:(id <MAOverlay>)overlay 
{
    if ([_routeManager isInternalOverlay:overlay])
    {
      return [_routeManager mapView:mapView rendererForOverlay:overlay];
    }
    //处理您自己的overaly
    return nil;
}

/**
 * @brief 在对应的地图delegate方法中调用此方法,需要判断是否为内部
 * annotation(carAnnotation、beginAnnotation、endAnnotation)。
 * @param mapView 地图
 * @param annotation 标注
 * @return 对于属于当前controller的annotation,返回相应的annotationview,否则返回nil
 */

- (MAAnnotationView *)mapView:(MAMapView *)mapView viewForAnnotation:(id <MAAnnotation>)annotation 
{
    if (annotation == _routeManager.carAnnotation || annotation == _routeManager.beginAnnotation || annotation == _routeManager.endAnnotation) 
    {
      return [_routeManager mapView:mapView viewForAnnotation:annotation];
    }
    //处理您自己的annotation
    return nil;
}


2.2.设置订单信息

创建OrderProperty

//经纬度创建订单
[_routeManager setOrderInfoWith:[self getOrderIdText]
                  beginPosition:_selectedStartPoint.coordinate
                    endPosition:_selectedEndPoint.coordinate];
// POI初始化订单
// POI订单信息
MASCTXPOIInfo *begin = [[MASCTXPOIInfo alloc]init];
begin.mid = self.selectedBeginPOIID;
begin.locPoint = self.selectedBeginPoint.coordinate;
MASCTXPOIInfo *end = [[MASCTXPOIInfo alloc]init];
end.mid = self.selectedEndPOIID;
end.locPoint = self.selectedEndPoint.coordinate;
[_routeManager setOrderInfoWith:[self getOrderIdText] 
                   beginPOIInfo:begin 
                     endPOIInfo:end];


2.3.切换订单状态

1)订单状态类型

///行程状态
typedef NS_ENUM(NSInteger, MASCTXRouteStatus)
{
    MASCTXRouteStatusUnspecified = 0,     ///<未指定状态
    MASCTXRouteStatusPickupPassenger = 1, ///<去接乘客
    MASCTXRouteStatusWaitPassenger = 2,   ///<等待乘客上车
    MASCTXRouteStatusPassengerOnBoard = 3, ///<乘客已上车
    MASCTXRouteStatusOrderComplete = 4,    ///<订单已结束
    MASCTXRouteStatusOffline = 5,          ///<离线状态,只走降级策略获取司机位置,内部不做其他请求
}


2)订单状态切换 

_routeManager.status = MASCTXRouteStatusXXX;


4、运行效果

高级功能 

功能1: 调起导航能力  

1.调起导航组件

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

/**
 * @brief 调起导航组件。内部默认添加设置:setStartNaviDirectly:YES、
                    setNeedCalculateRouteWhenPresent:NO、
                          setNeedDestoryDriveManagerInstanceWhenDismiss:NO
 * @param compositeManager 导航组件manager
 * @param compositeUserConfig config
 * @since 3.1.0
 */
- (void)startNaviWithCompositeManager:(AMapNaviCompositeManager *)compositeManager 
                compositeUserConfig:(AMapNaviCompositeUserConfig *)compositeUserConfig;
AMapNaviCompositeUserConfig *config = [[AMapNaviCompositeUserConfig alloc] init];
[_sctxDriverManager startNaviWithCompositeManager:_naviCompositeManager compositeUserConfig:config];


运行效果 


2.使用自定义导航View(AMapNaviDriveView)

1)对导航界面自定义要求比较高的情况下可以参考 导航UI定制化 介绍

2)注意事项:

  • 启动自定义导航界面时,无需调用 startGPSNavi,司乘同显内部会startGPSNavi。
  • 退出导航界面时,务必不要调用 AMapNaviDriveManager的stopNavi及 destroyInstance,司乘同显会依赖AMapNaviDriveManager的状态。


功能2: POI算路 

1.背景

在出行的业务场景中,乘客设置的终点是否合理,比如乘客可能通过拖动地图选取的终点,这样会导致终点坐标会有很大误差,导致路线规划不合理,可能无法正常到达,建议使用Poiid算路接口,这样能确保导航规划的路线终点是一个可到达的点。

2.具体实现

//上车点信息,经纬度必须填,否则起点图标不显示
AMapNaviPOIInfo *beginInfo = [[AMapNaviPOIInfo alloc]init];
beginInfo.locPoint =  [AMapNaviPoint locationWithLatitude:self.selectedBeginPoint.coordinate.latitude
    longitude:self.selectedBeginPoint.coordinate.longitude];
beginInfo.mid = self.selectedBeginPOIID;
//目的地信息,经纬度必须填,否则终点图标不显示
AMapNaviPOIInfo *endInfo = [[AMapNaviPOIInfo alloc]init];
endInfo.locPoint =  [AMapNaviPoint locationWithLatitude:self.selectedEndPoint.coordinate.latitude longitude:self.selectedEndPoint.coordinate.longitude];
endInfo.mid = self.selectedEndPOIID;
//初始化订单信息
[_sctxDriverManager setOrderInfoWith:[self getOrderIdText] viaPOIInfos:nil beginPOIInfo:beginInfo endPOIInfo:endInfo]; 


3.效果对比

                              未使用PoiId 

                                使用PoiId 


功能3: 变更上车点/途径点/目的地 

1.变更上车点

1)变更上车点只能限定在接乘客阶段,具体实现方法:

MASCTXCViaPoint *beginPoint = [MASCTXCViaPoint pointWithLatitude:39.79 longitude:116.01];
[_sctxPassengerManager updateBeginPoint:beginPoint 
                               callback:^(int resultCode, NSString * _Nullable errorMsg) {
            [self logStr:@"更改起点结果%d, %@", resultCode, errorMsg];
}];


2)变更成功或者失败均会在callback中回调,具体错误码为: 

resultCode : errorMsg
{
  0 : @"更改成功",
  1 : @"user cancelled",
  2 : @"error.description",
  3 : @"参数错误",
  4 : @"仅接客阶段才能更改起点"/@"仅送客阶段才能更改途经点或终点",
  5 : @"不适用拼车模式",
}


3)运行效果 

                                 乘客端

                                 司机端


2.变更途经点或者目的地

1)变更途经点和目的地只能限定在送乘客阶段,具体实现方法:

NSArray *points = @[[MASCTXCViaPoint pointWithLatitude:39.996349 longitude:116.46807],
                    [MASCTXCViaPoint pointWithLatitude:40.001478 longitude:116.473177],
                    [MASCTXCViaPoint pointWithLatitude:39.993982 longitude:116.480344]];
MASCTXCViaPoint *endPoint = [MASCTXCViaPoint pointWithLatitude:39.79 longitude:116.01];
[_sctxPassengerManager updateViaPointsWith:points 
                               andEndPoint:endPoint
                                  callback:^(int resultCode, NSString *errorMsg) {
            [self logStr:@"更改途径点和目的地结果%d, %@", resultCode, errorMsg];
        }];


2)变更成功或者失败均会在callback中回调,具体错误码为: 

resultCode : errorMsg
{
  0 : @"更改成功",
  1 : @"user cancelled",
  2 : @"error.description",
  3 : @"参数错误",
  4 : @"仅接客阶段才能更改起点"/@"仅送客阶段才能更改途经点或终点",
  5 : @"不适用拼车模式",
}

 

3)运行效果 

                                 乘客端

                                 司机端


功能4: 覆盖物样式自定义 

司乘同显覆盖物(车、路线、起终点)样式自定义,具体参数如下

1.司机端:

@interface MADriverRouteManager : NSObject
///小车图片
@property (nonatomic, strong) UIImage *carImage;
///起点图片
@property (nonatomic, strong) UIImage *startImage;
///终点图片
@property (nonatomic, strong) UIImage *endImage;
///路况纹理 - 拥堵
@property (nonatomic, strong) UIImage *blockedImage;
///路况纹理 - 非常缓慢
@property (nonatomic, strong) UIImage *verySlowImage;
///路况纹理 - 缓慢
@property (nonatomic, strong) UIImage *slowImage;
///路况纹理 - 畅通
@property (nonatomic, strong) UIImage *goodImage;
///路况纹理 - 未知
@property (nonatomic, strong) UIImage *unknownImage;
///路线默认纹理
@property (nonatomic, strong) UIImage *defaultImage;
///备选路况纹理 - 拥堵
@property (nonatomic, strong) UIImage *unSelectedBlockedImage;
///备选路况纹理 - 非常缓慢
@property (nonatomic, strong) UIImage *unSelectedVerySlowImage;
///备选路况纹理 - 缓慢
@property (nonatomic, strong) UIImage *unSelectedSlowImage;
///备选路况纹理 - 畅通
@property (nonatomic, strong) UIImage *unSelectedGoodImage;
///备选路况纹理 - 未知
@property (nonatomic, strong) UIImage *unSelectedUnknownImage;
///备选路线默认纹理
@property (nonatomic, strong) UIImage *unSelectedDefaultImage;
///途经点图片,适用普通订单
@property (nonatomic, strong) UIImage *viaPointImage;
///线宽,默认 18
@property (nonatomic, assign) CGFloat lineWidth;
@end
//司机端拼车单分类
@interface MADriverRouteManager (carSharing)
///默认上车点图片,如此图片和途经点中上车点图片都没有设置,则不显示上车点annotation
@property (nonatomic, strong) UIImage *wayPointImage_on;
///默认下车点图片,如此图片和途经点中下车点图片都没有设置,则不显示下车点annotation
@property (nonatomic, strong) UIImage *wayPointImage_off;
@end


2.乘客端: 

@interface MAPassengerRouteManager : NSObject
///小车图片
@property (nonatomic, strong) UIImage *carImage;
///起点图片
@property (nonatomic, strong) UIImage *startImage;
///终点图片
@property (nonatomic, strong) UIImage *endImage;
///途经点图片,适用普通订单
@property (nonatomic, strong) UIImage *viaPointImage;
///途经点上车点图片, 仅适用拼车单
@property (nonatomic, strong) UIImage *viaStartImage;
///途经点下车点图片,仅适用拼车单
@property (nonatomic, strong) UIImage *viaEndImage;
///路况纹理 - 拥堵
@property (nonatomic, strong) UIImage *blockedImage;
///路况纹理 - 非常缓慢
@property (nonatomic, strong) UIImage *verySlowImage;
///路况纹理 - 缓慢
@property (nonatomic, strong) UIImage *slowImage;
///路况纹理 - 畅通
@property (nonatomic, strong) UIImage *goodImage;
///路况纹理 - 未知
@property (nonatomic, strong) UIImage *unknownImage;
///路线默认纹理
@property (nonatomic, strong) UIImage *defaultImage;
///备选路况纹理 - 拥堵
@property (nonatomic, strong) UIImage *unSelectedBlockedImage;
///备选路况纹理 - 非常缓慢
@property (nonatomic, strong) UIImage *unSelectedVerySlowImage;
///备选路况纹理 - 缓慢
@property (nonatomic, strong) UIImage *unSelectedSlowImage;
///备选路况纹理 - 畅通
@property (nonatomic, strong) UIImage *unSelectedGoodImage;
///备选路况纹理 - 未知
@property (nonatomic, strong) UIImage *unSelectedUnknownImage;
///备选路线默认纹理
@property (nonatomic, strong) UIImage *unSelectedDefaultImage;
///步行虚线线颜色,默认为blue
@property (nonatomic, strong) UIColor *walklineColor;
///步行虚线线宽,默认 10
@property (nonatomic, assign) CGFloat walklineWidth;
///步行路线纹理(默认为nil,由于步行修改为虚线,如果设置了此纹理,则按纹理线显示)
@property (nonatomic, strong) UIImage *walkImage;
///已走过路线的纹理,默认为灰色纹理
@property (nonatomic, strong) UIImage *passedTraceImage;
///线宽,默认 18
@property (nonatomic, assign) CGFloat lineWidth;
@end


功能5: 历史轨迹展示 

用户可以在行程中实时同步司机位置到高德的轨迹服务,然后在司乘同显界面关联展示。  


1.司机位置同步

合作方可根据业务实际情况,按照2s~5s的固定频率通过此接口上传车辆位置、状态等信息。

对应接口:http://tsapi.amap.com/v1/data/vehicle?key=

详情可以参考:http://mobility.amap.com/doc/mobility-reference/server/others/vdc

 

2.历史轨迹展示

2.1.行程中

1)初始化新增轨迹服务相关设置,具体写法:(以司机端为例,乘客端写法相同)

///创建司机端manager
_sctxDriverManager = [[MADriverRouteManager alloc] init];
//设置轨迹服务id,客户可与接口人咨询,sid与key有绑定关系
_sctxDriverManager.traceSID = [[SCTXAppSettings sharedInstance] sid];
///乘客上车时间, unix时间戳(timeIntervalSince1970),单位毫秒
_sctxDriverManager.orderStartTime = @(1556002138000);
//是否显示历史轨迹
_sctxDriverManager.showsPassedTrace = YES;
//发生偏航或者重新算路情况下,是否显示历史轨迹
_sctxDriverManager.showHistoryTraceWhileDiverged = YES;


2)运行效果 


2.2.行程结束

1)行程结束用户可以通过轨迹查询接口直接查询历史轨迹进行展示,具体实现:(参考Demo)

/**
 * 历史轨迹查询
 */
- (void)historyTraceAction {    
    static MASCTXTraceQueryAllHistoryWorker *worker = nil;
    worker = [[MASCTXTraceQueryAllHistoryWorker alloc] init];
    
    NSString *key = [[SCTXAppSettings sharedInstance] appKey];
    NSString *sid = [[SCTXAppSettings sharedInstance] sid];
    NSString *orderId = [self getOrderIdText];
    
    NSTimeInterval endTime = [NSDate date].timeIntervalSince1970*1000;
    NSTimeInterval startTime = endTime - 3600*1000;
    
    [worker queryAllHistoryTraceWithKey:key sid:sid orderId:orderId startTime:startTime endTime:endTime resultCallback:^(MASCTXHistoryTraceResponse *response, NSError *error, MASCTXHistoryTraceRequest *request) {
        NSLog(@"HistoryTrace: response = %@, error = %@, request = %@", response,error,request);
        [self historyTraceActionResult:response];
    }];
}
/**
 * 历史轨迹展示
 */
- (void)historyTraceActionResult:(MASCTXHistoryTraceResponse*)response {    
    if(response.errcode != 10000) {
        return;
    }
    
    NSMutableArray<MASCTXTracePointObject *> *mArr = [NSMutableArray array];
    for(MASCTXTraceTraceObject *trace in response.tracks) {
        [mArr addObjectsFromArray:trace.points];
    }
    
    if(mArr.count == 0){
        return;
    }
    
    ///annotation
#if 0
    NSMutableArray *annoArr = [NSMutableArray array];
    for (int i = 0; i < mArr.count; ++i) {
        MASCTXTracePointObject *point = [mArr objectAtIndex:i];
        MAPointAnnotation *anno = [[MAPointAnnotation alloc] init];
        NSString *dateStr = nil;
        NSString *coordStr = nil;
        if(point.locateTime != 0) {
            NSDate *date = [NSDate dateWithTimeIntervalSince1970:point.locateTime / 1000];
            dateStr = [date description];
        }
        //dateStr = [NSString stringWithFormat:@"%lld",point.locateTime];
        coordStr = [NSString stringWithFormat:@"%.7f, %.7f", point.location.latitude,point.location.longitude];
        
        anno.title = [NSString stringWithFormat:@"%d,%@,sp=%f,di=%f,ac=%f", i,dateStr?:@"null", point.speed, point.direction, point.accuracy];
        anno.coordinate = point.location;
        [annoArr addObject:anno];
        
    }
    
    [self.mapView addAnnotations:annoArr];
    [self.mapView showAnnotations:annoArr animated:NO];
#endif
    
    ///line
    MAPolyline *polyline = nil;
    NSInteger count = mArr.count;
    CLLocationCoordinate2D *coords = (CLLocationCoordinate2D *)malloc(count * sizeof(CLLocationCoordinate2D));
    for (int j = 0; j < count; ++j) {
        MASCTXTracePointObject *point= mArr[j];
        coords[j] = point.location;
    }
    polyline = [MAPolyline polylineWithCoordinates:coords count:count];
    
    [self.mapView removeOverlay:_historyTracePolyline];
    _historyTracePolyline = polyline;
    [self.mapView addOverlay:_historyTracePolyline];
    [self.mapView showOverlays:@[_historyTracePolyline] animated:NO];
    
    free(coords);
}


2)运行效果 

 备注:历史轨迹是使用司机端实际上传的位置点进行纠偏抓路处理后的,效果取决于上传点的质量(精度、速度、方向等),如果实际效果与真实轨迹相差太大,很大可能是上传的点有问题,如丢点严重。可以反馈具体case(sid、订单号、起始时间),高德方面来排查; 


功能6: 拼车场景 

从司乘同显 2.0.0版本开始,支持拼车场景,具体实现方法:  

1.司机端

拼车单在初始化与普通订单有些区别,如下:

1)初始化订单信息,设定拼车单类型

/**************初始化订单信息,设置拼车单类型*****************/
[_driverManger setOrderInfoWith:[self getOrderIdText]];
_driverManger.orderType = kMASCTXDOrderType_carSharing;


2)添加乘客

/***************************添加乘客***********************/
///拼车单: 拼车单经纬度信息顺序,对应子订单号与上下车类型
//拼车单上下车点信息
CLLocationCoordinate2D coords[6] = {
    CLLocationCoordinate2DMake(40.012884,116.468971),
    CLLocationCoordinate2DMake(40.000787,116.409405),
    CLLocationCoordinate2DMake(40.021429,116.419533),
    CLLocationCoordinate2DMake(40.04246,116.306751),
    CLLocationCoordinate2DMake(40.003549,116.326321),
    CLLocationCoordinate2DMake(39.944614,116.322888)
};
//乘客端子订单号
NSArray *suborderIds = @[@"0001", @"0002", @"0002", @"0001", @"0003", @"0003"];
//乘客端上下车类型
int types[6] = {kMASCTXWayPoitTypeOn,kMASCTXWayPoitTypeOn,kMASCTXWayPoitTypeOff,kMASCTXWayPoitTypeOff,kMASCTXWayPoitTypeOn,kMASCTXWayPoitTypeOff};
_testWayPoints = [NSMutableArray array];
for(int i = 0; i < sizeof(coords) / sizeof(coords[0]); ++i) {
    MAWayPointInfo *wayPoint = [[MAWayPointInfo alloc] init];
    wayPoint.coord = coords[i];
    wayPoint.subOrderId = suborderIds[i];
    wayPoint.pointType = types[i];
    [_testWayPoints addObject:wayPoint];
}
[_driverManger setWayPoints:_testWayPoints];


3)切换订单状态

注意:司机端在拼车场景下只需要切换一次订单状态,即SCTXConfig.MASCTXDRouteStatusPassengerOnBoard

//切换到接驾状态,拼车单只有一个状态
_driverManger.status = MASCTXDRouteStatusPassengerOnBoard;


4)乘客状态切换

注意:接到某个乘客或者送达某个乘客时,司机端需要主动移除对应途经点,并重新调用 

[_driverManger setWayPoints:wayPoints];重置途经点列表;如果未主动移除,在驶过第一个途经点后会一直偏航重算回到该途经点;


2.乘客端

拼车单在初始化与普通订单有些区别,如下:

1)初始化订单信息,设定拼车单类型

//经纬度初始化订单
[self.sctxPassengerManager setOrderInfoWith:[self getOrderIdText] 
                              beginPosition:self.selectedBeginPoint.coordinate 
                              endPosition:self.selectedEndPoint.coordinate];
// 设置拼车子订单
self.sctxPassengerManager.subOrderID = [self getSubOrderIdText];


2)设置订单状态

 拼车单只有两个订单状态,分别为 MASCTXRouteStatusWaitPassenger(接乘客)和MASCTXRouteStatusPassengerOnBoard(送乘客) 

//切换到 接乘客 或者 送乘客 状态
self.sctxPassengerManager.status = MASCTXDRouteStatusPassengerXXX;

 

 运行效果: 

                                  司机端

                                  乘客端


功能7:司机端选择路线 

注意: 司乘同显从2.3.1版本之后支持司机端路线切换,司机端在每次算路成功时,会回调2-3条路线信息供用户选择,具体实现如下: 

 

多路线回调代理方法

/**
 @brief 多路线选择回调。算路成功,且导航返回多条路线时调用此方法。chooseResultCallback:路径选择完成的结果回调. 具体naviRoute信息在naviDriveManager中获取. 
 配合- (void)setSelectedRoute:(NSInteger)naviRouteID; 使用来选择路线。
 @param manager              MADriverRouteManager
 @param naviDriveManager     AMapNaviDriveManager
 @param chooseResultCallback 选路完成的状态回调(需要在选路完成后调用)
 */
- (void)driverRouteManager:(MADriverRouteManager *)manager naviDriveManager:(AMapNaviDriveManager*)naviDriveManager chooseResultCallback:(void(^)(void))chooseResultCallback;


功能8:乘客端选择路线 

1.司机端

司机端需要打开下面两个开关,乘客端才能正常路线选择:

// 开启多备选模式,行程中选路需要开启多备选路线支持
[_sctxDriverManager.driveManager setMultipleRouteNaviMode:YES];


2.乘客端

1)获取乘客端选择路线管理类

需要通过_sctxPassengerManager.getPassengerSelectRouteManager; 获取 乘客端路线选择管理类;

//获取乘客端选择路线管理类
MAPassengerSelectRouteManager *optionalRouteManager = _sctxPassengerManager.getPassengerSelectRouteManager;
//设定选路界面对应的 AMapView 对象,主要是用来绘制对应的覆盖物(起终点、备选路线等)
optionalRouteManager.mapView = _mapView; 


2)设置代理

//设置乘客端选择路线状态代理
optionalRouteManager.delegate = self;
//乘客端选路代理
@protocol MAPassengerSelectRouteManagerDelegate <NSObject>
@optional
/**
 @brief 乘客端路线选择回调
 @param manager 选路manager
 @param routes  多路线
 */
- (void)passengerSelectRouteManger:(MAPassengerSelectRouteManager *)manager selectRouteFrom:(NSArray<MASCTXRoute*> *)routes;
/**
 @brief 某条路线被选中回调
 @param manager 选路manager
 @param routeId 选中被高亮的路线
 */
- (void)passengerSelectRouteManger:(MAPassengerSelectRouteManager *)manager routeFocused:(NSString*)routeId;
/**
 @brief 乘客端选择路线结果回调(包括行前和行中)
 @param manager  选路manager
 @param type     选路结果回调MASCTXSelectRouteResult
 */
- (void)passengerSelectRouteManger:(MAPassengerSelectRouteManager *)manager selectRouteRuseltType:(MASCTXSelectRouteType)type;
@end


选路回调代理状态类型MASCTXSelectRouteType: 

typedef enum : NSUInteger {
    MASCTXSelectRoutePassengerPullRoutesFailed = 3002,     //乘客行前拉取路线失败
    MASCTXSelectRoutePassengerSelectRouteSuccess = 3003,   //乘客选择路线推送服务端成功
    MASCTXSelectRoutePassengerSelectRouteFailed = 3004,    //乘客选择路线推送服务端失败
    MASCTXSelectRouteDriverChangeOnPreRouteSuccess = 3005, //司机切换乘客行前选择路线成功
    MASCTXSelectRouteDriverChangeOnPreRouteFailed = 3006,  //司机切换乘客行前选择路线失败
    MASCTXSelectRouteDriverChangeOnBoardRouteSuccess = 3007,     //司机切换乘客行中选择路线成功
    MASCTXSelectRouteDriverChangeOnBoardRouteFailed = 3008,      //司机切换乘客行中选择路线失败
    MASCTXSelectRouteDriverYaw = 3009,                           //司机偏航
    MASCTXSelectRouteExistViaPointChangeRouteFailed = 3010,      //添加途经点导致司机切换选路失败
    MASCTXSelectRoutePassengerRefreshSelectRouteNoUpdate = 3011, //乘客重算路径与当前一致,请稍后再试
    MASCTXSelectRouteEndPointHasChangedChangeRouteFailed = 3012, //目的地已变更,导致司机切换选路失败
} MASCTXSelectRouteType; 


3)开始选路

行车前乘客端选路会实时规划上车点到下车点的路线供选择,选定后,司机端在切换到行程中会使用该路线进行导航;

行程中乘客端选路会依赖司机端同步的多备选路线,切换实时生效;

//进入选路状态
[_optionalRouteManager enterChoosingRouteState];


4)选定路线

 (注意:行程前选择路线后,目的地有变更或者新增途经点,选路均会失效) 

//选定某条路线
[_optionalRouteManager selectedRouteFinished]; 


5)停止选路

//停止选路
[_optionalRouteManager quitChoosingRouteState];


运行效果 

                         行程前选路 


                         行程中选路 


功能9:司机端等待乘客状态路线模式(MADriverRouteManager)

/**
 * @brief 等客状态下,展示路线类型 参量参考:
 * 1.MASCTXDriverWaitingRouteModePickUp = 0 展示接乘客路线,默认值 
 * 2.MASCTXDriverWaitingRouteModeOnBoard = 1 展示送乘客路线 
 * 3.MASCTXDriverWaitingRouteModeNoRoute = 2 不展示路线
 */
- (MASCTXDriverWaitingRouteMode) driverWaitingRouteMode


功能10:设置驶过终点重算距离阈值(MADriverRouteManager)

/**
 * @brief 到达圈半径,当司机驶过终点,而没有及时改变订单状态,在驶出该半径范围会立即触发重新算路逻辑
 * @param destinationFenceRadius 单位: 米, 默认值200,可自定义范围[50 - 1000] 
 */
- (CGFloat) destinationFenceRadius


功能11:司机端路线选择routeId(乘客端/服务端)回调(MADriverRouteManager)

/**
 * @brief 司机行中拉取服务路线回调
 * @param manager MADriverRouteManager
 * @param routeId 路线id
 * @param type    路线来源 常量参考:
 * 1.MASCTXDSelectRouteSourceTypePassenger = 0, //乘客端选路
 * 2.MASCTXDSelectRouteSourceTypeServer  = 1,   //服务端绑路
 */
- (void)driverRouteManager:(MADriverRouteManager *)manager selectedRouteId:(NSString*)routeId type:(MASCTXDSelectRouteSourceType)type;


功能12:乘客端由司机端触发的 上车点/目的地/途经点 变更的回调(MASCTXAlertMessageType)

MASCTXAlertMessageDriverHasChangedBeginPoint = 1014, ///司机端更改了起点
    
MASCTXAlertMessageDriverHasChangedEndPoint = 1015,   ///司机端更改了终点
    
MASCTXAlertMessageDriverHasChangedViaPoints = 1016,  ///司机端更改了途经点


返回顶部 示例中心 常见问题 智能客服 公众号
二维码