Записки Junior-а: Extension Today в iOS 8

Усім привіт. З виходом версії iOS 8 компанія Apple анонсувала понад 4 000 нових API. Серед безлічі «смаколиків» я звернув увагу на технологію Extensions (розширення).
Ознайомившись в Інтернеті з величезною кількістю матеріалів про нову функцію, мені захотілося на практиці застосувати отримані знання — так би мовити, поєднати приємне з корисним.
Площу для експерименту я обрав одне з наших нових мобільних додатків, KeepSnap, яке наразі знаходиться в iTunes Connect на стадії перевірки та публікації в Apple App Store.
Було вирішено трохи розширити функціонал вже створеного додатка за рахунок використання Extension Today (іншими словами, віджета). Останній використовується для надання миттєвої інформації в Центрі Уведомлень. У моєму випадку, це або швидкий перехід фотографа на форму авторизації, або відображення його поточного балансу з проданих фотографій та активності сервісу геолокації.
Після узгодження алгоритму роботи та створення дизайн-макета майбутнього повідомлення я приступив до роботи.
Саме тут починається все найцікавіше. Як виявилося, для реалізації цієї можливості мені потрібно було вирішити кілька завдань, ось деякі з них:
- Як дані передаються між основним додатком та його віджетом?
- Як повідомити основний додаток про події, що відбулися в віджеті?
- Як перейти до потрібного представлення (сторінки) в основному додатку по натисканню кнопки на віджеті?
- Як запустити основний додаток, що знаходиться у фоновому режимі?
Найпростішим завданням було розміщення готового віджета в Центрі Уведомлень. Налаштувати відображення віджета можна наступним чином: встановити додаток на свій смартфон, відкрити Центр Уведомлень, перейти на вкладку Today (Сьогодні), в нижній частині якої знайти та натиснути кнопку Edit (Змінити). З списку запропонованих для відображення віджетів вибрати потрібний, натиснувши на кнопку у вигляді зеленого плюса.
У даному представленні можна видаляти віджети, а також змінювати порядок їх відображення. Натиснувши на кнопку Ready (Готово), ми побачимо наш віджет серед інших, встановлених на iPhone.
Щоб втілити дизайн-макет свого віджета в працюючий додаток, я з готового шаблона Xcode 6 створив віджет Today і приступив до його оформлення в Storyboard. Шаблон автоматично створює UIViewController та візуальне представлення майбутнього віджета. Подальша робота зводиться до оперування стандартними об'єктами Interface Builder-а та створення посилань у вигляді IBOutlets та IBActions для відображення внесених змін, а також обробки дотиків користувача до екрана в місцях розташування активних елементів (кнопок).
Щоб відповісти на запитання про те, як дані передаються між основним процесом і віджетом (окремий процес), потрібно згадати про клас NSUserDefaults і застосувати його з невеликою модифікацією під нашу задачу. Для початку необхідно освоїти ще одну функцію iOS 8 під назвою App Group.
Вказана технологія дозволяє об'єднувати в групи програми, створені за допомогою однойменного сертифіката розробника. Всередині групи такі програми можуть обмінюватися даними навіть у випадку неактивності одного з них. У Target-і KeepSnap я створив групу com.stfalcon.KeepSnap, потім те саме повторив для Target-а KeepSnapToday. Тепер я отримав механізм, за допомогою якого мої дані можуть передаватися між процесами в обидва боки.
В коді додаю наступні рядки, щоб прочитати
NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.stfalcon.Keepsnap"]; NSString *userLogin = [defaults objectForKey:@"userLogin"];
або записати
NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.stfalcon.Keepsnap"]; [defaults setObject:widgetTaped forKey:kDefaultsWidgetTaped]; [defaults synchronize];
в пам'ять пристрою дані для обміну.
Аналогічний код використовую на стороні основного застосунку, щоб замкнути ланцюг подібних дій.
Щоб повідомити основному застосунку про події, що сталися у віджеті, необхідно застосувати технологію локальних сповіщень (клас NSNotifications). Алгоритм моїх дій такий: при натисканні кнопки на віджеті через App Group я зберігаю в пам'яті пристрою нове значення змінної, яка повинна повідомити основному застосунку про відбулася подію.
Щоб запустити основний застосунок з будь-якого іншого застосунку або віджета, необхідно налаштувати параметр URL Types на вкладці Info Target-а KeepSnap.
При обробці події IBAction при натисканні на кнопку віджета запускається на обробку наступний код:
NSURL *url = [NSURL URLWithString:@"keepsnap://"]; [self.extensionContext openURL:url completionHandler:nil];
Далі, в залежності від стану мого застосунку (не запущено, виконується, знаходиться у фоновому режимі) створення сервера сповіщень буде відбуватися або в методі application:openURL:sourceApplication:annotation: об'єкта AppDelegate, або в методі viewDidLoad класу KSPMainViewController. Якщо значення змінної з буфера обміну змінилося, формується розсилка відповідного сповіщення всім об'єктам, які підписані на його отримання. Таким чином, основний застосунок завжди буде знати про дії користувача, які він здійснює на відображенні віджета.
При обробці отриманого сповіщення про те, що користувач натиснув одну з 2-х можливих кнопок на віджеті, я виводжу на екран смартфона необхідне візуальне представлення — або форму авторизації (натиснення кнопки Please Sign In), або форму налаштувань робочих параметрів для фотографа (натиснення круглої кнопки Geolocation). Далі користувач працює в звичному штатному режимі мого застосунку :-).
Ось коротко про те, що таке віджети, навіщо вони потрібні та як їх можна реалізувати на моєму конкретному прикладі. Мені технологія дуже сподобалася — рекомендую до використання всім, хто хоче щось змінити у своєму додатку та додати йому нові можливості. До речі, це відмінний спосіб виділити свій додаток серед інших, встановлених на пристрої користувача. Головне, не навантажувати віджет різними обчисленнями, ресурсоємними процесами та видовищними ефектами. Мінімум необхідної інформації та дотримання вимог Apple дозволять вашому додатку зайняти свою нішу та виділитися на фоні конкурентів.
Моя стаття присвячена одному з 6-ти можливих Extensions — віджету Today. Буду радий у майбутньому поділитися з вами своїм новим досвідом у реалізації інших типів розширень.