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

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

¹ Тресорит Сенд. Бесплатное решение для обмена файлами со сквозным шифрованием, в котором вы можете делиться своими файлами (до 5 ГБ) без регистрации.

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

Анатомия расширения браузера

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

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

Манифест

Расширения могут обеспечивать дополнительное поведение сайтам, посещаемым пользователем, или самому браузеру. В качестве точки входа файл manifest.json является описателем функций и требований расширения, а также декларацией различных контекстов, в которых выполняется расширение.

У расширения есть несколько способов привязать себя к браузеру. Наиболее известна кнопка действия браузера, которая появляется рядом с адресной строкой браузера. Расширение может разместить свой постоянный значок там или внутри строки URL-адреса в качестве действия страницы для выбранных веб-сайтов, объявленных заранее (с атрибутами browser_action и page_action соответственно). Щелчок по этому значку активирует всплывающее окно, загружающее зарегистрированный HTML-ресурс.

Для действий без представлений (загруженный HTML) или длительных независимых вычислений, всегда готовых приложений, также есть возможность запускать скрипты или одну страницу в фоновом режиме (атрибут background). Эта фоновая страница может быть постоянной или запускаться только при определенных событиях.

Расширение также может иметь специальную страницу параметров (атрибут options_page), доступную из контекстного меню страницы browser_action и списков расширений. Другие ресурсы также могут быть представлены с помощью атрибута web_accessible_resources, например определенные HTML-страницы, изображения или ресурсы сценария, к которым могут обращаться размещенные в Интернете сайты или сценарии содержимого.

Расширение может нацеливаться на определенные веб-сайты и вводить код JavaScript (атрибут content_scripts). Эти сценарии содержимого выполняются в отдельном контексте от сценариев на этих веб-сайтах, но могут изменять DOM страницы. (Используя это расширение, можно внедрять сценарии и ресурсы, которые теперь работают в одном контексте.)

Для получения дополнительной информации см. Документацию manifest.json на MDN.

API JavaScript для веб-расширений

Скрипты расширения браузера запускаются в расширенном контексте, где - с явными разрешениями - расширение может получить доступ не только к простому веб-сайту. Расширение может изменять поведение браузера при вводе пользователем данных; доступ к открытым вкладкам, файлам cookie; отправлять уведомления; изменить сетевые запросы или просто изменить его значок. Все зависит от того, что пользователь разрешил расширению делать при установке расширения.

Подробное описание см. В Документации по JavaScript API на MDN. Расширению Tresorit Send требуется доступ только к cookies на send.tresorit.com и к самому сайту для вставки сценария содержимого, отключающего всплывающее окно Добавить в Chrome, поскольку у пользователя уже есть расширение установлено. Таким образом, наиболее важным API является модуль runtime, который упрощает обмен данными внутри расширения (помимо других функций), подробно описанный в следующем разделе.

Коммуникация

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

runtime.connect(). Установите соединение между двумя расширениями; или от сценария содержимого к сценариям фона.

runtime.sendMessage() / runtime.onMessage. Отправлять и прослушивать сообщения из сценария содержания, фоновых сценариев, всплывающих окон браузера или страницы или страницы параметров.

tabs.sendMessage() / runtime.onMessage. Отправляйте и слушайте сообщения с различных страниц расширений скрипту содержания, запущенному для сайта.

Уловки, благодаря которым расширение Tresorit Send для Chrome работает

Мы с самого начала разработали веб-приложение Tresorit Send с учетом расширения Chrome. Нам нужно было убедиться, что компоненты веб-приложения можно реорганизовать, чтобы оно могло следовать жизненному циклу расширения, сохраняя при этом все базовые функции и даже расширяя их. В этом разделе подробно описаны решения и хитрости, которые мы применили, чтобы сделать расширение отличным.

Постоянно работающая фоновая страница

Жизненный цикл веб-приложения довольно прост. Пользователь загружает страницу, HTML анализируется, стили и скрипты загружаются и применяются. Приложение запускается и работает до тех пор, пока не будет приостановлено или закроется вкладка.

То же самое относится к зарегистрированной странице browser_action, которая открывается, когда пользователь щелкает значок расширения. Однако это не постоянная страница. Он виден только до тех пор, пока пользователь не щелкнет где-нибудь за пределами расширения, а затем он закроется. Поскольку наше расширение загружает файлы большого размера, до 5 ГБ, мы не можем ожидать, что пользователь не будет использовать свой браузер до завершения загрузки.

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

Для обработки статических и динамических рабочих процессов и взаимодействия между процессами внутри приложения (основной поток графического интерфейса, рабочий обработчик сеансов, криптовалютные рабочие, фоновая страница) мы используем нашу платформу с открытым исходным кодом WorkerServiceManager (похожую на comlink, но WSM поддерживает IE11, воркеры и окна, фреймы и тому подобное с обертками). WSM позволяет отправлять и получать сообщения между двумя рабочими процессами через основной поток графического интерфейса. Экземпляр WSM может быть динамически расширен за счет временных рабочих и окон в качестве целей сообщений.

Это то, что мы используем для разделения приложения на FrontendServiceManager и BackgroundServiceManager. Первый объявляет службы, запущенные на внешнем интерфейсе (одна служба, EventService, которая может получать события и действовать в соответствии с ними, например, когда загрузка файла завершена), и имеет список удаленных сервисов, которые будут зарегистрированы, с сериализацией сообщений «прокси», которые управляют безопасностью типов и преобразованием сообщений. Удаленные службы, например LinkSessionService, PacketManagerService или AsyncAsmCryptoService.

Когда приложение работает в расширении, оно знает, что эти удаленные службы находятся вне контекста потока графического интерфейса. Для этого требуется ссылка на окно фоновой страницы (runtime.getBackgroundPage()), где создается отдельный экземпляр BackgroundServiceManager и пересылает ему сообщения.

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

С помощью WorkerServiceManager службы могут работать где угодно (например, в другой вкладке, в окне или в работнике), пока там зарегистрирован WorkerServiceManager, ожидающий сообщений.

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

Как сделать идентификатор расширения фиксированным

Каждое расширение получает идентификатор при установке. В Firefox каждая установка получает уникальный идентификатор, в то время как в Chrome он получает фиксированный идентификатор при установке из Chrome Store (подробнее о Chrome Store, консоли Chrome Dev в следующем разделе). Расширения Chrome, установленные локально, получают случайный идентификатор.

Когда расширение делает сетевой запрос, источник запроса определяется идентификатором расширения. Для Chrome это chrome-extension://<fixed-id>, а для Firefox - moz-extension://<random-UUID>. Поскольку серверы Tresorit Send разрешают подключения только из выбранных исходных доменов (CORS), нам нужны фиксированные идентификаторы. К сожалению, в Firefox это невозможно, поэтому браузер не поддерживается до тех пор, пока не будут устранены эти проблемы (№14, №17).

Фиксированные идентификаторы для расширений Chrome назначаются при создании в Chrome Dev Console. Чтобы иметь такой же идентификатор партии для разрабатываемой версии расширения:

  1. загрузить версию расширения
  2. опубликовать это
  3. загрузите подписанный архив расширений (файл .crx) из Google из Панели инструментов разработчика или с помощью такого инструмента, как Chrome Extension Downloader
  4. распаковать архив и открыть manifest.json файл
  5. скопируйте атрибут key (открытый ключ RSA-256 для расширения, назначенного Google) из этого manifest.json файла в исходный manifest.json файл.

Теперь версия для разработчиков будет иметь тот же идентификатор, что и версия, опубликованная в Chrome Store, и перезаписать уже установленную локальную версию.

Связь с живым веб-приложением

Используете размещенное веб-приложение Tresorit Send с установленным расширением Chrome? Эй, мы не судим! Но просто чтобы мы не подталкивали вас к повторной установке расширения, расширение сообщает веб-приложению, что оно присутствует и чувствует себя хорошо, установленным в вашем браузере.

К сожалению, из веб-приложения невозможно определить, установлено ли расширение уже. Таким образом, мы используем content_scripts только в домене send.tresorit.com.

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

Обработка обновлений

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

Взглянув на статистику, предоставленную Chrome Developer Dashboard, легко увидеть, что нашему расширению требуется от 2 до 4 недель для полного развертывания и обновления на каждом компьютере пользователя. Кроме того, новая версия может быть отложена даже на час, прежде чем она станет общедоступной после публикации.

Расширения Chrome с постоянными фоновыми страницами перезагружаются только при перезапуске браузера. У большинства пользователей это случается нечасто. Чтобы исправить это, нам нужно вручную перезапустить (и, таким образом, установить обновление для) расширения. В Chrome есть API для обработки обновлений расширений (chrome.runtime.onUpdateAvailable), который проверяет наличие обновлений с интервалом в несколько часов и уведомляет расширение, когда оно обнаруживается.

Когда расширение получает событие «доступно обновление», оно проверяет, все ли окна и всплывающие окна закрыты и нет ли в процессе загрузки, а затем автоматически перезапускается.

В случае, если нам действительно нужно исправить неработающий выпуск и мы хотим принудительно отказаться от версии расширения, сервер может отклонить соединение с ответом DeprecatedClientAgent. Затем расширение отображает модальное окно и заставляет Chrome проверять наличие новой версии (используя runtime.requestUpdateCheck()).

Угловая навигация

