Найти в Дзене
mamaich

Отправка команд на устройства Яндекс, продолжение

В прошлой статье я написал, как отправлять protobuf сообщения на Яндекс.Станцию Max. Аналогичным образом можно отправлять команды и на другие устройства (я проверял на своих Яндекс ТВ Станции и на Яндекс.Модуле). В прошлый раз я описал команду Глагола "externalCommandBypass", которая позволяет отправлять определенные сообщения в aliced. Но есть более интересная команда - "clusterMessage". С помощью этой команды можно отправлять сообщения QuasarMessage любому сервису (не только aliced). Увы, но подсунуть свой system_config таким образом нельзя - так как отправитель будет не syncd, то адресаты подобные сообщения просто не примут. Формат "clusterMessage" следующий: {
"command": "clusterMessage",
"from_device_id" : "случайный GUID",
"service_name"" : "сервис, в который отправляем QuasarMessage",
"quasar_message_base64"" : "base64 закодированный protobuf c QuasarMessage"
} Список сервисов можно посмотреть в quasar.cfg (но на самом деле их намного больше). Описание сообщения QuasarMessa

В прошлой статье я написал, как отправлять protobuf сообщения на Яндекс.Станцию Max. Аналогичным образом можно отправлять команды и на другие устройства (я проверял на своих Яндекс ТВ Станции и на Яндекс.Модуле).

В прошлый раз я описал команду Глагола "externalCommandBypass", которая позволяет отправлять определенные сообщения в aliced. Но есть более интересная команда - "clusterMessage". С помощью этой команды можно отправлять сообщения QuasarMessage любому сервису (не только aliced). Увы, но подсунуть свой system_config таким образом нельзя - так как отправитель будет не syncd, то адресаты подобные сообщения просто не примут.

Формат "clusterMessage" следующий:

{
"command": "clusterMessage",
"from_device_id" : "случайный GUID",
"service_name"" : "сервис, в который отправляем QuasarMessage",
"quasar_message_base64"" : "base64 закодированный protobuf c QuasarMessage"
}

Список сервисов можно посмотреть в quasar.cfg (но на самом деле их намного больше). Описание сообщения QuasarMessage можно найти в сдампленном, по приведенной в прошлой статье инструкции, файле yandex_io\protos\quasar_proto.proto. Всего в QuasarMessage входит несколько сотен видов сообщений.

QuasarMessage
QuasarMessage

Не знаю, обязательное ли поле request_id, но я его заполняю всегда случайным GUID (да, хоть у меня во всех скриптах всегда указывается один и тот же GUID - но он изначально был сгенерирован случайным образом :)

Обычно QuasarMessage содержит только одно optional сообщение из списка - но, возможно, если указать несколько, то можно будет получить интересные баги.

Из потенциально полезных для использования сообщений, я остановился на Directive. Описание можно найти в файле yandex_io\sdk\directive_sequencer\protos\directive.proto.

Directive
Directive

Я не разбирался для чего нужны все приведенные на скриншоте поля. Для вызова команд достаточно заполнения только трёх:

"directive": {
"is_route_locally": true,
"name": "имя команды",
"json_payload": "{ параметры для команды в формате json }"
}

Вот таким образом можно попросить устройство открыть указанный URL в установленном приложении:

1. Создаем файл, описывающий QuasarMessage c Directive внутри:

https://pastebin.com/psJ6JFjr
https://pastebin.com/psJ6JFjr

2. Создаем питон скрипт "_make_obj_quasar.py", который преобразует данный JSON в двоичный protobuf в формате base64:

https://pastebin.com/vx1nkVAQ
https://pastebin.com/vx1nkVAQ

3. Превращаем QuasarMessage из JSON в бинарник:

python _make_obj_quasar.py файл_с_json
-5

4. И скармливаем в curl:

curl --location -g "http://localhost:58080" ^
-H "Content-Type: application/json" ^
--data "{""command"": ""clusterMessage"", ""from_device_id"" : ""b68affc3-2974-4e9d-9f71-185dd4fa6c58"", ""service_name"" : ""aliced"", ""quasar_message_base64"" : ""CiRjMTEzMzlkOC04MDY4LTQxMzQtOWNiNC00YjllZDA4MDRjOWOaDVEKCG9wZW5fdXJpMkN7InVyaSI6Imh0dHBzOi8vd3d3LnlvdXR1YmUuY29tL2NoYW5uZWwvVUNZMEM2QTN0M1JUVU4zQkI2NXJXQWdRIiB9YAE="" }"

Откроется приложение youtube.

Таким образом можно открывать не только веб сайты. Например, можно открыть окно встроенного в устройство маркета по ссылке "home-app://market_item?package=имя.пакета" (увы, приложения, которые отсутствуют в маркете для вашего устройства так установить не получится).

откроет окно "яндекс игры" в маркете
откроет окно "яндекс игры" в маркете

Кроме директивы "open_uri" есть ряд других (желающие могут найти их самостоятельно в ServicesIosdk.apk). Большинство из них малополезны.

Опишу "send_android_app_intent" - как видно из названия, оно позволяет запустить требуемый нам Intent (он должен быть экспортируемым). Для примера запущу окно VLC Player.

json_payload для "send_android_app_intent" имеет следующие параметры:

{
"action": "android.intent.action.MAIN",
"start_type": "StartActivity",
"category": "android.intent.category.DEFAULT",
"flags": {
"FLAG_ACTIVITY_NEW_TASK": true
},
"component": {
"pkg": "org.videolan.vlc",
"cls": "org.videolan.vlc.StartActivity"
}
}

Названия параметров говорят сами за себя. Набор доступных флагов можно увидеть в ServicesIosdk.apk

Полностью QuasarMessage выглядит так (кавычки в json_payload должны быть экранированы):

{
"request_id" : "c11339d8-8068-4134-9cb4-4b9ed0804c9c",
"directive": {
"is_route_locally": true,
"name": "send_android_app_intent",
"json_payload": "{\"action\":\"android.intent.action.MAIN\",\"start_type\":\"StartActivity\",\"category\":\"android.intent.category.DEFAULT\",\"flags\":{\"FLAG_ACTIVITY_NEW_TASK\":true },\"component\":{\"pkg\":\"org.videolan.vlc\",\"cls\":\"org.videolan.vlc.StartActivity\"} }"
}
}

Далее его также передаем скрипту, получаем base64 строку, которую скармливаем в curl.

Если json_payload собран некорректно (например, ошибка в intent), то на стороне устройства будет брошено исключение, которое разорвет соединение клиента с Глаголом. Для восстановления потребуется перезапустить dd-alicization.exe.

Ошибку можно увидеть в "adb logcat" на устройствах с включенным adb.