Статьи

Усовершенствованная конфигурация Pebble Watch

Для тех, кто смотрел Power Rangers в детстве и мечтал о модных часах, заставляющих их чувствовать себя супергероем, умные часы — воплощение мечты. Я могу быть одним из вышеупомянутых мечтателей Power Ranger. Объедините это с побуждениями разработчика, которые наполняют мои вены, и у вас есть ребенок 90-х, который скоро станет серым, безумным ученым, как доктор Эммет Браун из «Назад в будущее».

Недавно я написал статью об основах разработки Pebble Watch с использованием JavaScript . Таким образом, мы создали циферблат, который использовал API Foursquare, чтобы сообщать пользователю, где находятся его ближайшие Starbucks. Вот как это выглядело в действии:

Приложение Find Me Starbucks в действии

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

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

Если вы хотите следовать этому уроку, вам понадобится:

  • Либо телефон Android, либо iPhone с установленным и запущенным приложением Pebble.
  • Часы Pebble .
  • Учетные данные API для API FourSquare .
  • Доступная сеть Wi-Fi для переноса приложения на мобильное устройство и часы Pebble.
  • Базовые знания JavaScript.
  • Готовность использовать командную строку и экспериментировать с кодом Си.
  • Желательно, чтобы пройти предыдущий учебник или иметь знания об основах разработки приложений Pebble с помощью JavaScript-фреймворка PebbleKit.
  • Интернет-хостинг для хранения одного файла в сети, который будет вашей страницей конфигурации.

Полный код для этого урока

Вместо того, чтобы добавлять весь код из нашего последнего урока в эту статью, вы можете проверить код «Find Me Starbucks» на GitHub или прочитать предыдущий урок . Код для нашего обновленного приложения также доступен на сайте «Найди меня что-нибудь» на GitHub , так что, если вы хотите загрузить код и следить за ним — не стесняйтесь!

Как работает конфигурация в мире приложений Pebble

До появления PebbleKit JavaScript Framework в SDK версии 2.0 приложениям Pebble необходимо было установить на телефон пользователя сопутствующее приложение для принятия любых пользовательских настроек. Если пользователь хотел, чтобы приложение погоды показывало ему погоду в градусах Цельсия, а не в градусах Фаренгейта, ему сначала нужно было установить сопутствующее приложение и открыть его, чтобы изменить настройки (или иметь окно с грубыми настройками в самом приложении наблюдения).

Страница настроек с включенным JavaScript

С помощью нового SDK мы теперь можем определить страницу конфигурации, которая будет доступна в самом приложении Pebble для Android / iOS. Доступ к настройкам осуществляется в том же месте, что и место, куда пользователь отправляется для установки и организации своих часовых приложений. Чище и логичнее с точки зрения пользователя.

JavaScript включен локальное хранилище

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

Как это устроено

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

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

Обновите ваш appinfo.json

Во-первых, чтобы включить страницу настроек в вашем приложении, мы добавляем "configurable" в массив возможностей, который мы ранее использовали для определения доступа к API геолокации через ключевое слово "location" :

 "capabilities": ["location", "configurable"] 

Мы также добавляем еще один дополнительный ключ для нашего приложения для использования с именем "searchingFor" , это будет строка, которая будет либо «Starbucks», либо пользовательским типом местоположения, которое запрашивает пользователь:

 "appKeys": { "location": 0, "searchingFor": 1 } 

Создание страницы настроек

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

Экран настроек Find Me Anything

Основной HTML, который вам понадобится, выглядит следующим образом (для простоты я удалил разметку, связанную со стилем и фреймворком)

 <label for="searchingFor">Whatcha wanna find?</label> <textarea cols="40" rows="8" name="searchingFor" id="searchingFor"></textarea> <button type="submit" id="b-cancel">Cancel</button> <button type="submit" id="b-submit">Submit</button> 

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

Отмена или отправка настроек

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

Чтобы отменить их изменения, мы установили для document.location значение pebblejs://close . Это отправит пустой ответ на наш JavaScript-код Pebble, который ничего не изменит:

 $('#b-cancel').click(function() { document.location = 'pebblejs://close'; }); 

Если они решают отправить свои изменения, мы передаем входные данные из текстовой области в строку. Функция saveOptions() ниже помещает значение из текстовой области в объект:

 function saveOptions() { var options = { searchingFor: $('#searchingFor').val() } return options; } 

Наша функция click передает наши данные, превращая объект в строку и кодируя его символы, чтобы мы могли поместить его в URL-адрес, на который мы нацелены с document.location (любые пробелы будут закодированы в %20 , любые другие специальные символы также изменятся ):

 $('#b-submit').click(function() { var location = 'pebblejs://close#' + encodeURIComponent(JSON.stringify(saveOptions())); document.location = location; }); 

Это успешно отправит нужные нам настройки в Pebble JavaScript.

Что, если пользователь уже что-то выбрал?