У Tresorit Send есть интерфейс Angular, даже в расширении, как одностраничное приложение (SPA). В размещенном веб-приложении мы используем пути виртуальных ресурсов (PathLocationStrategy, например, /home /users /login). Однако, когда пользователь нажимает кнопку F5 обновления, когда фокус находится на странице browser_action, виртуальный ресурс не будет найден.

Для расширений браузера рекомендуется HashLocationStrategy, где текущий виртуальный путь добавляется к относительному URL-адресу страницы browser_action после # в виде строки запроса (index.html#login). Это переживает перезагрузку страницы и отображает правильный компонент.

Значки

Хотя для отображения значков предусмотрен API (browserAction.setBadgeBackgroundColor(), browserAction.setBadgeText()), позволяющий отображать текст с произвольным цветом фона, этот API не подготовлен для отображения пользовательских значков, значков поверх основного значка.

Однако можно нарисовать новое изображение browser_action на холсте с тем же ресурсом значка, затем нарисовать на нем значок и установить его в качестве отображаемого значка (browserAction.setIcon()). С помощью таймеров также возможно анимировать значок, отображая прогресс, даже когда всплывающее окно не открыто, и пользователь ожидает длительной операции, такой как загрузка больших файлов.

Всплывающие окна и выбор файлов в Linux

В Chrome ресурсы browser_action HTML открываются во всплывающих окнах ограниченного размера внутри окна браузера, сразу под значком browser_action. Это всплывающее окно может оставаться открытым до тех пор, пока пользователь не щелкает за его пределами.

При загрузке файлов с использованием расширения Tresorit Send в Windows и macOS пользователь может выбирать файлы в селекторе файлов, и всплывающее окно по-прежнему будет открыто. Это не относится к операционным системам на базе Linux. В этих системах всплывающее окно закрывается, как только пользователь начинает выбирать файлы.

Чтобы решить эту проблему, расширение открывает новое окно в Linux с ограничениями по размеру, приблизительно соответствующее тому месту, где оно должно открываться. Поскольку расположение основного browser_action ресурса известно, легко имитировать поведение всплывающих окон. Однако это окно необходимо закрыть вручную.

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

Политика безопасности контента

Как и в размещенном веб-приложении Tresorit Send, мы устанавливаем атрибут content_security_policy в manifest.json расширения. Таким образом мы можем объявить:

  • с какими доменами мы разрешаем взаимодействовать расширению (наши серверы)
  • откуда мы принимаем входящие сообщения
  • какие сайты могут вставлять расширение как фрейм
  • откуда берутся изображения, скрипты, рабочие файлы
  • куда сообщать о нарушениях политики безопасности контента

Публикация расширения Chrome

Когда у вас будет готовое расширение браузера с manifest.json в качестве точки входа, установленными обязательными полями и имеющимися ресурсами, вы готовы загрузить его в Chrome. Проверьте, правильно ли он работает, а затем отправьте его в Chrome Store, чтобы все могли им пользоваться!

В этом разделе я подробно расскажу, как начать работу с Chrome Store для разработчиков, какие уловки мы используем для создания различных тестовых выпусков и как публиковать новую версию расширения Chrome при каждом развертывании веб-приложения.

Магазин Chrome для разработчиков

Чтобы узнать, как опубликовать расширение в Chrome Store, прочтите его прямо из источника: Опубликовать в Chrome Web Store.

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

  • Дашборд разработчика - старый сайт, на котором есть все необходимые настройки, правда, со старым внешним видом.

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

Вы можете и должны использовать обе версии при загрузке расширения. Если вы работаете не в одиночку, не забудьте создать новую учетную запись групповой публикации. Учетная запись публикации группы, поддерживаемая Группами Google, позволяет добавлять и удалять ваших коллег-разработчиков. (Вам придется заплатить единовременную плату разработчика за каждую учетную запись.)

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

Создание тестовых версий для внутреннего тестирования

Расширения Chrome могут быть в следующих 4 категориях:

  • Не опубликовано
  • Общедоступно - это могут видеть все (в выбранных странах).
  • Не в списке - его могут видеть только люди, у которых есть ссылка.
  • Частный - его могут видеть только избранные тестировщики.

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

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

Автоматическая публикация в Chrome Store

Каждый раз, когда развертывается веб-приложение Tresorit Send, мы также выпускаем расширение Chrome. После того, как все скопировано в папку dist-ext, оно архивируется и отправляется в Chrome Store как новая версия. Затем новая версия публикуется либо для тестировщиков, либо для общественности.

Для получения дополнительной информации прочтите документацию в разделе Использование API публикации Chrome Web Store.

О подписании расширения

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

Понравилось то, что вы прочитали? Попробуйте вживую на Tresorit Send или скачайте Tresorit Send Chrome extension!