Как в браузере сделать
Некоторые сайты по своим возможностям не уступают полноценным компьютерным программам. Добавьте любимые сервисы на боковую панель, чтобы использовать их как веб-приложения — открывать одним нажатием и работать в отдельном окне, а не искать нужную вкладку. Например, можно проверить письма в Яндекс.Почте или организовать встречу в Телемосте, не открывая основное окно Браузера со множеством вкладок.
Для популярных мессенджеров, социальных сетей и онлайн-игр тоже созданы веб-приложения.
Добавить в качестве веб-приложений можно сайты, использующие технологию Progressive Web Application, и некоторые популярные ресурсы, которые мы поддерживаем собственными силами.
Примечание. Не все сайты в MacOS адаптированы под веб-приложения, но каталог регулярно пополняется.Установить
В разделе Приложения Яндекса , Мессенджеры , Социальные сети или Производительность нажмите правой кнопкой мыши нужное приложение. Примечание. Если вы хотите скрыть кнопку Установить приложение в Умной строке, нажмите → Настройки → Интерфейс и отключите опцию Показывать кнопку установки приложения . Нажмите на боковой панели → Добавить сайт как приложение . Начните вводить адрес сайта и выберите его в открывшемся меню.Не все сайты работают в виде приложений корректно. Если вы столкнулись с этой проблемой или не можете добавить сайт — напишите нам в службу поддержки.
Быстрый доступ
Есть несколько способов быстро открыть веб-приложение:
Нажмите на панели значок приложения или значок .
Примечание. Чтобы скрыть приложение из боковой панели, нажмите на нее правой кнопкой мыши и снимите отметку с приложения.Приложение можно будет запускать через ярлык на рабочем столе, через меню «Пуск» или из панели задач компьютера. Для этого:
Нажмите правой кнопкой значок веб-приложения на панели задач и выберите Закрепить на панели задач .Приложение будет запускаться каждый раз при включении компьютера. Для этого:
Нажмите правой кнопкой мыши значок веб-приложения на боковой панели.Окна веб-приложений
Примечание. В окне веб-приложения доступны некоторые функции браузера. Например, здесь можно открывать ссылки в отдельных вкладках, запускать расширения, использовать режим чтения и другие инструменты. В Windows можно переключаться между окнами с помощью клавиш Alt + Tab .Окно веб-приложений можно использовать в трех режимах. Чтобы выбрать режим:
В этом режиме вы можете закрепить сайт на панели задач Windows и работать как с отдельной программой.
Приложение открывается в отдельном окне. Чтобы оно всегда отображалось поверх других окон и программ, нажмите → Показывать поверх других окон .
Размер окна можно изменить перетаскиванием границ. Также можно перемещать окно, зажав левой кнопкой мыши верхнюю панель приложения.
Чтобы закрыть окно, в правом верхнем углу нажмите .
Режим удобен, когда вам нужно быстро получить информацию из приложения и сразу закрыть его. Например, для работы с онлайн-словарем.
Приложение открывается в небольшом окне поверх основного окна браузера. Размеры и положение этого окна не меняются.
Чтобы закрыть окно, нажмите левой кнопкой мыши в любом месте за его пределами.
Во всплывающем окне иногда удобнее работать с мобильной версией сайта. Чтобы ее открыть, нажмите → Открыть мобильную версию .
В этом режиме, работая с основным окном, вы можете держать на виду еще один сервис (чаты, почта, онлайн-трансляция).
Окно браузера разделяется на две половины по вертикали, приложение открывается в левой половине меньшего размера. Чтобы увеличить размер окна приложения, перетаскивайте границу справа.
Чтобы закрыть окно, в правом верхнем углу нажмите или нажмите значок приложения на боковой панели.
В закрепленном окне иногда удобнее работать с мобильной версией сайта. Чтобы ее открыть, нажмите → Открыть мобильную версию .
Меню веб-приложений
Чтобы открыть меню, нажмите . В меню доступны опции:
Показывать поверх других окон — окно приложения будет показываться поверх окон всех программ, пока вы не отключите опцию или не закроете приложение. Доступно только в режиме Отдельное окно. На стартовую страницу — перейти на стартовую страницу приложения. Может пригодиться, если на сайте приложения нет кнопки Домой . Скопировать адрес — скопировать адрес открытой страницы сайта приложения. Перезагрузить приложение — обновить страницу сайта приложения. Открыть в браузере — окно приложения будет закрыто, а приложение откроется в новой вкладке браузера. Открыть мобильную версию — открыть мобильную версию приложения. Некоторые сайты в закрепленном или всплывающем окне будут выглядеть лучше в мобильной версии. Удалить приложение — удалить приложение с компьютера.Горячие клавиши
Ctrl + Shift + Tab
Ctrl + Shift + Tab
">,"extra_meta":[>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>],"title":"Веб-приложения в браузере. Справка","canonical":"https://browser.yandex.ru/help/personalization/web-app.html","productName":"Яндекс.Браузер","extra_js":[[],[,"mods":<>,"__func134":true,"tag":"script","bem":false,"attrs":,"__func61":true>],[,"mods":<>,"__func134":true,"tag":"script","bem":false,"attrs":,"__func61":true>]],"extra_css":[[],[,"mods":<>,"__func63":true,"__func62":true,"bem":false,"tag":"link","attrs":>],[,"mods":<>,"__func63":true,"__func62":true,"bem":false,"tag":"link","attrs":>]],"csp":<"script-src":[]>,"documentPath":"/help/personalization/web-app.html","isBreadcrumbsEnabled":true,"lang":"ru","params":<>>>>'>"tag":"meta","attrs":Некоторые сайты по своим возможностям не уступают полноценным компьютерным программам. Добавьте любимые сервисы на боковую панель, чтобы использовать их как веб-приложения — открывать одним нажатием и работать в отдельном окне, а не искать нужную вкладку. Например, можно проверить письма в Яндекс.Почте или организовать встречу в Телемосте, не открывая основное окно Браузера со множеством вкладок.
Для популярных мессенджеров, социальных сетей и онлайн-игр тоже созданы веб-приложения.
Добавить в качестве веб-приложений можно сайты, использующие технологию Progressive Web Application, и некоторые популярные ресурсы, которые мы поддерживаем собственными силами.
Примечание. Не все сайты в MacOS адаптированы под веб-приложения, но каталог регулярно пополняется.Установить
Не все сайты работают в виде приложений корректно. Если вы столкнулись с этой проблемой или не можете добавить сайт — напишите нам в службу поддержки.
Быстрый доступ
Есть несколько способов быстро открыть веб-приложение:
Нажмите на панели значок приложения или значок .
Примечание. Чтобы скрыть приложение из боковой панели, нажмите на нее правой кнопкой мыши и снимите отметку с приложения.Приложение можно будет запускать через ярлык на рабочем столе, через меню «Пуск» или из панели задач компьютера. Для этого:
Нажмите правой кнопкой значок веб-приложения на панели задач и выберите Закрепить на панели задач .Приложение будет запускаться каждый раз при включении компьютера. Для этого:
Нажмите правой кнопкой мыши значок веб-приложения на боковой панели.Окна веб-приложений
Примечание. В окне веб-приложения доступны некоторые функции браузера. Например, здесь можно открывать ссылки в отдельных вкладках, запускать расширения, использовать режим чтения и другие инструменты. В Windows можно переключаться между окнами с помощью клавиш Alt + Tab .Окно веб-приложений можно использовать в трех режимах. Чтобы выбрать режим:
В этом режиме вы можете закрепить сайт на панели задач Windows и работать как с отдельной программой.
Приложение открывается в отдельном окне. Чтобы оно всегда отображалось поверх других окон и программ, нажмите → Показывать поверх других окон .
Размер окна можно изменить перетаскиванием границ. Также можно перемещать окно, зажав левой кнопкой мыши верхнюю панель приложения.
Чтобы закрыть окно, в правом верхнем углу нажмите .
Режим удобен, когда вам нужно быстро получить информацию из приложения и сразу закрыть его. Например, для работы с онлайн-словарем.
Приложение открывается в небольшом окне поверх основного окна браузера. Размеры и положение этого окна не меняются.
Чтобы закрыть окно, нажмите левой кнопкой мыши в любом месте за его пределами.
Во всплывающем окне иногда удобнее работать с мобильной версией сайта. Чтобы ее открыть, нажмите → Открыть мобильную версию .
В этом режиме, работая с основным окном, вы можете держать на виду еще один сервис (чаты, почта, онлайн-трансляция).
Окно браузера разделяется на две половины по вертикали, приложение открывается в левой половине меньшего размера. Чтобы увеличить размер окна приложения, перетаскивайте границу справа.
Чтобы закрыть окно, в правом верхнем углу нажмите или нажмите значок приложения на боковой панели.
В закрепленном окне иногда удобнее работать с мобильной версией сайта. Чтобы ее открыть, нажмите → Открыть мобильную версию .
Меню веб-приложений
Чтобы открыть меню, нажмите . В меню доступны опции:
Чтобы быстро перейти к нужной настройке, введите ее название в поле поиска в верхнем левом углу страницы.
Стартовая страница браузера
Вместо стартовой (домашней) страницы Яндекс.Браузер при запуске отображает либо Табло с наиболее посещаемыми страницами, либо вкладки, открытые в прошлый раз. По умолчанию открываются вкладки.
В блоке Вкладки отключите опцию При запуске браузера открывать ранее открытые вкладки . Открывать вместе с ранее открытыми вкладками новую Нажмите → Настройки → Интерфейс и включите опцию Открывать новую вкладку вместе с восстановленными .Как изменить вид контекстного меню?
Если в контекстном меню для вас слишком много команд:
В блоке Контекстное меню включите опцию Показывать компактное меню .После этого часть команд переместится в раздел Дополнительно .
Когда вы выделяете слова или фразы, над ними автоматически всплывает панель с командами Найти в Яндексе и Копировать . Если вам она мешает:
В блоке Контекстное меню отключите опцию При выделении текста показывать кнопки «Найти» и «Копировать» .Что происходит при сбросе настроек браузера?
В результате сброса настроек браузера будут восстановлены исходные настройки:
Чтобы сбросить настройки браузера:
Прокрутите страницу вниз и нажмите Сбросить все настройки .Как закрепить браузер на панели задач?
Из меню Пуск или с рабочего стола
Нажмите правой кнопкой мыши ярлык Яндекс.Браузера (на рабочем столе или в меню Пуск ).Если вы хотите удалить ярлык браузера с панели задач, выберите пункт Открепить от панели задач .
Из панели задач
Нажмите правой кнопкой мыши значок браузера на панели задач.Если вы хотите удалить ярлык браузера с панели задач, выберите пункт Открепить от панели задач .
Как закрепить браузер на начальном экране в меню Пуск?
Отменить действие можно с помощью пункта Открепить от начального экрана .
Как открыть браузеру доступ к данным приложений в macOS
В операционной системе macOS 10.14 Mojave доступ к данным приложений ограничивается автоматически. Чтобы Яндекс.Браузер мог получить доступ к данным других приложений (например, других браузеров):
В верхнем левом углу нажмите → Системные настройки В блоке Универсальный доступ установите флажок возле строки Яндекс.Браузер .Зачем нужен фоновый режим?
В фоновом режиме часть функций браузера продолжает работать после закрытия и запускается автоматически вместе с включением компьютера. Значок браузера виден в области уведомлений Windows, даже если он закрыт.
Преимущества работы браузера в фоновом режиме:
при запуске браузер открывается быстрее (важно, когда открыто много вкладок); работают фоновые расширения (например, прокси-расширения). Примечание. При работе в фоновом режиме браузер не отслеживает действия пользователя. Но немного тратит ресурсы компьютера.Чтобы отключить работу браузера в фоновом режиме:
В блоке Автозапуск и фоновый режим отключите опцию Разрешить работу в фоне .Как убрать кнопку Яндекс
Кнопка находится в Умной строке слева. Чтобы убрать ее:
В правом верхнем углу нажмите → Настройки → Интерфейс . ","lang":>,"extra_meta":[>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>,>],"title":"Частые вопросы о настройках браузера - Яндекс.Браузер. Справка","canonical":"https://browser.yandex.ru/help/faq/faq-settings.html","productName":"Яндекс.Браузер","extra_js":[[,"mods":,"__func137":true,"tag":"script","bem":false,"attrs":,"__func67":true>],[,"mods":,"__func137":true,"tag":"script","bem":false,"attrs":,"__func67":true>],[,"mods":,"__func137":true,"tag":"script","bem":false,"attrs":,"__func67":true>]],"extra_css":[[],[,"mods":,"__func69":true,"__func68":true,"bem":false,"tag":"link","attrs":>],[,"mods":,"__func69":true,"__func68":true,"bem":false,"tag":"link","attrs":>]],"csp":<"script-src":[]>,"lang":"ru">>>'>"current":"ru","available":["en","ru"]>Где найти настройки?
Нажмите → Настройки .
Чтобы быстро перейти к нужной настройке, введите ее название в поле поиска в верхнем левом углу страницы.
Стартовая страница браузера
Вместо стартовой (домашней) страницы Яндекс.Браузер при запуске отображает либо Табло с наиболее посещаемыми страницами, либо вкладки, открытые в прошлый раз. По умолчанию открываются вкладки.
Как изменить вид контекстного меню?
Если в контекстном меню для вас слишком много команд:
После этого часть команд переместится в раздел Дополнительно .
Когда вы выделяете слова или фразы, над ними автоматически всплывает панель с командами Найти в Яндексе и Копировать . Если вам она мешает:
Что происходит при сбросе настроек браузера?
В результате сброса настроек браузера будут восстановлены исходные настройки:
За последние несколько месяцев мы внесли множество улучшений в движок рендеринга Microsoft Edge (EdgeHTML), делая особый акцент на совместимости с современными браузерами и соответствии новым и грядущим стандартам. Помимо того, что EdgeHTML лежит в основе браузера Microsoft Edge, он также доступен для приложений на Universal Windows Platform (UWP) через элемент управления WebView. Сегодня мы хотим рассказать, как можно использовать WebView для создания своего браузера в Windows 10.
Используя стандартные веб-технологии, включая JavaScript, HTML и CSS, мы создали простое UWP-приложение, которое содержит внутри WebView и реализует базовую функциональность: навигацию и работу с избранным. Подобные приемы могут быть использованы в любом UWP-приложении для прозрачной интеграции веб-контента.
В основе нашего примера лежит мощный элемент управления WebView. Помимо комплексного набора API, данный элемент также позволяет преодолеть некоторые ограничения, присущие iframe, например, отслеживание фреймов (когда некоторый сайт меняет свое поведение в случае выполнения внутри iframe) и сложность определения загрузки документа. В дополнение x-ms-webview, — так WebView задается в HTML, — дает доступ к функциональности, не доступной в iframe, в частности, улучшенный доступ к локальному контенту и возможности делать снимки содержимого. Когда вы используете элемент управления WebView, вы получаете тот же самый движок, что и в Microsoft Edge.
Создаем браузер
Как было написано выше, браузер базируется на элементе управления WebView для HTML, а для создания и оживления пользовательского интерфейса в основном используется JavaScript. Проект создан в Visual Studio 2015 и представляет собой универсальное Windows-приложение на JavaScript.
Помимо JavaScript, мы также использовали немного HTML и CSS, а также некоторое количество строк кода на C++ для поддержки комбинаций клавиш, но это не требуется в простом случае.
Также мы пользуемся новыми возможностями нового ECMAScript 2015 (ES2015), поддерживаемыми в Chakra, JavaScript-движке, работающем в Microsoft Edge и элементе управления WebView. ES2015 позволил нам сократить количество генерируемого и шаблонного кода, тем самым существенно упростив реализацию идеи. Мы использовали следующие возможности ES2015 при создании приложения: Array.from(), Array.prototype.find(), arrow functions, method properties, const, for-of, let, Map, Object.assign(), Promises, property shorthands, Proxies, spread operator, String.prototype.includes(), String.prototype.startsWith(), Symbols, template strings и Unicode code point escapes.
Интерфейс пользователя
Пользовательский интерфейс включает следующие десять компонентов:
Дополнительная функциональность
Мы также реализовали несколько дополнительных возможностей, чтобы сделать работу с браузером еще более приятной:
Использование WebView
Введенный для JavaScript-приложений в Windows 8.1 элемент управления WebView, иногда также упоминаемый по имени тега x-ms-webview, позволяет хостить веб-контент внутри вашего Windows-приложения. Он доступен как для HTML, так и для XAML.Для начала работы достаточно разместить соответствующий элемент в коде страницы.
Разработка браузера
Мы будем использовать 15 различных API x-ms-webview. Все кроме двух из них управляют навигацией между страницами с некотором смысле. Давайте посмотрим, как можно использовать данные интерфейсы для создания различных элементов UI.
Управление кнопками назад и вперед
Когда вы нажимаете кнопку назад, браузер возвращает предыдущую страницу из истории браузера, если она доступна. Аналогично, когда вы нажимаете кнопку вперед, браузер возвращает последующую страницу из истории, если она также доступна. Для реализации подобной логики мы используем методы goBack() и goForward(), соответственно. Данные функции автоматически осуществят навигацию на корректную страницу из стека навигации.
После перехода на некоторую страницу, мы также обновляем текущее состояние кнопок, чтобы предотвратить «возможность» навигации, когда мы достигаем одного из концов стека навигации. Другими словами, мы отключаем кнопки навигации вперед или назад, проверяя свойства canGoBack или canGoForward на равенство false.
Управление кнопками обновления и остановки
Кнопки обновления и остановки слегка отличаются от остальных компонент панели навигации тем, что они используют одно и то же место в UI. Когда страница загружается, нажатие на кнопку остановит загрузку, спрячет «кольцо прогресса» и отобразит иконку обновления. И наоборот, когда страница загружена, нажатие на кнопку запустит обновление страницы и (в другой части кода) отобразит иконку остановки. Мы используем методы refresh() или stop() в зависимости от текущих условий.
Управление адресной строкой
В целом, реализация адресной строки может быть очень простой. Когда адрес URL введен в текстовое поле, нажатие Enter вызовет метод navigate(), используя содержимое input-элемента адресной строки в качестве параметра.
Однако современные браузеры пошли сильно дальше и внедряют дополнительную функциональность для удобства пользователей. Это добавляет некоторую сложность в реализации – и тут все зависит от сценариев, которые вы хотите поддержать.
Отображение favicon
Мы используем метод invokeScriptAsync(), чтобы вставить внутрь элемента управления WebView скрипт, который вернет строку в случае успеха. Наш скрипт ищет внутри страницы все элементы с link-теком, проверяет, если rel-атрибут содержит слово “icon”, и в случае совпадения возвращает значение “href”-атрибута назад в приложение.
Как упомянуто выше, мы используем в нашем коде возможности из новой спецификации ES2015. Вы могли заметить использование стрелочной нотации во многих примерах выше, а также ряд других возможностей. Вставляемый скрипт – это отличный пример улучшения кода, достигаемого за счет поддержки ES2015.
Поддержка комбинаций клавиш
Чтобы определить нажатие горячих клавиш для выполнения тех или иных действий, например, чтобы при нажатии комбинации Ctrl+L выделять адресную строку или по F11 переключаться в полноэкранный режим, нам нужно вставить еще один скрипт в WebView. Для этого мы используем метод invokeScriptAsync(), который мы уже упоминали выше. Однако, нам нужно как-то сообщать назад в слой приложения, когда те или иные клавиши нажаты.
С помощью метода addWebAllowedObject(), мы можем выставить для инжектируемого кода метод, через который можно будет передавать нажимаемые клавиши в слой приложения на JavaScript. Также важно понимать, что в Windows 10, элемент управления WebView выполняется в отдельном потоке. Нам нужно создать диспетчер, который будет передавать события в поток UI, чтобы слой приложения мог их обрабатывать.
Внешний вид браузера
Теперь, когда мы разобрались с ключевыми API WebView, давайте немного улучшим внешний вид нашего браузера.
Брендирование заголовка
Используя API Windows Runtime, мы можем поменять свойство ApplicationView.TitleBar, чтобы настроить цветовую палитру все компонентов заголовка приложения. В нашем браузере при загрузке приложения мы меняем цвета так, чтобы они соответствовали панели навигации. Мы также обновляем цвета при открытии меню, чтобы соответствовать фону меню. Каждый цвет нужно задавать как объект с RGBA свойствами. Для удобства мы создали вспомогательную функцию, генерирующую нужный формат из шестнадцатеричной строковой записи.
Прочие возможности
Индикация прогресса, а также меню настроек и избранного используют CSS transitions для анимации. Из меню настроек временные веб-данные можно очистить, используя метод clearTemporaryWebDataAsync(). А в меню избранного отображаемый список хранится в JSON-файле в корневой папке перемещаемого хранилища данных приложения.
Исходный код
Полный пример кода доступен в нашем репозитарии на GitHub. Вы можете также попробовать демонстрационный браузер, установив соответствующее приложение из Windows Store, или развернув приложение из проекта для Visual Studio.
В отличие от распространенной "клиент-серверной" архитектуры, для децентрализованных приложений характерно:
- Отсутствие необходимости хранить базу данных с логинами и паролями пользователя. Информация для доступа хранится исключительно у самих пользователей, а подтверждение их достоверности происходит на уровне протокола.
- Отсутствие необходимости использовать сервер. Логика приложения может выполняться в блокчейн-сети, где возможно и хранение необходимого количества данных.
Существует 2 относительно безопасных хранилища для ключей пользователей — хардверные кошельки и браузерные расширения. Хардверные кошельки в большинстве своем максимально безопасны, однако сложны в использовании и далеко не бесплатны, а вот браузерные расширения являются идеальным сочетанием безопасности и простоты в использовании, а еще могут быть совершенно бесплатны для конечных пользователей.
Учитывая все это, мы захотели сделать максимально безопасное расширение, которое упрощает разработку децентрализованных приложений, предоставляя простой API для работы с транзакциями и подписями.
Об этом опыте мы вам и расскажем ниже.
В статье будет пошаговая инструкция как написать браузерное расширение, с примерами кода и скриншотами. Весь код вы можете найти в репозитории. Каждый коммит логически соответствует разделу данной статьи.
Краткая история браузерных расширений
Браузерные расширения существуют достаточно давно. В Internet Explorer они появились еще в 1999-м году, в Firefox — в 2004-м. Тем не менее, очень долго не было единого стандарта для расширений.
Можно сказать, что он появился вместе с расширениями в четвертой версии Google Chrome. Конечно, никакой спецификации тогда не было, но именно API Chrome стал ее основой: завоевав большую часть рынка браузеров и имея встроенный магазин приложений, Chrome фактически задал стандарт для браузерных расширений.
У Mozilla был свой стандарт, но, видя популярность расширений для Chrome, компания решила сделать совместимый API. В 2015 году по инициативе Mozilla в рамках World Wide Web Consortium (W3C) была создана специальная группа для работы над спецификациями кроссбраузерных расширений.
За основу был взят уже существующий API расширений для Сhrome. Работа велась при поддержке Microsoft (Google в разработке стандарта участвовать отказался), и в результате появился черновик спецификации.
Формально спецификацию поддерживают Edge, Firefox и Opera (заметьте, что в этом списке отсутствует Chrome). Но на самом деле стандарт во многом совместим и с Chrome, так как фактически написан на основе его расширений. Подробнее о WebExtensions API можно прочитать здесь.
Структура расширения
Единственный файл, который обязательно нужен для расширения — манифест (manifest.json). Он же является “точкой входа” в расширение.
Манифест
По спецификации файл манифеста является валидным JSON файлом. Полное описание ключей манифеста с информацией о том, какие ключи в поддерживается в каком браузере, можно посмотреть здесь.
Ключи, которых нет в спецификации, “могут” быть проигнорированы (и Chrome, и Firefox пишут об ошибках, но расширения продолжают работать).
А я бы хотел обратить внимание на некоторые моменты.
- background — объект, который включает в себя следующие поля:
- scripts — массив скриптов, которые будут выполнены в background-контексте (поговорим об этом чуть позже);
- page — вместо скриптов, которые будут выполнятся в пустой странице, можно задать html с контентом. В этом случае поле script будет проигнорировано, а скрипты нужно будет вставить в страницу с контентом;
- persistent — бинарный флаг, eсли не указан, то браузер будет "убивать" background-процесс, когда посчитает, что он ничего не делает, и перезапускать при необходимости. В противном случае страница будет выгружена только при закрытии браузера. Не поддерживается в Firefox.
- matches — паттерн url, по которому определяется, будет включаться конкретный content script или нет.
- js — список скриптов которые будут загружены в данный матч;
- exclude_matches — исключает из поля match URL, которые удовлетворяют этому полю.
- default_popup — путь до HTML файла с popup-интерфейсом, может содержать CSS и JS.
Контекст выполнения
У расширения есть три контекста исполнения кода, то есть, приложение состоит из трех частей с разным уровнем доступа к API браузера.
Extension context
Здесь доступна большая часть API. В этом контексте "живут":
- Background page — “backend” часть расширения. Файл указывается в манифесте по ключу “background”.
- Popup page — popup страница, которая появляется при нажатии на иконку расширения. В манифесте browser_action -> default_popup .
- Custom page — страница расширения, "живущая" в отдельной вкладке вида chrome-extension://<id_расширения>/customPage.html .
Этот контекст существует независимо от окон и вкладок браузера. Background page существует в единственном экземпляре и работает всегда (исключение — event page, когда background-скрипт запускается по событию и "умирает" после его выполнения). Popup page существует, когда открыто окно popup, а Custom page — пока открыта вкладка с ней. Доступа к другим вкладкам и их содержимому из этого контекста нет.
Content script context
Файл контент-скрипта запускается вместе с каждой вкладкой браузера. У него есть доступ к части API расширения и к DOM-дереву веб-страницы. Именно контент-скрипты отвечают за взаимодействие со страницей. Расширения, манипулирующие DOM-деревом, делают это в контент-скриптах – например, блокировщики рекламы или переводчики. Также контент-скрипт может общаться со страницей через стандартный postMessage .
Web page context
Это собственно сама веб-страница. К расширению она не имеет никакого отношения и доступа туда не имеет, кроме случаев, когда в манифесте явно не указан домен этой страницы (об этом — ниже).
Сервер или background:
Также есть событие onDisconnect и метод disconnect .
Схема приложения
Давайте сделаем браузерное расширение, которое хранит приватные ключи, предоставляет доступ к публичной информации (адрес, публичный ключ общается со страницей и позволяет сторонним приложениям запросить подпись транзакций.
Разработка приложения
Наше приложение должно как взаимодействовать с пользователем, так и предоставлять странице API для вызова методов (например, для подписи транзакций). Обойтись одним лишь contentscript не получится, так как у него есть доступ только к DOM, но не к JS страницы. Подключаться через runtime.connect мы не можем, потому что API нужен на всех доменах, а в манифесте можно указывать только конкретные. В итоге схема будет выглядеть так:
Будет еще один скрипт — inpage , который мы будем инжектить в страницу. Он будет выполняться в ее контексте и предоставлять API для работы с расширением.
Начало
Весь код браузерного расширения доступен на GitHub. В процессе описания будут ссылки на коммиты.
Начнем с манифеста:
Создаем пустые background.js, popup.js, inpage.js и contentscript.js. Добавляем popup.html — и наше приложение уже можно загрузить в Google Chrome и убедиться, что оно работает.
Чтобы убедиться в этом, можно взять код отсюда. Кроме того, что мы сделали, по ссылке настроена сборка проекта с помощью webpack. Чтобы добавить приложение в браузер, в chrome://extensions нужно выбрать load unpacked и папку с соответствующим расширением — в нашем случае dist.
Теперь наше расширение установлено и работает. Запуститьинструменты для разработчиков для разных контекстов можно следующим образом:
Доступ к консоли контент-скрипта осуществляется через консоль самой страницы, на которой он запущен.
Это браузерное расширение для работы с сетью Ethereum. В нем разные части приложения общаются через RPC при помощи библиотеки dnode. Она позволяет достаточно быстро и удобно организовать обмен, если в качестве транспорта ей предоставить nodejs stream (имеется в виду объект, реализующий тот же интерфейс):
Теперь мы создадим класс приложения. Оно будет создавать объекты API для popup и веб-страницы, а также создавать dnode для них:
Создадим инстанс приложения в background скрипте:
Так как dnode работает со стримами, а мы получаем порт, то необходим класс-адаптер. Он сделан при помощи библиотеки readable-stream, которая реализует nodejs-стримы в браузере:
Теперь создаем подключение в UI:
Затем мы создаем подключение в content script:
Так как API нам нужен не в контент-скрипте, а непосредственно на странице, мы делаем две вещи:
- Создаем два стрима. Один — в сторону страницы, поверх postMessage. Для этого мы используем вот этот пакет от создателей metamask. Второй стрим — к background поверх порта, полученного от runtime.connect . Пайпим их. Теперь у страницы будет стрим до бэкграунда.
- Инжектим скрипт в DOM. Выкачиваем скрипт (доступ к нему был разрешен в манифесте) и создаем тег script с его содержимым внутри:
Теперь создаем объект api в inpage и заводим его global:
У нас готов Remote Procedure Call (RPC) с отдельным API для страницы и UI. При подключении новой страницы к background мы можем это увидеть:
Пустой API и origin. На стороне страницы мы можем вызвать функцию hello вот так:
Работать с callback-функциями в современном JS — моветон, поэтому напишем небольшой хелпер для создания dnode, который позволяет передавать в объект API в utils.
Объекты API теперь будут выглядеть вот так:
Получение объекта от remote следующим образом:
А вызов функций возвращает промис:
Версия с асинхронными функциями доступна здесь.
В целом, подход с RPC и стримами кажется достаточно гибким: мы можем использовать steam multiplexing и создавать несколько разных API для разных задач. В принципе, dnode можно использовать где угодно, главное — обернуть транспорт в виде nodejs стрима.
Внутренний стейт и localStorage
Нам понадобится хранить внутренний стейт приложения — как минимум, ключи для подписи. Мы можем достаточно легко добавить стейт приложению и методы для его изменения в popup API:
В background обернем все в функцию и запишем объект приложения в window, чтобы можно было с ним работать из консоли:
Добавим из консоли UI несколько ключей и посмотрим, что получилось со стейтом:
Стейт нужно сделать персистентным, чтобы при перезапуске ключи не терялись.
Хранить будем в localStorage, перезаписывая при каждом изменении. Впоследствии доступ к нему также будет необходим для UI, и хочется также подписываться на изменения. Исходя из этого удобно будет сделать наблюдаемое хранилище (observable storage) и подписываться на его изменения.
Добавим инициализацию начального стейта и сделаем store observable:
"Под капотом" mobx заменил все поля store на proxy и перехватывает все обращения к ним. На эти обращения можно будет подписываться.
Далее я буду часто использовать термин “при изменении”, хотя это не совсем корректно. Mobx отслеживает именно доступ к полям. Используются геттеры и сеттеры прокси-объектов, которые создает библиотека.
Декораторы action служат двум целям:
- В строгом режиме с флагом enforceActions mobx запрещает менять стейт напрямую. Хорошим тоном считается работа именно в строгом режиме.
- Даже если функция меняет стейт несколько раз – например, мы меняем несколько полей в несколько строк кода, — обсерверы оповещаются только по ее завершении. Это особенно важно для фронтенда, где лишние обновления стейта приводят к ненужному рендеру элементов. В нашем случае ни первое, ни второе особо не актуально, однако мы будем следовать лучшим практикам. Декораторы принято вешать на все функции, которые меняют стейт наблюдаемых полей.
В background добавим инициализацию и сохранение стейта в localStorage:
Интересна здесь функция reaction. У нее два аргумента:
- Селектор данных.
- Обработчик, который будет вызван с этими данными каждый раз, когда они изменяются.
В отличие от redux, где мы явно получаем стейт в качестве аргумента, mobx запоминает к каким именно observable мы обращаемся внутри селектора, и только при их изменении вызывает обработчик.
Важно понимать, как именно mobx решает, на какие observable мы подписываемся. Если бы в коде я написал селектор вот так () => app.store , то reaction не будет вызван никогда, так как сам по себе хранилище не является наблюдаемым, таковыми являются только его поля.
Если бы я написал вот так () => app.store.keys , то опять ничего не произошло бы, так как при добавлении/удалении элементов массива ссылка на него меняться не будет.
Mobx в первый раз выполняет функцию селектора и следит только за теми observable, к которым мы получали доступ. Сделано это через геттеры прокси. Поэтому здесь использована встроенная функция toJS . Она возвращает новый объект, в котором все прокси заменены на оригинальные поля. В процессе выполнения она читает все поля объекта – следовательно, срабатывают геттеры.
В консоли popup снова добавим несколько ключей. На этот раз они попали еще и в localStorage:
При перезагрузке background-страницы информация остается на месте.
Весь код приложения до этого момента можно посмотреть здесь.
Безопасное хранение приватных ключей
Хранить приватные ключи в открытом виде небезопасно: всегда есть вероятность того, что вас взломают, получат доступ к вашему компьютеру и так далее. Поэтому в localStorage мы будем хранить ключи в зашифрованном паролем виде.
Для большей безопасности добавим приложению стейт locked, в котором доступа к ключам не будет совсем. Мы будем автоматически переводить расширение в стейт locked по таймауту.
Mobx позволяет хранить только минимальный набор данных, а остальное автоматически рассчитывать на их основе. Это — так называемые computed properties. Их можно сравнить с view в базах данных:
Теперь мы храним только шифрованные ключи и пароль. Все остальное вычисляется. Перевод в стейт locked мы делаем с помощью удаления пароля из стейта. В публичном API появился метод для инициализации хранилища.
У браузера есть idle API, через который можно подписаться на событие — изменения стейта. Стейт, соответственно, может быть idle , active и locked . Для idle можно настроить таймаут, а locked устанавливается, когда блокируется сама ОС. Также мы поменяем селектор для сохранения в localStorage:
Код до этого шага находится здесь.
Транзакции
Итак, мы подошли к самому главному: созданию и подписи транзакций в блокчейне. Мы будем использовать блокчейн WAVES и библиотеку waves-transactions.
Если не сделать observable вручную, то mobx сделает это сам при добавлении в массив messages. Однако он создаст новый объект, на который у нас не будет ссылки, а она понадобится для следующего шага.
Approve и reject мы выносим в API UI, newMessage — в API страницы:
Теперь попробуем подписать транзакцию расширением:
В целом все готово, осталось добавить простой UI.
Интерфейсу нужен доступ к стейту приложения. На стороне UI мы сделаем observable стейт и добавим в API функцию, которая будет этот стейт менять. Добавим observable в объект API, полученный от background:
В конце мы запускаем рендер интерфейса приложения. Это react-приложение. Background-объект просто передается при помощи props. Правильно, конечно, сделать отдельный сервис для методов и store для стейта, но в рамках данной статьи этого достаточно:
С помощью mobx очень просто запускать рендер при изменении данных. Мы просто вешаем декоратор observer из пакета mobx-react на компонент, и рендер будет автоматически вызываться при изменении любых observable, на которые ссылается компонент. Не нужно никаких mapStateToProps или connect, как в redux. Все работает сразу "из коробки":
Остальные компоненты можно посмотреть в коде в папке UI.
Теперь в классе приложения необходимо сделать селектор стейта для UI и при его изменении оповещать UI. Для этого добавим метод getState и reaction , вызывающий remote.updateState :
При получении объекта remote создается reaction на изменение стейта, который вызывает функцию на стороне UI.
Итак, приложение готово. Веб-страницы могут запрашивать подпись транзакций:
Код доступен по этой ссылке.
Заключение
Если вы дочитали статью до конца, но у вас остались вопросы, вы можете задать их в репозитории с расширением. Там же вы найдете коммиты под каждый обозначенный шаг.
А если вам интересно посмотреть код настоящего расширения, то вы сможете найти это здесь.
Читайте также: