Создание Today Extension для iOS 8

в 9:15, , рубрики: ios8, objective-c, swift, разработка под iOS

С выходом iOS 8 компания Apple представила новою концепцию под названием App Extensions, с помощью которой, Вы сможете делиться функциональностью Вашего приложения с другими приложениями, и из самой ОС.

Один из этих типов расширений являются Today Extensions, также известные как Widgets. Они предоставляют Вам возможность вводить информацию в Центр Уведомления, который является отличным способом предоставления самой актуальной информации, которой интересуется пользователь.

В этой статье, Вы напишете приложение на основе расширения Today Extension, которое представит текущую рыночную стоимость Bitcoin на основе доллара США.

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

Bitcoin / Биткойн

Для тех, кто еще не знаком с Bitcoin — это цифровая криптовалюта, которая еще находиться в периоде становления. Кроме использования его для одноранговых обменов и покупок, Bitcoin позволяет пользователю обменивать их на другие криптовалюты такие как Dogecoin и Litecoin или на доллары США или Евро.

Так как, это относительно новая валюта, ее рыночная стоимость колеблется поминутно; были как огромные пики так и спады за весь период ее существования. Таким образом, это — идеальный кандидат для Today Extension, так как инвесторы или покупатели захотят знать курс акций с точностью до секунды!

Crypticker

Поскольку Вы пишете расширение, для начала работы Вам понадобиться готовое приложение; что ж, пришло время познакомиться с Crypticker.

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

Расширение будет содержать все эти функции, но Вы не сможете увидеть цену в течение определенного дня, проведя пальцем по графику. Есть некоторые связи в Today Extensions, особенно когда дело доходит до использования жестов и многозадачности. Жест часто активируется проведением пальца между Today Extensions и Центром Уведомления, таким образом, не нужно иметь большой пользовательский опыт для ее выполнения.

Приступим к работе

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

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

image

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

Для тех, кто еще не знает BTC это сокращенная форма для Bitcoin; так же, как USD обозначает доллар США. Today Extension представит уменьшенную версию основного представления о Crypticker.

Теоретически, у приложения Crypticker есть возможность показать ценообразование для нескольких криптовалюта, но наше расширение предназначено только для BTC. Поэтому, оно называется BTC Widget.

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

К концу статьй, ваш Today Extension будет выглядеть примерно так:

image

Добавление Target Today Extension

Расширения созданы в виде отдельного двоичного файла, полученные от ихнего приложения-хоста. Таким образом, вы должны будете добавить target Today Extension к проекту Crypticker.

В Xcode в Project Navigato, выберите проект Crypticker и добавьте новый target, EditorAdd Target… Тогда выбираем iOSApplication ExtensionToday Extension. И жмем кнопку Next.

image

В Product Name впишите BTC Widget, и убедитесь, что языком программирования выбрат Swift, и что проект Embed in Application являются Crypticker. И нажимаем Finish.

image

При запросе нужно активировать схему BTC Widget. Поскольку текст указывает, что для Вас будет создана другая схема для запуска в Xcode.

Поздравляем! Теперь BTC Widget появится в Вашем списке targets.

image

Удостоверьтесь, что Вы выбрали BTC Widget, тогда вкладку «General», а затем нажмите кнопку +, которая находиться под строкой Linked Frameworks and Libraries. Как показано на рисунку:

image

Выберите CryptoCurrencyKit.framework и нажмите Add.

CryptoCurrencyKit – пользовательский фреймворк, который используеться приложением Crypticke для получения цен и валюты из сети. К счастью для Вас, невероятно добрый и вдумчивый разработчик Crypticker применил модульное проектирование для кода, превратив его в фреймворк, так, чтоб несколько targets могли его использовать.

В целях обмена данными между приложением-хостом и его расширениями необходимо использовать пользовательский фреймворк. Если Вы этого не сделаете, Вам нужно будет продублировать код много раз, и нарушить важное правило программной инженерии: DRY — или, Не повторяйся. Я повторю это снова: «Не повторяйся».

С этого момента, Вы можете приступить к реализации расширение.

Обратите внимание, теперь у Вас есть группа в Project navigator, названа именем вашего нового targeta, BTC Widget. Именно здесь код Today Extension находится по умолчанию.

Разверните группу, и Вы увидите контроллер представления, storyboard и файл Info.plist. Его целевая конфигурация также указывает ему загрузить свой интерфейс из MainInterface.storyboard, который содержит один контроллер представления с назначенным классом к TodayViewController.swift.

image

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

Фактически, жизненный цикл расширения отображается на жизненном цикле TodayViewController

Откройте MainInterface.storyboard и Вы увидите темно-яркий фон со светлой надписью «Hello World». Today Extensions имеют изображения наиболее высокой чёткости с светлым фоном и светлым или ярким цветным текстом, который прекрасно гармонирует с темным, размытым фоном Центра Уведомления/Notification Center.

Убедитесь, что выбран target BTC Widget на панели инструментов Xcode, скомпелированная и запущена. В результате чего появится окно с запросом разрешения на запуск приложения. Xcode спросит Вас, какое приложение-хост вы хотите запустить. Выберите Today. Это указывает на то что IOS откроет Центр уведомлений на панели Today, который в свою очередь запускает Ваш виджет. Центр уведомлений – это фактически приложение-хост для Today Extensions.

image

Это также позволяет Xcode использовать свой отладчик в процессе работы виджета.

image

Вот Ваш виджет. Круто, не так ли? Хотя это и суперзахватывающая штука, над виджетом еще нужно немножко поработать. Пришло время, сделать нечто интересное!

Примечание: Вы можете заметить много ошибок связанных с использование Auto Layout которые отобразаються в консоле при запуске виджета. Это — проблема с шаблоном в Xcode, и мы надеемся, что Apple решит ее в будущем. Хотя, Вы не волнуйтесь, поскольку у вас и так будет ваш собственный интерфейс, и возможность использовать Auto Layout.

Создаем интерфейс

Открываем MainInterface.storyboard и удаляем Label. Добавляем view размером 150 точек в высоту и 320 точек в ширину устанавливаем для нее в Size Inspector. Переместите Button, две Label и View из Object Library на контроллеры представления.

  • Разместите одну из lable в верхнем левом углу, и в Attributes Inspector установите Text в $592.12 и Color в Red: 66, Green: 145 and Blue: 211. Она покажет текущую рыночную цену.
  • Разместите другую Lable справа от той, которую Вы только что установили, но оставьте поле справа для кнопки. В Attributes Inspector установите Text до +1.23 и Color до Red: 133, Green: 191 and Blue: 37. Это покажет разницу между вчерашней ценой и текущей ценой.
  • Переместите кнопку к верхнему правому представлению, и в Attributes Inspector установите Image в caret-notification-center и удалите Title.
  • Наконец, поместите пустое view ниже двух lable и кнопки, растяните его так, чтоб нижний и боковые края касались содержания view и установите Height в 98. В Attributes Inspector установите Background как Clear Color, и в Identity Inspector установите Class — JBLineChartView.

Примечание: есть класс под названием JBLineChartDotView, который Xcode может предложить при наборе, убеждаясь, что Вы выбрали JBLineChartView.

Ваше View и Document Outline должны выглядеть примерно так:

image

Примечание: View представленное в белых тонах в целях видимости в этой статье. У Вашего view фактически будет темно-серый фон, который моделирует, как Ваше view будет появляться в Центре Уведомлени.

Не волнуйтесь о том, в каком порядке все это расположено, поскольку скоро Вы будете добавлять Auto Layout, чтобы должным образом определить расположение.

Теперь разверните группу Crypticker в Project Navigator и выберите Images.xcassets. В File Inspector, добавьте предметной каталог к target расширения, установив флажок слева от BTC Widget.

Это заставляет Xcode включить каталог графических ресурсов из target Crypticker в Вашу target Widget; именно здесь находится caret-notification-center image, которое Вы использовали для своей кнопки. Если у Вас есть одинаковые графических ресурсов между Вашим контейнерным приложением и виджетом, то это — хорошая идея использовать специальный каталог, который содержит только ресурсы, которыми можно будет поделиться. Это уменьшит чрезмерное увеличение размера в Ваших окончательных комплектах расширений, не включая изображения, которые не используются.

image

Вернитесь к MainInterface.storyboard и откройте Assistant Editor. И убедитесь, что TodayViewController.swift является активным файлом. Добавьте следующий код в верхнюю часть файла:

import CryptoCurrencyKit

Это Вы сделали импорт фреймворка CryptoCurrencyKit.

Затем, Вы должны обновить объявление класса, которое должно выглядеть таким образом:

class TodayViewController: CurrencyDataViewController, NCWidgetProviding {

Это приведет к тому, что TodayViewController станет подклассом CurrencyDataViewController, и обеспечит, что бы он соответствовал протоколу NCWidgetProviding.

CurrencyDataViewController входит в CryptoCurrencyKit и также используется в качестве основного представления в Crypticker. Поскольку виджет и приложение будет показывать подобную информацию через UIViewController, имеет смысл поместить повторно используемые компоненты в суперкласс, затем разделить их на подклассы, поскольку установленные требования варьируются.

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

Зажмите Ctrl и переместите с кнопки в наш класс, чуть ниже объявления класса. В появившемся диалоговом окне убедитесь, что Connection выбран как Outlet, Type выбран как UIButton, и введите toggleLineChartButton в поле Name. Нажмите Connect.

image

Тогда зажмите ctrl и переместите с кнопки на нижнюю часть класса на этот раз. В появившемся диалоговом окне измените Connection на Action, установите Type в UIButton и введите toggleLineChart в строку Name. Нажмите на Connect

image

TodayViewController разделяет на подклассы CurrencyDataViewController, у которого есть выходы для ценовой lable, leble изменения цен и отображения линейной диаграммы. Теперь Вам нужно их подключить. В Document Outline, зажмите ctrl и переместите от Today View Controller к price label (с установленным текстом к 592.12$). Выберите priceLabel из всплывающего окна, чтобы создать соединение. Повторите все это для другой lable, выбрав priceChangeLabe из всплывающего окна. Наконец, сделайте то же самое для Line Chart View, выбрав lineChartView из всплывающего окна…

image

Auto Layout

Для того, чтобы Ваш виджет был адаптивным, вам необходимо установить Auto Layout связи. Новые связи, вышедшие с iOS 8, являются концепцией Adaptive Layout. Общая идея состоит в том, что представление, разработанное с единственным расположением, может работать на различных размерах экрана. Представление считается адаптивным, когда оно может адаптироваться к неизвестным будущим метрическим значениям устройства.

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

Выберите Lable $ 592,12, а затем выберите EditorSize to Fit Content. Если опция Size to Fit Content отключена в меню, отмените выбор Lable, а затем выберите ее снова и попробуйте еще раз; иногда Xcode может немного работать с перебоями. Далее, используя кнопку Pin внизу рабочей области storyboard, установите для Top и Leading приоритет в значении 8 и 16 соответственно. Убедитесь, что Constrain to margins выбран.

image

Выберите Lable +1.23 и снова выберите EditorSize to Fit Content. Затем, используя кнопку Pin, выберите связь Top и Trailing, и в свойствах установите значение 8.

image

Выберите Button, и с помощью кнопки Pin установите приоритет для Top и Trailing в значении 0, и для Bottom в значении 8. Width и Height до 44. Убедитесь, что Constrain to margins выключен.

image

Вам необходимо понизить приоритет нижней привязки для кнопки. Выберите кнопку, а затем откройте Size Inspector. Найдите Bottom Space to: связь в списке связей, нажмите нажмите кнопку Edit и измените его Priority на 250.

Снижая приоритет, Вы позволяете системе Auto Layout изменить эту привязку, если он сочтет это необходимым. 250 является произвольным значением, которое, оказывается, меньше чем 1000, именно такой приоритет установлен на всех привязках по умолчанию. Эта привязка должна измениться, как только виджет будет находиться в свернутом состоянии. Имея различные уровни приоритетов в привязках, Вы подскажите системе, какие связи нужно изменить первыми или последними, когда возникает конфликт.

image

Наконец, выберите Line Chart View. С помощью кнопки Pin, выберите Leading, Trailing and Bottom и в свойствах установите значение 0, а высоту в 98.

image

Из Document Outline выберите представление контроллеров View, а затем EditorResolve Auto Layout IssuesAll ViewsUpdate Frames. Это позволит устранить любые Auto Layout предупреждения в рабочих областях путем обновления фреймов, чтобы соответствовать правильным привязкам. Если Update Frames выбран, тогда, Вы сделали все так, как нужно, и нет необходимости для запуска приложения.

Так как все ваши привязки находятся на своем месте, последним шагом является создания выхода для привязки высоты представления линейной диаграммы. Найдите Line Chart View в Document Outline и щелкните по треугольнику для раскрытия.

Тогда щелкните по треугольнику для Constraints, чтобы найти необходимую привязку для высоты. Выберите ее, и затем переместите ctrl+drag в Assistant Editor, расположив чуть ниже другого outlet. В сплывающем окне удостоверьтесь, что Connection выбрано Outlet, и введите lineChartHeightConstraint для Name. Нажмите Connect.

image

Реализация TodayViewController.swift

Теперь интерфейс находится на своем месте и что было необходимо настроенно, откройте файл TodayViewController.swift выбрав его в Standard Editor.

Вы заметите, что Вы работаете с стандартным подклассом UIViewController. Комфортно, не так ли? Хотя позже Вы столкнетесь с новым методом widgetPerformUpdateWithCompletionHandler из протокола NCWidgetProviding. Вы узнаете больше о нем к концу этой статьи.
Этот контроллер представления ответственен за отображение текущей цены, разницу в цене, за нажатие кнопки и показ ценовой истории на линейной диаграмме.

Определите свойство в верхней части TodayViewController, которое Вы будете использовать для отслеживания, если линейная диаграмма будет отображаться или нет:

var lineChartIsVisible = false

Теперь замените метод viewDidLoad() следующей реализацией:

override func viewDidLoad() {
  super.viewDidLoad()
  lineChartHeightConstraint.constant = 0
 
  lineChartView.delegate = self;
  lineChartView.dataSource = self;
 
  priceLabel.text = "--"
  priceChangeLabel.text = "--"
}

Этот метод выполняет следующие действия:

  1. Устанавливает высоту для линейной диаграммы «height constraints» в значение 0, так, чтобы это было умолчанию.
  2. Устанавливает self в качестве источника данных и делегата для представления линейной диаграммы.
  3. Устанавливает некоторый placeholder текст на двух Lables.

Оставайтесь в TodayViewController, и добавьте следующий метод:

override func viewDidAppear(animated: Bool) {
  super.viewDidAppear(animated)
 
  fetchPrices { error in
    if error == nil {
      self.updatePriceLabel()
      self.updatePriceChangeLabel()
      self.updatePriceHistoryLineChart()
    }
  }
}

Метод fetchPrices определяется в CurrencyDataViewController, и является асинхронным вызовом, который принимает завершения блока. Метод выполняет запрос к веб-сервису, упомянутый в начале статьй, чтобы получить информацию о цене на Bitcoin.

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

Благодаря конструкции виджета, Вы также должны реализовать widgetMarginInsetsForProposedMarginInsets для предоставления вкладок настраиваемых полей. Добавьте следующий код к TodayViewController:

func widgetMarginInsetsForProposedMarginInsets
  (defaultMarginInsets: UIEdgeInsets) -> (UIEdgeInsets) {
    return UIEdgeInsetsZero
}

По умолчанию, виджеты имеют большое поле, которое установлено во многих виджетов Apple, по умолчанию. Если Вы хотите заполнить всю ширину Центра Уведомления, то Вам необходимо реализовать этот метод и вернуть UIEdgeInsetsZero, который определяет значение 0 для всех сторон.

Теперь пришло время посмотреть, что у Вас вышло. Выберите схему BTC Widget. Скомпилируйте и запустите расширение. Выберите Today в качестве приложение для запуска при запросе.

