Статьи

Создание мобильного JavaScript-плеера

Как некоторые из вас могут знать, я зависим от HTML5 и JavaScript API.

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

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

JavaScript API Powered Audio Player

В этом уроке я буду использовать следующие API:

  • Ambient Light API для изменения темы веб-страницы в зависимости от уровня освещенности окружающей среды.
  • Proximity API для воспроизведения / паузы аудио в зависимости от близости объекта.
  • API состояния батареи для определения уровня заряда батареи и автоматической приостановки звука при критическом низком заряде батареи.
  • API веб-уведомлений для уведомления пользователя о том, что батарея разряжена и что из-за этого звук был приостановлен.
  • Vibration API для обеспечения тактильной обратной связи, которая усиливает уведомляющее сообщение, описанное выше.

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

Эта демонстрация будет использовать собственный audio HTML5 для воспроизведения аудио без какой-либо библиотеки в качестве запасного варианта. Тем не менее, сообщение будет отображаться, если браузер не поддерживает аудио element .

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

Создание разметки

Демо-версия состоит из одной HTML-страницы с очень простой разметкой. Он состоит из краткого описания эксперимента и audio с включенными нативными элементами управления (атрибут controls ). На странице есть link и элемент script . Первый относится к файлу CSS (обсуждается в следующем разделе), содержащему блоки объявлений для определения трех разных тем (подробнее об этом в следующем разделе). Последний указывает на файл JavaScript, содержащий бизнес-логику эксперимента.

Как видно из приведенного ниже кода, элемент body имеет предопределенное значение атрибута class для normal-theme . Он представляет тему по умолчанию, которая используется в нормальных условиях освещения.

Полный код HTML-страницы приведен ниже:

 <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>Mobile Audio Player</title> <meta name="description" content="APIs-powered Audio Player"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="css/main.css"> </head> <body class="normal-theme"> <h1>APIs-powered Audio Player</h1> <p> This demo shows how to create a simple APIs-powered audio player. In particular this page uses the Proximity API, the Battery Status API, the Vibration API, the Web Notifications API, and the Ambient Light API. </p> <audio id="audio" src="http://freshly-ground.com/data/audio/mpc/20090119%20-%20Untitled%20Groove.mp3" controls> <p>I'm sorry but your browser doesn't support the <code>audio</code> element, so you can't run the demo.</p> </audio> <script src="js/main.js" async></script> </body> </html> 

Темы игрока

CSS-файл эксперимента очень прост и короток. Он определяет несколько правил для элемента body и три темы: dark-theme , normal-theme и light-theme . Каждая из этих тем определяет цвет для фона и одну для текста страницы.

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

