Привет! Меня зовут Ваня, я пишу мобильное приложение 2ГИС под iOS. Сегодня будет история о том, как наш навигатор появился в CarPlay. Расскажу, как с такой себе документацией и недоделанными инструментами мы создали рабочий продукт и разместили его в AppStore.


Пара слов о CarPlay



Сначала немного матчасти для понимания некоторых аспектов работы CarPlay и причин, по которым мы приняли те или иные решения.


CarPlay — это не ОС внутри другой ОС, как об этом пишут в очень многих статьях. Если грубо, то CarPlay — это протокол для работы с внешним дисплеем экрана головного устройства; звуком из динамиков автомобиля; тач-скринами, тач-панелями, шайбами и другими устройствами ввода.


То есть весь исполняемый код находится непосредственно в основном приложении (даже не в отдельном extension’е!) Это очень круто: чтобы получить новые фичи, не нужно обновлять магнитолу или даже машину, нужно просто обновить iOS.


На WWDC 2018 Keynote нам представили возможность создания навигационных приложений под CarPlay, что нас очень обрадовало. Сразу после презентации мы отправили запрос на разрешение разработки под CarPlay. В запросе необходимо было показать, что наше приложение умеет в навигацию.


Пока мы ждали ответа от Apple, вышла лекция, в которой на примере sample-приложения CountryRoads рассказывали о работе с CarPlay.framework. В лекции не рассказали о подводных камнях и тонкостях при работе с CarPlay, но упомянули, что после подключения к CarPlay-магнитоле приложение будет работать в режиме background.


Первая палка в колёса


Работа приложения в background’е нас разочаровала. На это было две причины:


  1. Мы не работаем в background’е. Когда-то оставили это ограничение по техническим причинам и ради энергосбережения.
  2. Наша карта написана на OpenGL (да, deprecated, да, не Metal, мы всё это знаем), а OpenGL в background state’е не работает. В лучшем случае вы получите чёрную вьюху, а в худшем — краш.

С работой в background’е ещё можно было справиться, но с картой определённо нужно было что-то решать. Тогда-то и пришла идея сделать её через стандартную MKMapView. Пока вы не начали закидывать нас камнями за идею использовать стандартные карты Apple, объясню: мы собирались использовать MKMapView, но не карты Apple.


Дело в том, что MKMapView умеет в загрузку сторонних тайлов. Тайлы — это специальные прямоугольные контейнеры для текстур. У нас как раз оказался сервачок, который умеет отдавать тайлы. На GitHub есть код с реализацией.


Ответ от Apple


Нам пришёл ответ от Apple, в котором, кроме разрешения на разработку, мы получили ещё и документацию «для избранных», код sample-приложения CountryRoads (его показывали на лекции WWDC) и, самое важное, приватный capability-ключ com.apple.developer.carplay-maps. Этот ключ прописывают в entitlements-файле со значением YES, чтобы система поняла, что вы можете обработать события от CarPlay при запуске вашего приложения.


Не дождавшись спринта с выделенными под разработку сториками, я полез качать Xcode Beta. Первая попытка собрать 2ГИС была провальной. Зато проект sample-приложения CoutryRoads удалось собрать под симулятор.


Перед каждым открытием окна симулятора CarPlay, последний должен был кастомизироваться через такое вот окно:



Для этого нужно было прописать в терминале строчку: defaults write com.apple.iphonesimulator CarPlayExtraOptions -bool YES


По какой-то причине это не сработало — пришлось запускать почти на самом маленьком симуляторе с разрешением 800?480 поинтов и скейлом ?2. В данный момент эта настройка работает и отлично помогает.


Создав свой sample-проект и вооружившись документацией, я начал разбираться, что к чему.
Первое, что я понял: навигационные приложения для CarPlay состоят из слоёв base view и templates.



Base view — это ваша карта. На этом слое должна быть только карта, никаких других вьюх и контролов.


Templates — это почти не кастомизирующийся обязательный набор UI-элементов для отображения маршрутов, манёвров, всяких списочков и так далее.


Разработка беты


Перейдём уже к написанию кода. Первое, что необходимо сделать, — реализовать парочку обязательных методов CPApplicationDelegate в файле ApplicationDelegate.


func application(
   _ application: UIApplication,
   didConnectCarInterfaceController controller: CPInterfaceController,
   to window: CPWindow
) {}

func application(
  _ application: UIApplication,
  didDisconnectCarInterfaceController controller: CPInterfaceController,
  from window: CPWindow
) {}

Давайте рассмотрим сигнатуру:


С UIApplication всё понятно.
CPWindow — наследник UIWindow, окно для внешнего дисплея головного устройства магнитолы.
CPInterfaceController — что-то типа аналога UINavigationController’а, только из CarPlay.framework.


Теперь перейдём непосредственно к реализации метода.


func application(
   _ application: UIApplication,
   didConnectCarInterfaceController controller: CPInterfaceController,
   to window: CPWindow
) {
  let carMapViewController = CarMapViewController(
    interfaceController: controller
  )
  let navigationController = UINavigationController(
    rootViewController: carMapViewController
  )
  window.rootViewController = navigationController
}

В didConnect необходимо написать код, похожий на тот, который мы привыкли видеть в didFinishLaunching. CarMapViewController — это base view (контроллер на самом деле, но ладно), как по документации.


Вот такую картинку в итоге я получил:



Где-то в это время до меня дошло, что в новом Xcode new build system включена по умолчанию и, скорее всего, из-за этого 2ГИС не собирается.


Я открыл Xcode, поставил legacy (а точнее stable, давайте называть вещи своими именами) build system, и моя теория подтвердилась: 2ГИС собрался.


Выставив тот самый capability-ключ, я запустил 2ГИС под CarPlay и не увидел логов о переходе приложения в режим background. Стало ещё непонятнее, ведь инженеры Apple со сцены сказали про background-режим, но, с другой стороны, нам обещали contentView у UIAlertView, а в итоге UIAlertView стал deprecated.


Решив, что так и должно быть, я не стал заморачиваться с MKMapView. Она лишила бы нас оффлайна и заставила заново писать отрисовку маршрутов.


Проблема одной карты


Не успел я обрадоваться новости о том, что в CarPlay будет наша карта, как передо мной встала следующая проблема: из-за технических особенностей карта может быть только одна.
Быстрое решение этой проблемы было, хоть и не очень элегантное.


Обычно в момент использования 2ГИС на CarPlay телефон заблокирован и лежит где-нибудь на полочке. А значит карта в этот момент на телефоне не сильно-то и нужна (не помешает для поиска, конечно). Поэтому мы решили при подсоединении телефона к CarPlay забирать карту из основного приложения и выводить её на экран CarPlay магнитолы. А при отсоединении, соответственно, возвращать обратно в приложение на телефон.


Да, решение такое себе, но оно быстрое, до сих пор работает и не пришлось пинать пару других команд, чтобы склепать MVP.


Контролы на карте


Итак, мы получили нашу карту на экране магнитолы. Теперь необходимо было сделать первые и очевидные для любой карты вещи: контролы зума, текущего местоположения и перемещения карты.



Начнём с зума и текущего местоположения, ведь эти контролы находятся на самой карте и это не обычные UIControl. Как я писал выше, на base view находится только карта.


Для того, что бы поместить эти контролы на карту, пришлось снова лезть в документацию и sample-приложение. Там я вычитал про первый темплейт — CPMapTemplate.



CPMapTemplate — прозрачный темплейт для отображения некоторых контролов на карте и аналога navigationBar’а. Создаётся и выставляется он так:


let mapTemplate = CPMapTemplate()
self.interfaceController.setRootTemplate(mapTemplate, animated: false)

Далее необходимо создать эти контролы и положить их на карту.


let zoomInButton = CPMapButton(…)
let zoomOutButton = CPMapButton(…)
let myLocationButton = CPMapButton(…)

self.mapTemplate.mapButtons = [
  zoomInButton, 
  zoomOutButton, 
  myLocationButton
]

Но массив mapButtons оказался с приколом, ведь сколько в него элементов ни клади, он возьмёт только первые три элемента и отобразит их на экране. Ни ошибок в лог, ни ассертов вы не получите.


Дальше я полез смотреть, как мне заставить двигаться карту, и нашёл в документации вот такое:


Navigation apps are designed to work with a variety of car input devices, and CarPlay does not support direct user interaction in the base view (apps do not directly receive tap or drag events). 

Странно, подумал я, и полез смотреть, как это сделано в sample-приложении CountryRoads. Ответ — через вот такой интерфейс:



Не очень удобно, но по-другому никак, документация же не будет врать, верно?


Поскольку место для контролов на карте у нас закончилось, необходимо было сделать кнопку для перевода карты в режим «таскания» в этом аналоге navigationBar’а.


let panButton = CPBarButton(…)
self.mapTemplate.leadingNavigationBarButtons = [panButton]
self.mapTemplate.trailingNavigationBarButtons = []

Но вот массивы leadingNavigationBarButtons и trailingNavigationBarButtons тоже оказались не без прикола: сколько элементов в них ни пихай, они возьмут только первые два. Тоже без ошибок в логе и ассертов.


А для активации и деактивации режима перетаскивания карты необходимо написать:


self.mapTemplate.showPanningInterface(animated: true)
self.mapTemplate.dismissPanningInterface(animated: true)

Построение и отображение маршрутов на карте


Далее я приступил к тому, чтобы наше уже существующее API переиспользовать для построения маршрутов.


Просто для демки и понимания, что и как делать, решил взять две точки и строить между ними маршрут. Точкой А было местоположение пользователя, а точкой Б — наш главный офис в Новосибирске.


Код
let choice0 = CPRouteChoice(
  summaryVariants: ["46 км"],
  additionalInformationVariants: ["с учетом пробок"],
  selectionSummaryVariants: ["1 час 7 мин"]
)
let choice1 = CPRouteChoice(
   summaryVariants: ["46 км"],
   additionalInformationVariants: ["с учетом пробок"],
   selectionSummaryVariants: [“1 час 11 мин"]
)

let startItem = MKMapItem(…)
let endItem = MKMapItem(…)
endItem.name = "Толмачёво, международный аэропорт”

let trip = CPTrip(
   origin: startItem,
   destination: endItem,
   routeChoices: [choice0, choice1]
)

let tripPreviewTextConfiguration = CPTripPreviewTextConfiguration(
   startButtonTitle: "В путь”,
   additionalRoutesButtonTitle: “Ещё”,
   overviewButtonTitle: "Назад"
)

self.mapTemplate.showTripPreviews(
  [trip],
  textConfiguration: tripPreviewTextConfiguration
)

На экране мы получили контрол с описанием маршрута:



Режим навигации


Маршруты — это хорошо, но главная фишка навигатора всё же в навигации. Чтобы она появилась, необходимо написать следующее:


func mapTemplate(
  _ mapTemplate: CPMapTemplate,
  startedTrip trip: CPTrip,
  using routeChoice: CPRouteChoice
) {
   self.navigationSession = 
       self.mapTemplate.startNavigationSession(for: trip)
}

CPNavigationSession — класс, с помощью которого можно отображать некоторые UI-элементы, необходимые только в режиме навигации.


Чтобы отобразить манёвр, необходимо:


let maneuver = CPManeuver()
maneuver.symbolSet = CPImageSet(
  lightContentImage: icon, 
  darkContentImage: darkIcon
)
maneuver.instructionVariants = ["Ул. Кутателадзе"]
maneuver.initialTravelEstimates = CPTravelEstimates(…)

self.navigationSession?.upcomingManeuvers = [maneuver]

После чего на экране магнитолы мы получим вот это:



Чтобы обновлять метраж до манёвра, необходимо:


let estimates = CPTravelEstimates(…)
self.navigationSession?.updateEstimates(estimates, for: maneuver)

It just works!


Когда основная функциональность для навигатора был готова, я решил показать эту поделку на внутренней презентации. Презентация удалась: все загорелись идеей доделать, потестировать и запустить навигатор как можно скорее.


Первым делом мы заказали реальное головное устройство с поддержкой CarPlay. И тут, как говорится, пошла жара.


PIONEER AVH-Z500BT


Provision Profiles


Из-за добавления нового capability-ключа необходимо перегенерировать профили. В обычной разработке мы не думаем об этом, ведь Xcode сделает всё сам. Но не в случае с приватным ключом.


Code Signing Error: Automatic signing is unable to resolve an issue with the "v4ios" target's entitlements. Automatic signing can't add the com.apple.developer.carplay-maps entitlement to your provisioning profile. Switch to manual signing and resolve the issue by downloading a matching provisioning profile from the developer website.

Это так же сломало нам CI, так как для локальной дистрибуции версий приложения мы используем enterprise-аккаунт, в который мы не запрашивали разрешение на разработку приложения под CarPlay. Но это уже совсем другая история


Debugging


Подключиться к CarPlay можно через Bluetooth или Lightning. Практика показывает, что второй способ гораздо популярнее. Наша магнитола в Bluetooth не умела, поэтому во время разработки пришлось пользоваться Wi-Fi дебагом. Если вы пробовали его на проектах сложнее, чем hello world, то вы знаете, какой это ад.


А для тех, кто не пробовал, рассказываю:

Я собирал приложение по проводу на телефон, а только потом, подключив телефон к CarPlay, через Wi-Fi, заливал на телефон и запускал по несколько минут.
Копирование приложения на телефон было около 3 минут, запуск приложения ещё около минуты и только потом после запуска остановка на брейкпоинтах была только секунд через 15.


И тут мне стало очень интересно, почему Apple не сделала никакой DevKit (чтобы Apple-way, it just works и вот это всё). Без него собирать тестовый стенд было не очень удобно. До сих пор раз в пару недель что-нибудь отваливается — приходится по фоткам вспоминать, что куда втыкать. Хорошо, что админ при сборке этого стенда рассказал, что и зачем.


The best framework we ever made


В конце концов, когда всё собралось на реальное устройство, стало понятно, что фиче «2ГИС под CarPlay» точно быть. Настало время делать по красоте.


Проблемы с вьюпортом


Необходимо было настроить вьюпорт карты, чтобы рисовать маршруты в области без лишних контролов, а не просто посередине. Короче говоря, чтобы это выглядело не так:



А так:



Я рассчитывал, что получу какой-нибудь layoutGuide с текущей видимой областью. Чтобы он учитывал и navigationBar, и вьюшку с маршрутом, и контролы на карте. На деле я не получил ничего. До сих пор непонятно, как настраивать вьюпорт, поэтому у нас в коде есть хардкод типа:


let routeControlsWidth = self.view.frame.width * 0.48 
let zoomControlWidth = self.view.frame.width * 0.15

Построение проезда не только между двумя точками


В первый релиз мы решили взять наш рубрикатор, сделанный через CPGridTemplate:



Избранное и Дом/Работа через CPListTemplate.



И клавиатурный поиск через CPSearchTemplate:



Код я показывать про темплейты не буду, так как он простой и про него хорошо написана документация (хоть про что-то).


Однако стоит упомянуть, какие проблемы были обнаружены при работе с ними.

CPInterfaceController может в навигацию, похожую на UIKit. т. е.


self.interfaceController.pushTemplate(listTemplate, animated: true)
self.interfaceController.presentTemplate(alertTemplate, animated: true)

Но если вы попытаетесь запушить, например CPAlertTemplate, то получите ассерт в логах, что CPAlertTemplate может быть только модально представлен.


Непонятно, почему Apple не спрятали логику транзишенов под капотом, не сделав тогда интерфейс типа:


self.interfaceController.showTemplate(listTemplate, animated: true)

Это также сломало возможность пользоваться наследниками CPTemplate, словно контроллерами в UIKit.


При попытке, например, положить в стек темплейтов ваш наследник, вы получите вот это:


Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unsupported object <YourAwesomeGridTemplate: 0x60000060dce0> <identifier: 6CAC7E3B-FE70-43FC-A8B1-8FC39334A61D, userInfo: (null)> passed to pushTemplate:animated:. Allowed classes: {(
    CPListTemplate,
    CPGridTemplate,
    CPSearchTemplate,
    CPMapTemplate
)}’

Тестирование и баги


Тестированием занимался artemenko-a-a. Один из первых багов, который он нашёл, мы до сих пор не можем починить.


Дело в том, что при отсоединении телефона от CarPlay-магнитолы спорадически нас прибивает Watchdog — без объяснении причины. Даже syslogs открывали, ничего не понятно. Так что если есть идея, как починить или понять причину, то велкам в комменты.


Следующий баг был в этом же месте, но с особенным поведением. Я писал выше, что метод didDisconnect у CPApplicationDelegate вызывается в момент отсоединения телефона от CarPlay. И в этом методе мы возвращаем карту с экрана магнитолы обратно в основное приложение. Представьте себе, сколько бы мы словили проблем, если бы этот метод не вызывался хотя бы раз из пяти.


Стало понятно, что это проблема iOS, а не конкретно нашего приложения, так как вся система считала, что она подключена к CarPlay.



Я даже зарепортил это как radar (как и все остальные баги). Меня попросили скинуть логи с таким-то профилем, но я не мог ответить поддержке в течение некоторого времени, поэтому они закрыли radar.


Раз Apple делать ничего не планировала, проблему пришлось обходить самостоятельно, так как воспроизводилась она достаточно часто.


И тут я вспомнил, что львиная доля подключений к CarPlay идёт через Lightning. Это значит, что телефон в момент подключения заряжается, а в момент отключения заряжаться перестаёт. А если так, то можно подписаться на состояние батареи и точно узнать, когда телефон перестал заряжаться и отключился от CarPlay.


Схема хиленькая, но выбора у нас не было. Мы пошли этим путём, и всё сработало!



К счастью, этот костыль из кода давно уже удалён: разработчики Apple починили всё в одном из релизов iOS.


История двух реджектов


Первый реджект был связан с метадатой. В тексте реджекта говорилось, что у нас в описании (не release notes) не сказано о том, что мы поддерживаем CarPlay. Как вы можете догадаться, ни в review guideline’ах, ни у того же Google Maps такого не было. Мы не стали спорить (потому что это обычно дольше, чем править метадату), скопировали строчку из Release Notes в Description и стали ждали нового ревью.


Второй реджект случился из-за списка городов. У 2ГИСа есть очень крутая фича — полный офлайн-режим работы. Эта фича стрельнула нам в ногу.


При подключении приложения без установленного города к CarPlay, мы не показываем карту, потому что показывать нечего. За это нас и зареджектили. Решение было простым: алерт без кнопок, в котором написано, что нужно скачать город.



То, о чём нельзя говорить


Перемещение карты жестами


Примерно в это же время вышел навигатор под CarPlay от Google Maps — и там можно было передвигать карту жестами по экрану. Приватные API, подумал я, это очевидно! Ребята из Google просто пришли из соседнего здания и сказали, что им надо. Ведь документация гласит:


Navigation apps are designed to work with a variety of car input devices, and CarPlay does not support direct user interaction in the base view (apps do not directly receive tap or drag events). 

Однако я всё-таки решил убедиться и полез гуглить, хоть это и было почти бессмысленно, ведь никаких технических статей про CarPlay Navigation Apps не было. Однако я умудрился найти что-то полезное и, ВНЕЗАПНО, на сайте Apple.


В гайдлайнах я нашел видео, которое говорит, что документация нагло врёт. На видео видно, как карту всё-таки можно перетаскивать жестами. Я понял, что ничего не понял, и единственное, что мне оставалось, — открыть CarPlay.framework и пересмотреть все .h файлы.


И о чудо! Я нахожу в CPMapTemplate’е его делегат CPMapTemplateDelegate, в котором есть 3 метода, которые как будто кричат о том, что если их реализовать, то можно будет получить управление жестами картой.


3 метода

/*Called when a pan gesture begins. May not be called when connected to some CarPlay systems.
/
optional public func mapTemplateDidBeginPanGesture(_ mapTemplate: CPMapTemplate)


/*Called when a pan gesture changes. May not be called when connected to some CarPlay systems.
/
optional public func mapTemplate(_ mapTemplate: CPMapTemplate, didUpdatePanGestureWithTranslation translation: CGPoint, velocity: CGPoint)


/*Called when a pan gesture ends. May not be called when connected to some CarPlay systems.
/
optional public func mapTemplate(_ mapTemplate: CPMapTemplate, didEndPanGestureWithVelocity velocity: CGPoint
)


Я реализовал их и запустил приложение на симуляторе — ничего не сработало. Не успев расстроиться, я понял, что симулятор может быть такого же качества, как и документация, и собрал на девайс. Всё завелось, счастью не было предела!


Забавный факт: CarPlay-магнитоле необходима четверть экрана, чтобы понять, что начался pan-жест. Хочу заметить, что UIPanGestureRecognizer’у нужно всего 10 поинтов.


Неодинаковость UI на разных магнитолах


Нам в поддержку поступило обращение: у пользователя в поиске вылезает всего один саджест, хотя могло бы быть и больше. Странно, подумал я, ведь на всех экранах помещается всего одна строка. Запросили скриншот:



И это совсем отличается от UI CPSearchTemplate, который я показывал выше. И это нужно учитывать при разработке, хоть и никак нельзя понять, сколько ячеек в табличке внизу может вместиться в экран.


Контрол ограничения скорости


Мы посмотрели на статистику и поняли, что навигатором для CarPlay пользуются и надо довести его хотя бы до уровня навигатора в основном приложении. В первую очередь решили добавить контрол ограничения скорости. Без проблем, конечно, не обошлось.


Вопрос номер один: где размещать?


Пошарив снова по .h файлам в CPWindow, я нашел любопытный layoutGuide:
var mapButtonSafeAreaLayoutGuide: UILayoutGuide


И это оказалось тем, что нужно. Наш контрол отлично туда вписался:




Вопрос номер два: это, вообще, законно?


Дело в том, что технически контрол находится на base view. А base view по документации не может содержать в себе ничего, кроме карты:


The base view is where the map is drawn. The base view must be used exclusively to draw a map, and may not be used to display other UI elements. Instead, navigation apps overlay UI elements such as the navigation bar and map buttons using the provided templates. 

Но ревьюверы пропустили нас в AppStore, а значит контролы, которые касаются навигации, встраивать всё-таки можно.


Голосовой поиск




По-хорошему, эту фичу нужно было сделать в первую очередь, но у нас накопилось несколько задач из техдолга, которые мешали реализовать голосовой поиск для CarPlay. И эта задача оказалась не такой простой, как казалось.


Проблема первая: анимации. Дело в том, что в CPVoiceControlTemplate нет возможности сделать стандартные анимации. Анимацию для распознавания речи и поиска пришлось собирать покадрово из картинок и указывать, сколько они идут по времени.


for i in 1...12 {
   if let image = UIImage(named: "carplay_searching_\(i)") {
      images.append(image)
   }
}

let image = UIImage.animatedImage(with: images, duration: 0.96)

Выглядит, как можете догадаться, не очень, но и размер приложения раздувать не хочется.


Проблема вторая: доступы. Алерты на доступ к микрофону и распознаванию речи появляются на дисплее телефона. Пришлось писать на дисплее магнитолы, что пользователю необходимо взять телефон в руки, дать разрешение и только потом пользоваться навигатором на магнитоле. Очень удобно!


Праворульные автомобили.


Нам прислали скриншот, в котором UI всего приложения был перевёрнут!



И, естественно, вьюпорт карты оставался таким, как мы его захардкодили, ведь никто не ожидал, что есть отдельная настройка для праворульных автомобилей. Как «правильно» это обойти, я не нашёл, но заметил, что, поскольку наш контрол ограничения скорости лежит в layoutGuide’е для контролов карты, он переместился в левую сторону.


Ультрафикс не заставил себя ждать. Сделали грубо, но это работает.


let isLeftWheelCar = self.speedControlViewController.view.frame.origin.x > self.view.frame.size.width / 2.0

Очень надеюсь, что есть правильное решение, и я просто не дочитал.


На этом у меня всё. Если вдруг соберётесь делать свой навигатор под CarPlay, учтите, что документация и фреймворк несовершенны. Платформа абсолютно новая, никто ничего не знает, а Apple делиться знаниями не торопятся.

Комментарии (69)


  1. shaggyone
    21.05.2019 09:04
    +1

    Нескромный вопрос, а на android auto планируете?


    1. docomo
      21.05.2019 09:12
      +2

      Конечно. Сейчас с делами раскидаемся, заберём у iOS-команды «потеху» и начнём потихоньку.


      1. alexpp
        21.05.2019 09:50

        Купите вторую потеху, не отнимайте у первой команды — пусть пилят под ios. А вот под андроид авто — ввиду отсутствия я-карт, вы бы стали первопроходцем из России.


        1. docomo
          21.05.2019 10:52

          Не в устройстве дело, конечно же. Просто пока есть более важные дела — сейчас существенно переписываем внутренности приложения. Как только закончим (к осени), так сразу время появится на всё остальное :)


          1. rmnuts
            21.05.2019 14:31

            Очень бы хотелось увидеть 2GIS на Android Auto.


          1. V13-TH
            23.05.2019 07:52

            Ну хотябы какие-то сроки у этого плана есть?


            1. docomo
              23.05.2019 07:54

              Пока дальше Q2 2019 не планировались точнее, а в Q2 этой задачи нет. Поэтому точнее не скажу. Одно ясно — рынок большой, надо делать. Поэтому задача в большом приоритете.


        1. Hashinger
          21.05.2019 12:12

          Если Я-карты отсутствует в PlayMarket можно просто переместить apk и поставить.


          1. alexpp
            21.05.2019 14:37

            Речь не про маркет. Я-карты не работают в режиме Android Auto.


            1. TRIMER
              22.05.2019 08:57

              Учитывая позицию яндекса по CarPlay (вроде бы делать не хотят, кивают в сторону яндекс.авто), то это вообще вопрос ожидать ли их на Android Auto.


    1. severgun
      21.05.2019 15:37

      Google не открывал доступ к Android Auto.
      Очевидно никто не будет заниматься нелегальным реверсом.


  1. motpac
    21.05.2019 09:14
    +1

    Уж если не медаль, то грамоту и вымпел передовика производства вам точно нужно вручить! Это не ирония. Люблю ваше приложение за доскональную проработку местности. Ещё бы голосов побольше для сопровождения и прощай яндекс.навигатор.


    1. autoclosure Автор
      21.05.2019 09:38

      Спасибо!


    1. igorp1024
      24.05.2019 08:49

      А междугородние трассы и знаки + камеры на них? Нет, не прощай ни разу. Если в городе — возможно.


  1. kpetrov54
    21.05.2019 09:26

    deleted


  1. Ilyasyakubov
    21.05.2019 09:41

    Можно вопрос не по теме? Когда наступят славные времена, когда приложение под iOS начнет запоминать свое состояние на случай выгрузки из оперативной памяти? Больше всего сброс состояния досаждает в процессе движения по маршруту.


    1. autoclosure Автор
      21.05.2019 09:48
      +1

      Мы умеем восстанавливать состояние после выгрузки из памяти в поиске проезда и навигаторе. А вообще мы сейчас ведем работы по уменьшению потребления памяти. Выгрузок из памяти всего приложения должно стать намного меньше.


      1. Ilyasyakubov
        21.05.2019 15:50

        Но зачем мне врать? После выгрузки из памяти по инициативе системы, маршрут сбрасывается :(


        1. autoclosure Автор
          21.05.2019 16:00

          Звучит как баг :(
          Будет очень здорово, если вы скинете нам логи через наше приложение: боковая панель -> Сообщить об ошибке -> Сообщить об ошибке. И там опишете вашу проблему.


          1. Ilyasyakubov
            21.05.2019 16:26

            Я так и поступил. Несколько дней назад. Ответа никакого. Хотя раньше отвечали оперативно.


            1. autoclosure Автор
              22.05.2019 08:16

              Отписал в саппорт, мы получили ваши логи и вам уже должны были ответить. Извиняюсь за долгий ответ.


              1. Ilyasyakubov
                22.05.2019 11:04
                +1

                Спасибо! Поймите, я не хейтер, я наоборот очень люблю 2Гис и много лет им пользуюсь. Просто очень обидно за нас с вами, что такая досадная вещь до сих пор не исправлена.


  1. Loki3000
    21.05.2019 09:42

    Мы не работаем в background’е

    Видимо, с этим связаны глюки на андроиде при работе в режиме разделения экрана? Похоже что данное поведение пора менять.


    1. docomo
      21.05.2019 09:48

      Есть такие планы у android-команды. Скоро.


  1. Aquahawk
    21.05.2019 09:43
    -1

    Звиздец. Как же меня бомбит. Неоднократно пытался юзать новешие техи от крупных вендоров и там почти всегда такое говнище. Почему??? Почему они не могут нанять себе программистов и написать хоть какой-то рабочий софт на своих апи?


    1. zanac
      21.05.2019 10:07

      Фигак-фигак и фтопку впродакшен.


    1. autoclosure Автор
      21.05.2019 10:12
      +1

      CarPlay, судя даже по приватному capability-ключу, до сих пор в неофициальной бете и поэтому много сил Apple на него не тратит.


      1. recker
        22.05.2019 07:46

        Классическая схема Apple. Обычно обновы таких фреймворков бывают раз в год, перед презентациями. Сам постоянно мучаюсь с CoreML.


    1. khim
      21.05.2019 16:20

      Потому что девять женщин не могут родить ребёнка за месяц.

      Как только что-то начинает работать — это демонстрируют на выставках.

      Когда родное приложение как-то завели (с помощью лома и какой-то матери) — надо релизить…

      Конкуренция же!

      А вы чего ждали?


    1. canister_exister
      22.05.2019 08:00

      в больших компаниях главное количество, а не качество, никому не важно как оно написано, главное что работает. Даже если вы скажете, что сможете это переписать и оно начнет работать в 2 раза быстрее, никому не интересно.


      1. khim
        22.05.2019 20:05

        На самом деле интересно и это делают… но это уже будет «новеший тех». Никто не будет останавливать релиз и всё переделывать если оно ну хоть как-то работает.

        А потом — да, перепишут, вылижут и исправят… Но это потом, после релиза.


  1. apro
    21.05.2019 10:47

    А вы разве не используете Qt/QML на мобильных устройствах?


    1. docomo
      21.05.2019 10:55

      Только в android-приложении.


      1. apro
        21.05.2019 13:01

        Только в android-приложении

        Исторически так сложилось или из-за проблем со Qt + Android,
        решили под iOS писать на Swift?


        1. docomo
          21.05.2019 17:50

          Тут autoclosure точнее подкажет насчёт iOS.


          1. autoclosure Автор
            21.05.2019 18:53

            2ГИС версии 4 под iOS начинали писать на objc, потом стали писать новую функциональность на Swift примерно 2.5 года назад.


  1. SergiusGee
    21.05.2019 13:01

    Во-первых, большое спасибо за статью! Мне как iOS разработчику было очень интересно :)
    Как пользователь, считаю вашу навигацию лучшей из CarPlay вариантов, но всё-таки не очень понятно, как использовать перемещение карты по кнопкам — например это реализовано в Google Maps и описано у вас в статье. Однако в приложении у вас просто нет такой кнопки :(
    К сожалению, не все системы для CarPlay сенсорные


    1. autoclosure Автор
      21.05.2019 13:09

      Спасибо!

      Кнопка такая есть и выделена красным кружком:
      image

      И по тапу на нее карта перейдет в режим перемещения:
      image


      1. SergiusGee
        21.05.2019 13:10

        Отлично, спасибо большое!


      1. mikelavr
        21.05.2019 15:03

        Но ведь чтобы тапнуть по кнопке, экран должен быть сенсорным? Тогда теряется смысл перехода на аппаратные кнопки.


        1. autoclosure Автор
          21.05.2019 15:33

          Не обязательно. CarPlay под капотом работает с разными средствами ввода. Например, могут быть аппаратные кнопки-стрелочки или шайба. Тогда каждый интерактивный элемент будет подсвечиваться когда он в фокусе (как на AppleTV). И нажатие этого на этот UI-элемент тоже будет сделано через какой-то аппаратный контрол.




  1. GloooM
    21.05.2019 18:13

    Листал статью, думал ну скрины типа с версии в процессе разработки, но судя по всему и в продакшене «прибытие» некрасиво прилипло к краю :(


    1. autoclosure Автор
      21.05.2019 18:49

      Строка «прибытие» системная и никак не кастомизируется :(
      Этот баг был отправлен в Apple, но никакого ответа до сих пор не получено.


  1. ololorin
    21.05.2019 18:49

    Спасибо за интересную статью. :)
    Пользуюсь вашим навигатором вместе с карплеем, очень нравится, определенно лучше альтернатив для России. Если принимаете пожелания, то хотелось бы где-нибудь отображать улицу, по которой движешься в данный момент (возможно снизу). И еще приятно было бы иметь подсказки с движением по полосам, как в гугл картах, например (это, возможно, сложнее, но если вдруг).


    1. autoclosure Автор
      21.05.2019 18:50

      Спасибо!
      Подсказки с движением по полосам точно есть в наших планах.


  1. SergeyRembo
    21.05.2019 19:01
    +2

    Когда я пару лет назад хотел воспользоваться Вашим навигатором, мой город ещё был не отрисован. Сейчас зашёл и увидел что все дома есть, и навигация доступна. CarPlay, о чём ещё мечтать! Обрадовался и проложил маршрут до пары мест. Провёл через односторонку под кирпич, не надо так! Это хорошо я свой город знаю, но по сути мне и нужен навигатор, чтобы в других городах ориентироваться. Подожду пока карты дотянут до яндековских и буду пользоваться. Яндекс всё равно ещё долго до CarPlay не доберётся.

    А так, спасибо за работу! Развивайтесь!


    1. autoclosure Автор
      22.05.2019 07:59

      Спасибо за фидбек!
      Если вдруг снова произойдет подобная ситуация, то было бы просто замечательно, если бы вы отправили нам сообщение об ошибке из карточки маршрута.



      1. SergeyRembo
        22.05.2019 10:39

        Не нашёл в веб версии такой функционал. Карточка маршрута есть, а кнопки нет


        1. autoclosure Автор
          22.05.2019 12:04

          Такая функциональность, к сожалению, есть только в мобильном приложении :(


  1. vsantonov
    22.05.2019 00:01

    Примерно в это же время вышел навигатор под CarPlay от Google Maps — и там можно было передвигать карту жестами по экрану.

    У меня до сих пор в Google Maps нет этой функции, что жутко раздражает. Так же отсутствие экранной клавиатуры. Может быть такое что магниторла передает некий параметр, сенсорная она или нет и уже на основе этого параметра интерфейс меняется с убогих стрелочек на сенсор? У меня просто имеется еще и колесо, приходится управляться им и голосом.


    1. autoclosure Автор
      22.05.2019 07:51

      Дисплей головного устройства сенсорный?
      А вот на экранную клавиатуру действительно есть некий параметр.


      1. vsantonov
        22.05.2019 08:00

        Дисплей сенсорный, но как доходит до зума карты пальцами, нифига. Тестировал на waze и google maps, что суть одно и то же.


        1. autoclosure Автор
          22.05.2019 08:04

          Сделать именно зум карты из-за ограничений CarPlay.framework действительно нельзя. Можно сейчас сделать только перемещение карты. Это тоже не работает?


          Если так, то тут даже не понятно на чей стороне косяк. На стороне Apple или же производителя магнитолы.


  1. vsantonov
    22.05.2019 00:03

    И еще один вопрос, про звук в беспроводном CarPlay, он передается в основном Wi-Fi канале или отдельно по Bluetooth?


    1. Zuy
      22.05.2019 06:11

      Скорее всего по WiFi идёт. Дело в том, что когда телефон подключается шнурком, то весь трафик внутри идёт по IPv6 over USB. В случае WiFi тот же трафик просто пускается в другой сетовой интерфейс.


    1. autoclosure Автор
      22.05.2019 07:53

      Это все под капотом CarPlay.framework, но судя по тому, что телефон к CarPlay-магнитоле подключается именно по Bluetooth, рискну предположить, что звук идет тоже по Bluetooth.


  1. vsantonov
    22.05.2019 08:01

    Только первоначальное соединение идет по bluetooth, дальше весь трафик идет через wifi. Сверху уже хорошо ответили.


  1. jetfreeman
    22.05.2019 09:36

    Привет! Спасибо за статью. Пара вопросов.

    1. Не планируется ли добавить возможность звонить в организации через интерфейс CarPlay? Поясню кейсом: телефон подключен к CarPlay, я подъезжаю к автомойке и хочу в нее позвонить, чтоб узнать, есть ли свободные боксы. Номер, соответственно, хочу посмотреть в 2ГИС. Но сейчас я не могу это сделать, не отключив телефон от магнитолы, поскольку на телефоне UI 2ГИС отсутствует.

    2. И можно ли скрыть клавиатуру на этом экране?

    image

    Скроллить по одной строке охрененно неудобно.


    1. autoclosure Автор
      22.05.2019 09:46
      +1

      1. К сожалению этого сделать сейчас невозможно из-за ограничений CarPlay.framework, однако задача разблокировки UI в основном приложении у нас топ 1 по приоритету.
      2. Тоже ограничение CarPlay.framework. Это, как я и писал выше, абсолютно никак не кастомизирующийся CPSearchTemplate.


      1. jetfreeman
        22.05.2019 09:53

        Ок, спасибо за ответ!


      1. xycainoff
        23.05.2019 01:52

        Спасибо за классную статью!
        Под рукой нет скриншота, но я почти на 100% уверен что в ГуглМапсовом КарПлее можно скрыть клавиатуру и видеть больше одного варианта результата поиска (но возможно это относится только к результату голосового поиска, не уверен). Попробуйте пожалуйста! 2ГИС ведь имхо этим и сильнее конкурентов — справочником организаций!


        1. xycainoff
          23.05.2019 03:05

          1. Сходил в авто и снял скрин. ГуглМапс при поиске с клавиатуры после нажатия кнопки «Search» перекидывает на следующий экран с результатом поиска и без клавиатуры:

          Скрин 1
          image


          1. xycainoff
            23.05.2019 03:07

            Последний скрин не прикрепился:

            Скрин
            image


          1. autoclosure Автор
            23.05.2019 08:04

            Спасибо за фидбек!


            1. А это хорошая идея, обязательно отправлю ее нашим продактам!
            2. Это я писал про текстовый поиск, это у вас так в голосовом в 2ГИС?
            3. Тут у нас есть техническая трудность. У нас ночная тема есть только в навигаторе, а навигатор пока что без маршрута мы запустить не можем. Сделать лучше есть в наших планах.
            4. Сейчас задача разблокировки UI в основном приложении у нас топ 1 по приоритету. Сделаем обязательно!


  1. hreqw41
    22.05.2019 09:47
    +1

    когда приложение вышло на carplay, меня как и у многих был легкий приступ эйфории и ожидания чего то невероятного. после активации carplay, я не использую встроенный навигатор bmw. мне нравится как работает гугл, пользуюсь им достаточно часто. яндекс, как я понимаю, намеренно выдерживает позицию, добиваясь признания автопроизводителями своей платформы. и тут вы выходите, круто!
    разочарование пришло быстро: при активации carplay экран телефона блокируется, поиск возможен только на экране авто, это крайне не удобно, т.к. часто ищешь не адрес а организацию и голосовой поиск здесь неудобен. кроме того не понимаю как позвонить по телефону организации с экрана авто, отсутствует другая справочная информация. вообщем если мне нужен 2гис в авто, приходится отключать carplay, в этот момент прерывается музыка, появляется раздражение, неприязнь. получается недонавигатор и обрезок 2гис:( недоволен я.
    но за статью огромное спасибо! очень интересно!


    1. autoclosure Автор
      22.05.2019 09:51

      Спасибо за фидбек!


      Задача разблокировки UI в основном приложении у нас топ 1 по приоритету. Сделаем как только появится время!


      Позвонить с экрана CarPlay из приложения 2ГИС, к сожалению, нельзя из-за технических ограничений CarPlay.framework.


  1. Romanchuk
    22.05.2019 09:54

    Когда-то давно хотел сделать интеграцию 2gis со своими часами, а именно получение координат точки назначения из 2gis andoid/ios приложения. Но подобной возможности я в своё время не нашёл. Есть ли для «простых смертных» возможность каким-то образом передать координаты строения из 2gis в другое приложение?


    1. autoclosure Автор
      22.05.2019 09:57

      Если я правильно вас понял, то такой возможности сейчас нет. Есть возможность открывать наше приложение из других приложений.
      Однако у нас есть приложение на Apple Watch, которое умеет показывать пешеходные маршруты, это очень удобно!


      1. Romanchuk
        22.05.2019 14:48

        Да, правильно. Хотелось бы аналогичное для Garmin =)