  • Если Центр Уведомления не появляется, проведите вниз от верхней части экрана, чтобы активировать его.
  • Если виджет не появится в Центре Уведомления, Вам нужно добавить его через меню Edit. В нижней части представления контента Today Вы сможете увидить кнопку Edit. Нажмите кнопку, чтобы раскрыть меню всех расширений Today Extensions, которые установлены в системе. Здесь Вы можете включить, отключить и переупорядочить их по своему желанию. Включите BTC Widget, если еще не сделали это.

image

Круто, не так ли?! Ваш виджет теперь отображает в режиме реального времени цены на Bitcoin прямо в Центре Уведомления. Но Вы, наверное, заметили одну проблему; кнопка не работает, и Вы не видите диаграмму.

image

Затем Вам нужно реализовать метод toggleLineChart для кнопки, которую Вы добавили так, чтобы она развернула представление виджета и представила диаграмму. Как следует из названия метода, эта кнопка будет исполнять роль переключателя; это также свернет представление, чтобы скрыть диаграмму.

Замените пустой метод toggleLineChart следующим кодом:

@IBAction func toggleLineChart(sender: UIButton) {
  if lineChartIsVisible {
    lineChartHeightConstraint.constant = 0
    let transform = CGAffineTransformMakeRotation(0)
    toggleLineChartButton.transform = transform
    lineChartIsVisible = false
  } else {
    lineChartHeightConstraint.constant = 98
    let transform = CGAffineTransformMakeRotation(CGFloat(180.0 * M_PI/180.0))
    toggleLineChartButton.transform = transform
    lineChartIsVisible = true
  }
}

Этот метод управляет постоянным значением высоты привязки Line Chart View, чтобы изменять размеры окна. Он также применяет преобразование развёртывания к кнопке, таким образом, точно отображая видимость диаграммы.

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

Вы можете сделать это в метоже viewDidLayoutSubviews, добавив его в TodayViewController:

override func viewDidLayoutSubviews() {
  super.viewDidLayoutSubviews()
  updatePriceHistoryLineChart()
}

Убедитесь, что выбрана схема BTC Widget, скомпилируйте и запустите приложение. Тогда выберите Today в качестве приложение для запуска при запросе.

Слева, Вы увидите, как появляется виджет, когда диаграмма скрыта. Справа, Вы увидите, как он отображается, когда мы «раскрыли» виджет. Здорово, правда же!

image

Быстрое изменим цвет линии, и у Вас будет один виджет. Добавьте следующее к TodayViewController:

override func lineChartView(lineChartView: JBLineChartView!,
  colorForLineAtLineIndex lineIndex: UInt) -> UIColor! {
    return UIColor(red: 0.17, green: 0.49,
      blue: 0.82, alpha: 1.0)
}

Убедитесь в правильности схемы, которая по-прежнему выбрана. Скомпилируйте и запустите приложение. Выберите Today в качестве приложение для запуска при запросе.

image

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

Замените существующую реализацию метода widgetPerformUpdateWithCompletionHandler следующим кодом:

func widgetPerformUpdateWithCompletionHandler(completionHandler: ((NCUpdateResult) -> Void)!) {
  fetchPrices { error in
    if error == nil {
      self.updatePriceLabel()
      self.updatePriceChangeLabel()
      self.updatePriceHistoryLineChart()
      completionHandler(.NewData)
    } else {
      completionHandler(.NoData)
    }
  }
}

Этот метод выполняет следующие действия:

  • Он извлекает текущие ценовые данные из веб-службы, вызывая fetchPrices.
  • Если нет ошибок, интерфейс постоянно обновляется.
  • Наконец — и в соответствии с требованиями протокола NCWidgetProviding — функция вызывает поставляемый в составе системы блок завершения с .NewData enumeration.
  • В случае ошибки блок завершения вызывают с помощью .Failed enumeration. Это сообщает системе, что новые данные не доступны, и существующий снимок должен быть использован.

И вот, мы завершили создавать Ваше расширение Today Extension! Вы можете загрузить заключительный проект здесь.

И что же дальше?

Центр Уведомления в iOS 8 это — Ваша собственная персональная игровая площадка! Виджеты были доступны в некоторых других мобильных операционных системах в течение многих лет, а теперь и Apple наконец предоставил Вам возможность создавать их.

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

Если Вы хотите больше узнать о создании других типов расширений IOS 8 App Extensions, читайте нашу книгу iOS 8 by Tutorials, где Вы можете узнать о Photo Extensions, Share Extensions, Action Extensions и о многом другом!

Мы не можем дождаться, чтобы увидеть, что Вы придумаете, и надеемся, что ваши Today Extensions будут в топе наших Центров Уведомлений в ближайшее время!

Автор: yarmolchuk

Источник

Поделиться

* - обязательные к заполнению поля