이 섹션에서는 Apple CarPlay와 함께 Navigation SDK를 사용하는 방법을 설명합니다. 대시보드 head에 앱의 탐색 환경을 표시하는 라이브러리 단위를 참고하세요. 운전자가 대시보드 내 시스템은 CarPlay를 지원하므로 운전자는 자동차 디스플레이를 연결할 수 있습니다. 음성 안내는 다음 기기에서도 실행됨 자동차 스피커입니다.
Apple에서 제공하는 UI 템플릿 모음에서 CarPlay 앱을 빌드합니다. 내 표시할 템플릿을 선택하고 데이터를 제공해야 합니다. 있습니다.
대시보드 내 시스템에는 안전 승인 대화형 요소가 표시되므로 목적지까지 안전하게 내비게이션을 이용합니다. 집중해야 합니다. 또한 운전자가 운송 수단과 상호작용할 수 있도록 주문 수락/거부 또는 조회와 같은 앱 관련 기능 지도에서 고객의 위치를 표시합니다. 주문 상태 업데이트는 대시보드 내 단위에 표시되도록 프로그래밍되어 있습니다.
<ph type="x-smartling-placeholder">설정
CarPlay로 시작하기
먼저 Apple 문서를 숙지합니다.
Navigation SDK 설정
- Apple 문서를 살펴봤다면 이제 Navigation SDK를 구현하는 방법을 보여줍니다.
- 프로젝트 설정: 아직 앱에 Navigation SDK를 통합하지 않은 상태여야 합니다.
- TurnByTurn 안내 사용 설정 피드를 만듭니다.
- 선택사항입니다. 생성된 이미지 사용 아이콘 있습니다.
- UIView 클래스에 제공된
GMSMapView
클래스를 사용하여 지도를 그립니다. 자세한 내용은 자세한 내용은 경로를 탐색하세요. 확인할 수 있습니다CPNavigationSession
를 TurnByTurn 라이브러리를 사용하세요.
지도 및 탐색 UI 그리기
이
GMSMapView
드림
클래스는 지도를 렌더링하고
CPMapTemplate
CarPlay 화면에서 UI를 렌더링합니다. 이 도구는 Kubernetes와
GMSMapView
는 스마트폰의 경우 작동하지만 상호작용이 제한됩니다.
Swift
init(window: CPWindow) {
super.init(nibName: nil, bundle: nil)
self.window = window
// More CPMapTemplate initialization
}
override func viewDidLoad() {
super.viewDidLoad()
let mapViewOptions = GMSMapViewOptions()
mapViewOptions.screen = window.screen
mapViewOptions.frame = self.view.bounds
mapView = GMSMapView(options: mapViewOptions)
mapView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
mapView.settings.isNavigationHeaderEnabled = false
mapView.settings.isNavigationFooterEnabled = false
// Disable buttons: in CarPlay, no part of the map is clickable.
// The app should instead place these buttons in the appropriate slots of the CarPlay template.
mapView.settings.compassButton = false
mapView.settings.isRecenterButtonEnabled = false
mapView.shouldDisplaySpeedometer = false
mapView.isMyLocationEnabled = true
self.view.addSubview(mapView)
}
Objective-C
- (instancetype)initWithWindow:(CPWindow *)window {
self = [super initWithNibName:nil bundle:nil];
if (self) {
_window = window;
// More CPMapTemplate initialization
}
}
- (void)viewDidLoad {
[super viewDidLoad];
GMSMapViewOptions *options = [[GMSMapViewOptions alloc] init];
options.screen = _window.screen;
options.frame = self.view.bounds;
_mapView = [[GMSMapView alloc] initWithOptions:options];
_mapView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
_mapView.settings.navigationHeaderEnabled = NO;
_mapView.settings.navigationFooterEnabled = NO;
// Disable buttons: in CarPlay, no part of the map is clickable.
// The app should instead place these buttons in the appropriate slots of the CarPlay template.
_mapView.settings.compassButton = NO;
_mapView.settings.recenterButtonEnabled = NO;
_mapView.shouldDisplaySpeedometer = NO;
_mapView.myLocationEnabled = YES;
[self.view addSubview:_mapView];
}
지도 상호작용 사용 설정
운전자 안전을 보장하기 위해 CarPlay는 화면 표시 경로에서 일련의 상호작용으로 상호작용합니다.
/
CPMapTemplateDelegate
드림
메서드를 참조하세요. 이 콜백을 사용하여 지도와의 제한적인 운전자 상호작용을 지원합니다.
표시됩니다.
추가 사용자 작업을 지원하려면 CPMapButton
의 배열을 만들고
CPMapTemplate.mapButtons
로 전송합니다.
다음 코드는 화면 이동, 확대/축소를 위한 화면 이동 상호작용과 버튼을 만듭니다. 사용자의 위치를 제공합니다.
화면 이동 상호작용
Swift
// MARK: CPMapTemplateDelegate
func mapTemplate(_ mapTemplate: CPMapTemplate, panBeganWith direction: CPMapTemplate.PanDirection) {
}
func mapTemplate(_ mapTemplate: CPMapTemplate, panWith direction: CPMapTemplate.PanDirection) {
let scrollAmount = scrollAmount(for: direction)
let scroll = GMSCameraUpdate.scrollBy(x: scrollAmount.x, y: scrollAmount.y)
mapView.animate(with: scroll)
}
func mapTemplate(_ mapTemplate: CPMapTemplate, panEndedWith direction: CPMapTemplate.PanDirection) {
}
func scrollAmount(for panDirection: CPMapTemplate.PanDirection) -> CGPoint {
let scrollDistance = 80.0
var scrollAmount = CGPoint(x: 0, y: 0)
switch panDirection {
case .left:
scrollAmount.x -= scrollDistance
break;
case .right:
scrollAmount.x += scrollDistance
break;
case .up:
scrollAmount.y += scrollDistance
break;
case .down:
scrollAmount.y -= scrollDistance
break;
default:
break;
}
if scrollAmount.x != 0 && scrollAmount.y != 0 {
// Adjust length if scrolling diagonally.
scrollAmount = CGPointMake(scrollAmount.x * sqrt(1.0/2.0), scrollAmount.y * sqrt(1.0/2.0))
}
return scrollAmount
}
Objective-C
#pragma mark - CPMapTemplateDelegate
- (void)mapTemplate:(CPMapTemplate *)mapTemplate panBeganWithDirection:(CPPanDirection)direction {
}
- (void)mapTemplate:(CPMapTemplate *)mapTemplate panWithDirection:(CPPanDirection)direction {
CGPoint scrollAmount = [self scrollAmountForPanDirection:direction];
GMSCameraUpdate *scroll = [GMSCameraUpdate scrollByX:scrollAmount.x Y:scrollAmount.y];
[_mapView animateWithCameraUpdate:scroll];
}
- (void)mapTemplate:(CPMapTemplate *)mapTemplate panEndedWithDirection:(CPPanDirection)direction {
}
- (CGPoint)scrollAmountForPanDirection:(CPPanDirection)direction {
static const CGFloat scrollDistance = 80.;
CGPoint scrollAmount = {0., 0.};
if (direction & CPPanDirectionLeft) {
scrollAmount.x = -scrollDistance;
}
if (direction & CPPanDirectionRight) {
scrollAmount.x = scrollDistance;
}
if (direction & CPPanDirectionUp) {
scrollAmount.y = -scrollDistance;
}
if (direction & CPPanDirectionDown) {
scrollAmount.y = scrollDistance;
}
if (scrollAmount.x != 0 && scrollAmount.y != 0) {
// Adjust length if scrolling diagonally.
scrollAmount =
CGPointMake(scrollAmount.x * (CGFloat)M_SQRT1_2, scrollAmount.y * (CGFloat)M_SQRT1_2);
}
return scrollAmount;
}
일반적인 버튼 사용법
Swift
// MARK: Create Buttons
func createMapButtons() -> [CPMapButton] {
let panButton = mapButton(systemImageName: "dpad.fill") { [weak self] in
self?.didTapPanButton()
}
let zoomOutButton = mapButton(systemImageName: "minus.magnifyingglass") { [weak self] in
self?.didTapZoomOutButton()
}
let zoomInButton = mapButton(systemImageName: "plus.magnifyingglass") { [weak self] in
self?.didTapZoomInButton()
}
let myLocationButton = mapButton(systemImageName: "location") { [weak self] in
self?.didTapMyLocationButton()
}
let mapButtons = [panButton, zoomOutButton, zoomInButton, myLocationButton]
return mapButtons
}
func mapButton(systemImageName: String, handler: @escaping () -> Void) -> CPMapButton {
}
// MARK: Button callbacks
@objc func didTapPanButton() {
mapTemplate?.showPanningInterface(animated: true)
}
@objc func didTapZoomOutButton() {
mapView.animate(with: GMSCameraUpdate.zoomOut())
}
@objc func didTapZoomInButton() {
mapView.animate(with: GMSCameraUpdate.zoomIn())
}
@objc func didTapMyLocationButton() {
if let lastLocation = lastLocation {
let cameraPosition = GMSCameraPosition(target: lastLocation.coordinate, zoom: 15)
mapView.animate(to: cameraPosition)
}
}
Objective-C
#pragma mark - Create Buttons
- (NSArray<CPMapButton *>*)createMapButtons {
NSMutableArray<CPMapButton *> *mapButtons = [NSMutableArray<CPMapButton *> array];
__weak __typeof__(self) weakSelf = self;
CPMapButton *panButton = [self mapButtonWithSystemImageNamed:@"dpad.fill"
handler:^(CPMapButton *_) {
[weakSelf didTapPanButton];
}];
[mapButtons addObject:panButton];
CPMapButton *zoomOutButton =
[self mapButtonWithSystemImageNamed:@"minus.magnifyingglass"
handler:^(CPMapButton *_Nonnull mapButon) {
[weakSelf didTapZoomOutButton];
}];
[mapButtons addObject:zoomOutButton];
CPMapButton *zoomInButton =
[self mapButtonWithSystemImageNamed:@"plus.magnifyingglass"
handler:^(CPMapButton *_Nonnull mapButon) {
[weakSelf didTapZoomInButton];
}];
[mapButtons addObject:zoomInButton];
CPMapButton *myLocationButton =
[self mapButtonWithSystemImageNamed:@"location"
handler:^(CPMapButton *_Nonnull mapButton) {
[weakSelf didTapMyLocationButton];
}];
[mapButtons addObject:myLocationButton];
return mapButtons;
}
#pragma mark - Button Callbacks
- (void)didTapZoomOutButton {
[_mapView animateWithCameraUpdate:[GMSCameraUpdate zoomOut]];
}
- (void)didTapZoomInButton {
[_mapView animateWithCameraUpdate:[GMSCameraUpdate zoomIn]];
}
- (void)didTapMyLocationButton {
CLLocation *location = self.lastLocation;
if (location) {
GMSCameraPosition *position =
[[GMSCameraPosition alloc] initWithTarget:self.lastLocation.coordinate zoom:15.];
[_mapView animateToCameraPosition:position];
}
}
- (void)didTapPanButton {
[_mapTemplate showPanningInterfaceAnimated:YES];
_isPanningInterfaceEnabled = YES;
}
- (void)didTapStopPanningButton {
[_mapTemplate dismissPanningInterfaceAnimated:YES];
_isPanningInterfaceEnabled = NO;
}
참고: CarPlay 화면에서는 대체 경로를 선택할 수 없습니다. 필수 요건 선택할 수 있습니다.
내비게이션 경로 표시
이 섹션에서는 데이터 피드의 리스너를 설정하는 방법과 안내 및 예상 이동 시간 패널에서 탐색 경로를 확인할 수 있습니다. 자세한 내용은 '빌드' CarPlay 내비게이션 앱" Google Play 앱 프로그래밍 섹션의 가이드 를 참조하세요.
안내 및 예상 이동 시간 패널은 다음 정보를 표시하는 탐색 카드를 제공합니다. 현재 이동과 관련된 내비게이션 정보 Google의 TurnByTurn Navigation SDK를 사용하면 기호, 텍스트, 확인할 수 있습니다
리스너 설정
세부 경로 안내 세부정보에 있는 이벤트 리스너 설정 안내를 따릅니다. 데이터 피드가 있어야 합니다.
내비게이션 정보 채우기
다음 코드 샘플의 첫 번째 부분은 CarPlay를 만드는 방법을 보여줍니다.
예상 여행 비용을
GMSNavigationNavInfo.timeToCurrentStepSeconds
에서 CPTravelEstimate
(으)로 다음을 수행할 수 있습니다.
세부 경로 안내 데이터 세부정보에서 이 요소 및 기타 표시 요소에 대해 자세히 알아보세요.
피드가 있어야 합니다.
샘플의 두 번째 부분에서는 객체를 만들어
CPManuevers
의 userInfo
필드입니다. 이렇게 하면 CPManeuverDisplayStyle
,
차선 안내 정보에도 사용됩니다. Apple의 CarPlay 앱 보기
프로그래밍
가이드
를 참조하세요.
Swift
// Get a CPTravelEstimate from GMSNavigationNavInfo
func getTravelEstimates(from navInfo:GMSNavigationNavInfo) -> CPTravelEstimates {
let distanceRemaining = navInfo.roundedDistance(navInfo.distanceToCurrentStepMeters)
let timeRemaining = navInfo.roundedTime(navInfo.timeToCurrentStepSeconds)
let travelEstimates = CPTravelEstimates(distanceRemaining: distanceRemaining, timeRemaining: timeRemaining)
return travelEstimates
}
// Create an object to be stored in the userInfo field of CPManeuver to determine the CPManeuverDisplayStyle.
/** An object to be stored in the userInfo field of a CPManeuver. */
struct ManeuverUserInfo {
var stepInfo: GMSNavigationStepInfo
var isLaneGuidance: Bool
}
func mapTemplate(_ mapTemplate: CPMapTemplate, displayStyleFor maneuver: CPManeuver) -> CPManeuverDisplayStyle {
let userInfo = maneuver.userInfo
if let maneuverUserInfo = userInfo as? ManeuverUserInfo {
return maneuverUserInfo.isLaneGuidance ? .symbolOnly : .leadingSymbol
}
return .leadingSymbol
}
// Get a CPManeuver with instructionVariants and symbolImage from GMSNavigationStepInfo
func getManeuver(for stepInfo: GMSNavigationStepInfo) -> CPManeuver {
let maneuver = CPManeuver()
maneuver.userInfo = ManeuverUserInfo(stepInfo: stepInfo, isLaneGuidance: false)
switch stepInfo.maneuver {
case .destination:
maneuver.instructionVariants = ["Your destination is ahead."]
break
case .destinationLeft:
maneuver.instructionVariants = ["Your destination is ahead on your left."]
break
case .destinationRight:
maneuver.instructionVariants = ["Your destination is ahead on your right."]
break
default:
maneuver.attributedInstructionVariants = currentNavInfo?.instructions(forStep: stepInfo, options: instructionOptions)
break
}
maneuver.symbolImage = stepInfo.maneuverImage(with: instructionOptions.imageOptions)
return maneuver
}
// Get the lane image for a CPManeuver from GMSNavigationStepInfo
func laneGuidanceManeuver(for stepInfo: GMSNavigationStepInfo) -> CPManeuver? {
let maneuver = CPManeuver()
maneuver.userInfo = ManeuverUserInfo(stepInfo: stepInfo, isLaneGuidance: true)
let lanesImage = stepInfo.lanesImage(with: imageOptions)
guard let lanesImage = lanesImage else { return nil }
maneuver.symbolImage = lanesImage
return maneuver
}
Objective-C
// Get a CPTravelEstimate from GMSNavigationNavInfo
- (nonull CPTravelEstimates *)travelEstimates:(GMSNavigationNavInfo *_Nonnull navInfo) {
NSMeasurement<NSUnitLength *> *distanceRemaining = [navInfo roundedDistance:navInfo.distanceToCurrentStepMeters];
NSTimeInterval timeRemaining = [navInfo roundedTime:navInfo.timeToCurrentStepSeconds];
CPTravelEstimate* travelEstimate = [[CPTravelEstimates alloc] initWithDistanceRemaining:distanceRemaining
timeRemaining:timeRemaining];
}
// Create an object to be stored in the userInfo field of CPManeuver to determine the CPManeuverDisplayStyle.
/** An object to be stored in the userInfo field of a CPManeuver. */
@interface ManeuverUserInfo : NSObject
@property(nonatomic, readonly, nonnull) GMSNavigationStepInfo *stepInfo;
@property(nonatomic, readonly, getter=isLaneGuidance) BOOL laneGuidance;
- (nonnull instancetype)initWithStepInfo:(GMSNavigationStepInfo *)stepInfo
isLaneGuidance:(BOOL)isLaneGuidance NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
- (CPManeuverDisplayStyle)mapTemplate:(CPMapTemplate *)mapTemplate
displayStyleForManeuver:(nonnull CPManeuver *)maneuver {
ManeuverUserInfo *userInfo = maneuver.userInfo;
return userInfo.laneGuidance ? CPManeuverDisplayStyleSymbolOnly : CPManeuverDisplayStyleDefault;
}
// Get a CPManeuver with instructionVariants and symbolImage from GMSNavigationStepInfo
- (nonnull CPManeuver *)maneuverForStep:(nonnull GMSNavigationStepInfo *)stepInfo {
CPManeuver *maneuver = [[CPManeuver alloc] init];
maneuver.userInfo = [[ManeuverUserInfo alloc] initWithStepInfo:stepInfo isLaneGuidance:NO];
switch (stepInfo.maneuver) {
case GMSNavigationManeuverDestination:
maneuver.instructionVariants = @[ @"Your destination is ahead." ];
break;
case GMSNavigationManeuverDestinationLeft:
maneuver.instructionVariants = @[ @"Your destination is ahead on your left." ];
break;
case GMSNavigationManeuverDestinationRight:
maneuver.instructionVariants = @[ @"Your destination is ahead on your right." ];
break;
default: {
maneuver.attributedInstructionVariants =
[_currentNavInfo instructionsForStep:stepInfo options:_instructionOptions];
break;
}
}
maneuver.symbolImage = [stepInfo maneuverImageWithOptions:_instructionOptions.imageOptions];
return maneuver;
}
// Get the lane image for a CPManeuver from GMSNavigationStepInfo
- (nullable CPManeuver *)laneGuidanceManeuverForStep:(nonnull GMSNavigationStepInfo *)stepInfo {
CPManeuver *maneuver = [[CPManeuver alloc] init];
maneuver.userInfo = [[ManeuverUserInfo alloc] initWithStepInfo:stepInfo isLaneGuidance:YES];
UIImage *lanesImage = [stepInfo lanesImageWithOptions:_imageOptions];
if (!lanesImage) {
return nil;
}
maneuver.symbolImage = lanesImage;
return maneuver;
}
조작
CarPlay에서는 CPManeuver
를 사용합니다.
클래스를 사용하여
세부 경로 안내 세부 경로 데이터 세부정보 보기
피드를 방문하여 자세한 내용을 확인하세요.
계기가 되길 바랍니다.