司乘同显-iOS 最后更新时间: 2020年12月15日
快速接入
1.获取Key
1.创建新应用
进入控制台,创建一个新应用。如果您之前已经创建过应用,可直接跳过这个步骤。
![](https://a.amap.com/chuxing/static/司乘同显-IOS/快速接入获取key1.png)
2.添加新key
在创建的应用上点击"添加新Key"按钮,在弹出的对话框中,依次输入应用名名称,选择绑定的服务为“iOS平台SDK”,输入您的key名称Bundle ID,如下图所示:
需要注意的是: 1个KEY只能用于一个应用,1个Key在多个应用上使用会出现服务调用失败。
![](https://a.amap.com/chuxing/static/司乘同显-IOS/快速接入获取key2.png)
在阅读完高德地图API服务条款后,勾选此选项,点击“提交”,完成 Key 的申请,此时您可以在所创建的应用下面看到刚申请的 Key 了。
如何获取 Bundle Identifier?
以下为您提供两种获取 Bundle Identifier 的方法。
- 方法一
通过代码获取,代码如下所示:
NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier];
- 方法二
Xcode 切换到 General 标签,查看 Bundle Identifier,如下图所示:
![](https://a.amap.com/chuxing/static/司乘同显-IOS/快速接入获取BundleIdentifier方法.png)
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.手动配置
参考https://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、运行效果
![](https://a.amap.com/chuxing/static/司乘同显-IOS/入门指南运行效果.gif)
高级功能
功能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];
运行效果
![](https://a.amap.com/chuxing/static/司乘同显-IOS/调起导航功能运行效果.gif)
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
![](https://a.amap.com/chuxing/static/司乘同显-IOS/POI算路效果对比未使用POIID.png)
使用PoiId
![](https://a.amap.com/chuxing/static/司乘同显-IOS/POI算路效果对比使用POIID.png)
功能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)运行效果
乘客端
![](https://a.amap.com/chuxing/static/司乘同显-IOS/变更上车点运行效果乘客端.gif)
司机端
![](https://a.amap.com/chuxing/static/司乘同显-IOS/变更上车点运行效果司机端.gif)
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)运行效果
乘客端
![](https://a.amap.com/chuxing/static/司乘同显-IOS/变更途经点或者目的地运行效果乘客端.gif)
司机端
![](https://a.amap.com/chuxing/static/司乘同显-IOS/变更途经点或者目的地运行效果司机端.gif)
功能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的固定频率通过此接口上传车辆位置、状态等信息。
对应接口:https://tsapi.amap.com/v1/data/vehicle?key=
详情可以参考:https://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)运行效果
![](https://a.amap.com/chuxing/static/司乘同显-IOS/历史轨迹展示行程中运行效果.png)
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)运行效果
![](https://a.amap.com/chuxing/static/司乘同显-IOS/历史轨迹展示行程结束后运行效果.png)
备注:历史轨迹是使用司机端实际上传的位置点进行纠偏抓路处理后的,效果取决于上传点的质量(精度、速度、方向等),如果实际效果与真实轨迹相差太大,很大可能是上传的点有问题,如丢点严重。可以反馈具体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;
运行效果:
司机端
![](https://a.amap.com/chuxing/static/司乘同显-IOS/拼车场景运行效果司机端.png)
乘客端
![](https://a.amap.com/chuxing/static/司乘同显-IOS/拼车场景运行效果乘客端.png)
功能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];
运行效果
行程前选路
![](https://a.amap.com/chuxing/static/司乘同显-IOS/路线选择行程前选路乘客端.gif)
![](https://a.amap.com/chuxing/static/司乘同显-IOS/路线选择行程前选路司机端.gif)
行程中选路
![](https://a.amap.com/chuxing/static/司乘同显-IOS/路线选择行程中选路司机端.gif)
功能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, ///司机端更改了途经点