Если пользователь уже внес изменения в настройки, скажем, он уже попросил приложение найти их gelato вместо этого, мы хотим, чтобы его предыдущая настройка «gelato» отображалась в текстовом поле при открытии настроек. Для этого мы отправим на страницу конфигурации HTML переменную в URL с именем searchingFor . Примером этого может быть URL http://www.yourpebbleappsettingpage.com?searchingFor=gelato .

У меня есть функция, которую я нашел давным-давно, и я довольно часто использую ее для получения переменных из URL:

 function getURLVariable(name) { name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]"); var regexS = "[\\?&]"+name+"=([^&#]*)", regex = new RegExp(regexS), results = regex.exec(window.location.href); if (results == null) return ""; else return results[1]; } 

Когда страница готова, мы проверяем переменную и помещаем текст этой переменной в наше текстовое поле. Переменная декодируется так, что любые символы, отформатированные для работы в строке URL, будут правильно отображаться в текстовой области. Для этого мы используем decodeURI() . Это превратит наши %20 и другие специальные символы обратно в их действительные символы для отображения:

 $(document).ready(function() { var priorSearch = getURLVariable('searchingFor'); priorSearch = decodeURI(priorSearch); if (priorSearch) { $('#searchingFor').html(priorSearch); } 

Не стесняйтесь стилизовать этот экран, чтобы сделать его красивым и захватывающим! Вы можете структурировать и стилизовать его так, как вам нравится, поскольку это плоская HTML-страница. На странице настроек примера Pebble использовался jQuery Mobile, поэтому я остановился на этом и просто изменил стиль, чтобы сделать его более аккуратным. Используйте любую интерфейсную среду или валидацию JavaScript, которая вам нужна. Сила твоя!

Настройка нашего JavaScript для принятия настроек

Наше приложение Pebble знает, что мы хотим разрешить изменение настроек, мы сказали это в нашем файле appinfo.json . У нас даже есть хорошая страница конфигурации для нашего приложения, которая выглядит многообещающей. Проблема в том, что наше приложение Pebble не знает, где найти этот экран конфигурации, мы его обещали. Он даже не знает, где мы хотим использовать этот searchingFor Часть данных, которые мы отправляем туда и обратно, — только то, что мы намереваемся получить. Здесь мы обновляем наш файл pebble-js-app.js чтобы соединить все.

Для начала нам понадобится новая переменная в нашем JavaScript. Давайте назовем его appinfo.json чтобы он соответствовал нашему ключу в файле appinfo.json (не обязательно называть его одинаковым, но для последовательности и ясности я так и сделал). Эта переменная должна будет сохранять предпочтения пользователя по типу местоположения, которое мы будем искать, пока они занимаются повседневной улучшенной жизнью Pebble.

Веб-хранилище в приложениях Pebble

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

 window.localStorage.setItem('ourVariableName', 'Our variable contents'); 

Чтобы получить его:

 window.localStorage.getItem('ourVariableName'); 

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

Мы рассмотрим наше локальное хранилище в тот момент, когда запускается наш JavaScript. Если он не находит наши данные для searchingFor в локальном хранилище, тогда мы устанавливаем значение по умолчанию «Starbucks». Это аккуратно размещено после определения locationOptions в начале файла pebble-js-app.js .

 var locationOptions = {timeout: 15000, maximumAge: 60000}, searchingFor = window.localStorage.getItem('searchingFor') ? window.localStorage.getItem('searchingFor') : 'Starbucks'; 

Затем мы добавляем эту переменную в наш запрос AJAX вместо упоминания Starbucks:

 req.open('GET', 'https://api.foursquare.com/v2/venues/search?client_id='+clientId+'&client_secret='+clientSecret+'&v='+version+'&ll='+latitude+','+longitude+'&query='+searchingFor, true); 

Пока наше приложение будет делать то же самое, что и раньше — найти нас Starbucks. Нам нужно сообщить ему, что делать, когда пользователь нажимает кнопку «Настройки» для вашего приложения. Мы делаем это с помощью showConfiguration событий showConfiguration :

 Pebble.addEventListener('showConfiguration', function() { Pebble.openURL('http://www.patrickcatanzariti.com/find_me_anything/configurable.html?searchingFor=' + searchingFor); }); 

Это приведет пользователя на вашу страницу с формой для заполнения этих настроек. Когда они отправят свои новые настройки (например, «gelato», как упомянуто выше), мы хотим, чтобы наш JavaScript в pebble-js-app.js был готов и ждал этих данных.

Для этого мы используем webviewclosed событий webviewclosed . Здесь мы декодируем его обратно из нашей строки URI (кодированная версия с %20 для пробелов и тому подобное) и снова анализируем его в объект JSON. Мы получаем значение searchFor из этого объекта JSON и кодируем его еще раз, теперь оно выходит из нашей строки JSON. Этот последний бит кодирования сохраняет его готовым для помещения в строку URL для вызова API Foursquare, обсуждавшегося ранее ( https://api.foursquare.com/v2/venues/search?client_id='+clientId+'&client_secret='+clientSecret+'&v='+version+'&ll='+latitude+','+longitude+'&query='+searchingFor request):

 Pebble.addEventListener('webviewclosed', function(e) { var options = JSON.parse(decodeURIComponent(e.response)); searchingFor = encodeURIComponent(options.searchingFor); 

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

 if (searchingFor == 'undefined') { searchingFor = 'Starbucks'; } 

После того как запрос searchFor понят и готов к хранению, мы сохраняем его в локальном хранилище с помощью функции window.localStorage.setItem() упомянутой выше. Таким образом, он все еще будет там в следующий раз, когда они откроют приложение.

 window.localStorage.setItem('searchingFor', searchingFor); 

Теперь, когда мы получили новый запрос на установку, мы снова запускаем window.navigator.geolocation.watchPosition() с нашим новым значением. Это запустит наш поиск по геолокации в API Foursquare с их новыми запрошенными настройками в момент закрытия окна настроек.

 locationWatcher = window.navigator.geolocation.watchPosition(fetch_location_data, fetch_location_error, locationOptions); }); 

Наш JavaScript теперь понимает эту новую настройку, но есть еще кое-что сделать.

Несколько дополнений к нашему C-коду

Наш файл find_me_anything.c не нужно слишком сильно менять. Я сделал следующие дополнения и изменения.

Увеличение размера буфера сообщений

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

Изменение было сделано в начале файла, когда был определен sync_buffer :

 static AppSync sync; static uint8_t sync_buffer[124]; 

Это также было изменено в нашей функции init() когда мы открываем синхронизацию сообщений:

 app_message_open(124, 124); 

Добавление нового ключа в наше приложение

Нам также нужно добавить наш новый ключ, который будет передаваться между Pebble JavaScript и кодом C: параметр searchingFor . В коде C я следовал соглашению и использовал заглавные буквы с подчеркиванием для выделения слов. Мы определяем 1 как 0x1 в шестнадцатеричном формате, что означает, что теперь мы можем ссылаться на SEARCHING_FOR при упоминании второй пары ключ / значение в нашем коде C:

 enum { OUR_LOCATION = 0x0, SEARCHING_FOR = 0x1 }; 

Я обновил init_location_search() чтобы она определяла наше начальное значение для значения SEARCHING_FOR как '' . Это поле пустое, так как оно будет заполнено, как только наш JavaScript включится и сообщит C о том, что мы ищем.

 Tuplet initial_values[] = { TupletCString(OUR_LOCATION, "Loading..."), TupletCString(SEARCHING_FOR, "") }; 

Наконец, мы обновляем нашу sync_tuple_changed_callback() чтобы она знала, что ответить, когда получит обновленную вторую пару ключ / значение. Когда это произойдет, все, что нам нужно, чтобы сделать код C, это изменить метку на часах, чтобы сказать «Ближайшее мороженое» или что-то новое, вместо «Ближайшие Starbucks»:

 switch (key) { case OUR_LOCATION: text_layer_set_text(text_layer, new_tuple->value->cstring); break; case SEARCHING_FOR: text_layer_set_text(label_layer, new_tuple->value->cstring); break; } 

Теперь, когда все готово, вы сможете изменять настройки своего приложения с помощью окна конфигурации. Когда вы отправите свои настройки, приложение Pebble должно обновиться, и у вас будет настроенное приложение, например:

Найди меня Все работает

Дополнительное дополнение к нашему коду JavaScript

При реализации этой новой функции я обнаружил, что иногда API FourSquare на самом деле не имеет адреса или значений, которые нам нужны в каждом месте. В некоторых местах эти данные отсутствуют. Это возвращает «неопределенный», когда мы показываем его на часах. Не хорошо! Поэтому я переписал немного нашей функции req.onload чтобы проверить наши записи и использовать первую, которая имела адрес и город:

 if (response && response.meta.code == '200' && response.response) { var venues = response.response.venues, venue = undefined, venueIndex = 0; // Look for the first instance of a venue with an address while (venues[venueIndex] !== undefined && venue === undefined) { if (venues[venueIndex] && venues[venueIndex].location.address !== undefined && venues[venueIndex].location.city !== undefined) { venue = venues[venueIndex]; } venueIndex++; } if (venue && venue.location.address !== undefined && venue.location.city !== undefined) { Pebble.sendAppMessage(...); 

То, что я сделал выше, это установил переменную с именем venue которая начинается как undefined . Я перебираю каждый элемент в данных response.response.venues которые возвращаются из Foursquare, и если я нахожу тот, который включает адрес и город, то я сохраняю этот объект в venue и мы больше не ищем оставшуюся часть ответа.

Теперь мы немного более захватывающее приложение!

Благодаря возможностям PebbleKit JavaScript Framework мы позволяем владельцам часов Pebble самим решать, как они хотели бы использовать наше приложение. Это настроено и более личное. Мы также сейчас используем локальное хранилище, поэтому наше приложение может помнить вещи. Это гораздо более ценное приложение, чем раньше, и мы используем все возможности JavaScript на часах Pebble.

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

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

Другие ресурсы