Полный код CSS ниже:

 body { max-width: 600px; margin: 0 auto; font-size: 20px; padding: 0 1em; } .dark-theme { background-color: #000000; color: #FFFFFF; } .normal-theme { background-color: #B8FFF7; color: #C53131; } .light-theme { background-color: #FFFFFF; color: #000000; } 

Бизнес логика

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

Первый шаг, который нам нужно выполнить, — это проверить поддержку API, которые мы планируем использовать, и сохранить результаты как свойства литерального объекта:

 var tests = { proximity: 'onuserproximity' in window, light: 'ondevicelight' in window, vibration: 'vibrate' in window.navigator, notification: 'Notification' in window }; 

Как вы видите, тест для Battery Status API отсутствует. Firefox реализует старую версию спецификаций, не основанную на Promise, поэтому мы будем рассматривать этот API как отдельный случай. В этой демонстрации я хотел поддержать обе версии, потому что Firefox — единственный браузер, который реализует все API, используемые в этом эксперименте. Я подумал, что важно иметь хотя бы один браузер, способный раскрыть все возможности демоверсии.

В дополнение к test переменной нам также понадобится переменная config определенная следующим образом:

 var config = { battery: { lowThreshold: 0.15, criticalThreshold: 0.05 }, vibration: { lowThreshold: [500, 200, 500], criticalThreshold: [1000] }, notification: { lowThreshold: { tTitle: 'Battery level: low', message: 'Please charge your device to avoid the audio to be automatically paused.' }, criticalThreshold: { title: 'Battery level: critical', message: 'The audio has been stopped to avoid the shutdown of your device.' } }, light: { darkThreshold: 50, normalThreshold: 10000 } }; 

Он содержит данные, которые мы будем использовать в сочетании с API-интерфейсами JavaScript. Например, мы определили пороговые значения для использования с API состояния батареи (под свойством battery ), чтобы указать, когда наше приложение будет считать уровень заряда батареи низким или критическим. Мы также определили шаблоны вибрации (под свойством vibration ), которые следует использовать, когда уровень заряда батареи низкий ( lowThreshold ) или критический ( criticalThreshold lowThreshold ). Наконец, мы определили свойства, которые будут использоваться с API веб-уведомлений (свойство notification ) и API Ambient Light (свойство light ), чтобы указать, когда мы будем считать уровень освещения низким и нормальным.

Последний шаг подготовки, который мы должны выполнить, — извлечь audio элемент. Это достигается с помощью следующего утверждения:

 var audio = document.getElementById('audio'); 

На данный момент мы готовы использовать API-интерфейсы JavaScript для предоставления суперспособностей нашему аудиоплееру. Первая функция, которую мы реализуем, — это жест для воспроизведения / приостановки звука. Если быть точным, мы не будем реализовывать настоящий жест. Достаточно поместить палец, руку или любой другой предмет достаточно близко к датчику приближения, чтобы воспроизвести / приостановить воспроизведение звука, но лучше назвать его «жестом».

Эта функция реализована с помощью следующего кода:

 if (tests.proximity) { window.addEventListener('userproximity', function (event) { if (event.near) { audio.paused ? audio.play() : audio.pause(); } }); } 

Легко, не правда ли? Еще одна простая функция, которую мы можем создать, — это переключение применяемой темы в зависимости от уровня освещенности среды. Прислушиваясь к изменению уровня освещенности, мы можем определить, находится ли он ниже определенного порога темноты ( darkThreshold ), между последним и нормальным порогом ( normalThreshold ) или выше нормального порога. После этого мы можем изменить тему соответственно. Превращение этого описания в код приводит к следующему фрагменту:

 if (tests.light) { window.addEventListener('devicelight', function(event) { var light = Math.round(event.value); if (light < config.light.darkThreshold) { document.body.className = 'dark-theme'; } else if (light < config.light.normalThreshold) { document.body.className = 'normal-theme'; } else { document.body.className = 'light-theme'; } }); } 

Теперь, когда у нас есть код для определения изменения уровня освещенности и определения «жеста» для воспроизведения / приостановки звука, мы должны реализовать функции, связанные с уровнем заряда батареи. Для этого мы должны прикрепить обработчик к событию levelchange и запустить тот же обработчик, как только приложение запустится. Если при запуске приложения уровень заряда батареи будет низким или критическим, мы сможем действовать соответствующим образом. Для этого мы определим функцию manageBattery() . Мы также определим версию API состояния батареи, поддерживаемую браузером, чтобы узнать, можем ли мы подключить обработчик напрямую или когда обещание будет выполнено.

Полученный код указан ниже:

 function manageBattery(battery) { // Code here... } if (window.navigator.getBattery) { window.navigator.getBattery().then(function(battery){ battery.addEventListener('levelchange', manageBattery.bind(window, battery)); manageBattery(battery); }); } else if (window.navigator.battery) { window.navigator.battery.addEventListener('levelchange', manageBattery.bind(window, window.navigator.battery)); manageBattery(window.navigator.battery); } 

Последний шаг — создание тела функции manageBattery() . Внутри этой функции мы должны выполнить следующие операции:

  1. Определить уровень заряда батареи (хороший, низкий или критический)
  2. Приостановить звук, если уровень заряда батареи является критическим
  3. Вибрация устройства с использованием другой схемы в зависимости от уровня заряда батареи (низкий или критический)
  4. Показывать разные уведомления о состоянии батареи в зависимости от ее уровня (низкий или критический)

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

 function manageBattery(battery) { if(!battery.charging && audio.duration > 0 && !audio.paused) { if (battery.level > config.battery.lowThreshold) { return; } var isCritical = battery.level <= config.battery.criticalThreshold; if (isCritical) { audio.pause(); } if (tests.vibration) { window.navigator.vibrate( isCritical ? config.vibration.criticalThreshold : config.vibration.lowThreshold ); } if (tests.notification) { Notification.requestPermission(function(permission) { if (permission !== 'denied') { new Notification( isCritical ? config.notification.criticalThreshold.title : config.notification.lowThreshold.title, { body: isCritical ? config.notification.criticalThreshold.message : config.notification.lowThreshold.message } ); } }); } } } 

С этим последним фрагментом мы закончили нашу демонстрацию, и теперь она готова к тестированию.

Код и живое демо

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

Вывод

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