Предыстория проекта
Чтобы предоставить некоторым учителям простой в использовании настольный инструмент потоковой передачи, мы планируем запустить настольное приложение Windows под названием Live Companion и быстро представить Live Companion 1.0 на Весеннем фестивале 2020 года. В настоящее время основными функциями Live Companion являются:
- Совместим с каждым входом на сайт
- прямая трансляция
- Живой Лианмай
- Интерактивный чат модератора
Разработка Live Companion ведется на основе Electron.С момента запуска проекта прошло уже больше года.Здесь я просто поделюсь опытом разработки Electron за более чем год,и в основном поделюсь некоторыми моментами на которые нужно обратить внимание при трансформации от веб-разработки до разработки на электронах.Принесите немного прибыли.
Технический отбор
Прежде чем приступить к работе с инструментами рабочего процесса push, мы изучили внутренний рабочий стол вибрато в прямом эфире — партнера по трансляции и базовую часть SDK plug-flow, выбор вибрато и прямой трансляции.Mediasdk
, и, наконец, определился с техническим выбором партнера прямой трансляции Byte Live:
Графический фреймворк | Фреймворк пользовательского интерфейса | глобализация | Упаковка приложения | Пакет SDK для потоковой передачи | Используйте платформу |
---|---|---|---|---|---|
Electron | React | react-intl | electron-builder | Mediasdk | Windows |
структура кода
Текущая структура каталогов Live Companion выглядит следующим образом:
-
app
: Бизнес-код-
assest
: статические ресурсы, такие как изображения, svg и т. д. -
components
: деловая составляющая -
containers
: Компонент выше, чем компоненты, обычно объединяющий несколько компонентов. -
pages
: Контейнер, соответствующий каждому BrowserWindow -
locale
: языковая конфигурация, связанная с интернационализацией. -
main
Модуль, вызываемый в основном процессе-
lib
: модули, вызываемые mediasdk, RTC и т. д. в основном процессе -
window
: Создание связанных с BrowserWindow и обработка связи процессов
-
-
reducers
: связанный с редуксом -
typings
: определение типа ts -
utils
: Инструменты -
package.json
: pkg каталога приложения, используется для установки зависимостей, которые необходимо вызывать в основном процессе. -
html文件
: html, загруженный BrowserWindow -
main.development.ts
: Файл входа в проект, используемый для запуска всего электронного проекта.
-
-
builder-config
: конфигурация, связанная с электронным сборщиком, включая локальную упаковку и конфигурацию онлайн-пакетов. -
config
: конфигурация, связанная с веб-пакетом -
script
: Скрипт, используемый при упаковке -
test
: шуточный тест -
package.json
: pkg корневого каталога, здесь устанавливаются интерфейсные зависимости, что позволяет избежать появления node_modules в упакованном файле.
Из структуры кода видно, что между написанием приложений Electron и веб-разработкой есть много общего:
- Его можно упаковать с помощью Webpack, а также есть пакеты различных компонентов React, package.json и другие файлы...
- В большинстве случаев пользовательский интерфейс и логика на странице могут продолжать использоваться в веб-разработке.
Подводя итог, переходя с веб-разработки на Electron, порог раннего старта низок.
Конечно, между веб-разработкой и разработкой на Electron обязательно будет разрыв, который также находится в центре внимания этого обмена.
Терминология, относящаяся к Electron, используемая при совместном использовании, будет сопровождаться ссылкой на официальную документацию Electron для справки.
Разница между электронной разработкой и веб-разработкой
Рабочий механизм
- Во время веб-разработки страница, которую мы разрабатываем, запускается во вкладке браузера:
Для одностраничного приложения (SPA) в качестве входного файла обычно используется HTML-файл. После упаковки интерфейсных ресурсов в HTML-код добавляется соответствующий файл bundle.js. файл загружается и соответствующий После того, как у вас есть ресурс, вы можете начать его использовать.
В то же время каждая вкладка браузера загружается в отдельный процесс.
- При разработке Electron наша страница запускается в окне десктопного приложения:
На веб-страницах Electron вы можете вводить собственные модули Nodejs в код для использования, такие как fs, path
Здесь мы вводим окна (соответствующие ElectronBrowserWindow) приложение Electron состоит из одного или нескольких окон.В Electron каждое окно соответствует html-файлу, что похоже на веб-разработку.
Но нам все равно нужен файл входа более высокого уровня, где мы организуем логику отображения различных окон в приложении.
То есть для приложений Electron шаг «доступа через браузер» на самом деле должен выполняться разработчиком.
Представьте себе браузер, вот три вопроса, над которыми стоит подумать:
- кто указывает, какие страницы посетить
- Кто обрабатывает действия самого браузера, открытие и закрытие вкладок, выход из браузера
- Кто несет ответственность за контент, отображаемый во вкладке страницы
В веб-разработке нам обычно нужно заботиться только о пользовательском интерфейсе и интерактивных частях интерфейсной страницы, и нам не нужно заботиться о закрытии окна и других операциях.
В приложениях Electron нам нужно отображать страницу пользователю, когда пользователь щелкает.Когда приложение содержит несколько окон, нам также необходимо управлять отображением и логикой скрытия каждого окна, такой как закрытие, отображение и положение окна. , Требуется осведомленность разработчика.
В Electron каждое окно соответствует процессу рендеринга, и есть основной процесс, который может управлять этими процессами рендеринга, поэтому мы обычно рассматриваем основной процесс как такой менеджер.
Для приведенной выше проблемы превратите ее в концепцию Электрона и посмотрите на нее:
- Кто указывает окно для открытия --> основной процесс
- Кто обрабатывает логику приложения, открытие и закрытие окон, выход из приложения -> основной процесс
- Кто отвечает за отображаемый в окне контент ---> процесс рендеринга
Различные окна взаимодействуют с основным процессом, и главный процесс выдает команды для формирования полного приложения Electron:
- Например, в окне входа в систему после успешного вызова интерфейса входа необходимо скрыть окно входа и отобразить последующее окно списка прямых трансляций.
- На стартовой странице должно появиться диалоговое окно, предлагающее пользователю
Взаимодействие и передача данных между BrowserWindow требует, чтобы соответствующий процесс рендеринга отправлял события в основной процесс.После того, как основной процесс обрабатывает, события отправляются указанному процессу рендеринга.
Проще говоря, разработка одностраничного приложения SPA — это один html, соответствующий одному приложению, в то время как разработка Electron может состоять из нескольких одностраничных приложений, которые посредством связи между процессами можно разделить на целое приложение.
Жизненный цикл электрона
Проекты, которые транслируются в прямом эфире в байтах, перечислены в структуре кода.main.development.ts
Такой файл, это входной файл проекта, в этом файле мы имеем дело с некоторымиBrowserWindowинициализация, регистрация необходимых обработчиков событий в основном процессе, отслеживание отчетов по данным и т. д. Самое главное, что мы имеем дело с жизненным циклом приложения Electron.готовое событие.
Жизненный цикл электрона
- запуск приложения
Когда приложение Electron завершит базовую инициализацию, оно будет выпущено один раз.ready
События, в настоящее время для разработчиков необходимо обрабатывать пользовательскую логику инициализации и отображать интерфейс пользовательского интерфейса для пользователя.
существуетmain.development.ts
Мы в приложенииready
Когда событие сработает, создайте страницу входа, страницу потока и т. д.BrowserWindow
, а в окне входаready-to-show
Когда событие срабатывает,show
способ отображения окна входа в Live Companion для пользователя.
- Выход из приложения
Всего на данный момент 6 живых партнеровBrowserWindow
, когда нам нужно выйти из приложения, мы уничтожим все текущиеBrowserWindow
экземпляр, который вызоветwindow-all-close
событие, здесь черезelectron.app.quit
метод, полностью закройте приложение.
const { app, BrowserWindow } = require('electron')
const path = require('path')
function createWindow () {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
win.loadFile('index.html')
}
app.whenReady().then(() => {
createWindow()
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})
})
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
Пример официального файла записи Electron
Опыт оптимизации
Предварительно созданный BrowserWindow
Здесь нужно отметить, что после создания каждого BrowserWindow оно должно занимать определенное количество ресурсов.В разработке необходимо максимально выполнить операцию в одном окне, чтобы уменьшить количество BrowserWindow.
BrowserWindow похож на вкладку браузера Chrome, в приложениях Electron каждое окно соответствуетBrowserWindow
экземпляр, который имеет свой собственный процесс рендеринга.
При создании мы можем указать размер, цвет, видимость и другие свойства этого окна.Документация BrowserWindow, когда мы создаем окно, передаемloadURL
Метод загружает указанный html для загрузки нашей страницы интерфейса.
В идеале поток для открытия нового окна будетnew BrowserWindow
->load js
->执行初始化逻辑
, закрытие окна пропускает этот экземпляр черезclose
метод уничтожить, а на самом деле каждый раз заново создаватьBrowserWindow
Накладные расходы относительно велики, и время ожидания пользователя часто невыносимо от создания до полностью интерактивной страницы.
В практических ситуациях мы обычно заранее создаем часто используемый BrowserWindow, а когда нам нужно его использовать, мы напрямую передаемshow
Отображение метода, когда вы нажимаете, чтобы закрыть, пройтиhide
Метод скрывает его в фоновом режиме, чтобы его можно было сразу открыть в следующий раз, сокращая время ожидания пользователя.Вот простая стратегия обмена пространством на время.Есть также много вопросов для обсуждения интерактивной оптимизации Электрона и того, как поймать с родным интерактивным опытом.
Когда мы показываем использование интерфейса Electronshow-hide
режим заменяетcreate-close
, вот некоторые моменты, которые отличаются от разработки веб-страницы:
- предварительно созданный
BrowserWindow
, логика инициализации может быть выполнена раньше времени -
BrowserWindow
При скрытии текущий компонент React не будет уничтожен.
Здесь мы конструируем сцену.После входа в систему мы попадаем в окно списка прямых трансляций.После нажатия на комнату прямых трансляций будет отображена стартовая страница комнаты прямых трансляций.
Взяв за пример инициализацию front-end страницы, когда мы переходим к инициализации страницы запуска, если она разработана по типу хуков, мы обычно указываем пустой массив в useEffect, что может обеспечить инициализацию всего компонента один раз, когда он загружается, например, из избыточности, Получите данные, запросите интерфейс и обновите соответствующее представление.
useEffect(() => {
init()
}, [])
Инициализация страниц в BrowerWindow
И мы обычно создаем заранее, чтобы оптимизировать интерактивный опыт пользователя.BrowserWindow
, и после этого сработает логика инициализации, что эквивалентно выполнению логики инициализации до клика, чего не ожидается.
в то же времяBrowserWindow
При скрытии, если не выполняется никакая специальная обработка, компонент React текущей страницы не будет уничтожен, поэтому, когда мы щелкаем в первый раз и щелкаем во второй раз, логика инициализации не будет выполняться повторно.
Есть два пути решения этого случая:
- В useEffect отслеживается переменная, и при изменении значения выполняется логика инициализации
- Посредством связи процесса основной процесс отправляет событие инициализации процессу рендеринга стартовой страницы.
Если мы используем первый метод мониторинга переменных, наш код может быть преобразован в:
useEffect(() => {
init(activityId)
}, [activityId])
Таким образом, когда мы нажимаем на живую комнату на странице списка, мы обновляем значение activityId, хранящееся в избыточности, и страница запуска обнаруживает изменение activityId, что может гарантировать, что логика инициализации выполняется правильно каждый раз, когда ActivityId переключился.
Существуют также недостатки использования этого метода, который эквивалентен использованию значения activityId в качестве триггерной основы для страницы для выполнения логики инициализации, а это означает, что нам необходимо уточнить, где это значение может вызвать логику изменения, чтобы предотвратить выполнение. логика инициализации, которая не соответствует ожиданиям.
Если мы воспользуемся вторым методом для выполнения инициализации через обмен данными между процессами, модификация кода будет немного сложнее.
Во-первых, нам нужно добавить прослушиватель на страницу внешнего интерфейса, обычно черезipcRenderer.on
реализация метода,ipcRendererСобытия, отправленные основным процессом, могут быть получены.Наш метод обработки здесь:
- После щелчка в окне списка перейдите
ipcRenderer.send
Метод отправляет это событие щелчка в основной процесс и переноситactivityId
параметр - Основной процесс через окно трансляции
BrowserWindow
примерwebContents.send
способ отправкиSHOW_MAIN_WINDOW
событие, проходactivityId
параметр - Процесс рендеринга окна запуска проходит через
ipcRenderer.on
мониторSHOW_MAIN_WINDOW
событие, прочитайте идентификатор активности и выполните процесс инициализации страницы
Таким образом, код на странице запуска может быть преобразован в:
const handleInit = (data)=>{
const { activityId } = data
init(activityId)
}
useEffect(() => {
ipcRenderer.on(EVENT.SHOW_MAIN_WINDOW, handleInit)
return ()=>{
ipcRenderer.removeListener(EVENT.SHOW_MAIN_WINDOW, handleInit)
}
}, [])
Таким образом, мы можем гарантировать, что инициализация каждой страницы запуска воспринимается и контролируется основным процессом.Здесь, когда логика страницы сложна, рекомендуется использовать метод события для управления инициализацией, что может избежать некоторых избыточных Требуется логика, такая как инициализация.
Конечно, если мы используем коммуникацию процесса, нам также нужно обратить внимание при использовании слушателя, он не может быть прочитан в хуке.useState
а такжеredux
Последнее значение в , если нашей логике инициализации нужны какие-то дополнительные параметры на странице, рекомендуется использоватьuseRef
сохранить эту переменную вinit
пройти, когдаref.current
читать.
Суммировать
Когда мы разрабатываем проекты Electron, уровень пользовательского интерфейса может в основном повторно использовать опыт веб-разработки,BrowserWindow
По существу также загружается html.
Подводя итог, в Electron нам нужно разработать:
- страница в Интернете
- Управление отдельными окнами
- Связанные с приложением: панель меню, жизненный цикл (открытие и закрытие приложений и т. д.)