Представьте, что ваш мессенджер, так любимый пользователем, отправляется в фоновый режим и там «засыпает». Как ему принять звонок, будучи не подключенным к серверу? Ответ как раз и заключается в пуше – сообщение «будит» приложение, оно переходит в активный режим и уже может принять звонок.
В iOS существует несколько способов пробудить приложение и передать ему контроль над происходящим.
Есть UILocalNotification – отложенные уведомления, привязанные к определенному моменту в будущем. Поскольку мы не знаем, когда поступит звонок, работать с UILocalNotification для организации телеконференций невозможно.
Есть извлечение данных в фоновом режиме (Background fetch), описываемое UIBackgroudnModes. Оно также привязывается ко времени и может будить приложение для скачивания и обновления данных в нужный момент времени. Так как мы не можем указать точное время звонка, фоновое пробуждение работать со звонками тоже не может.
Будить приложение можно удаленными уведомлениями. Если вы делаете свой проект, то включается эта возможность в закладке проекта “Capabilities” в Xcode, там есть раздел “Background Modes” и опция “Remote notifications” (также можно включить ключ UIBackgroundModes со значением “remote-notification” в Info.plist).
В самом уведомлении необходимо сделать ключ content-available со значением 1:
{
"aps" : {
"content-available" : 1
},
"content-id" : 42
}
только тогда приложение проснется (или запустится) и вызовет метод application:didReceiveRemoteNotification:fetchCompletionHandler. Как раз в нем вы можете уже реализовать нужный функционал.
- (void) application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
NSLog(@"Remote Notification userInfo is %@", userInfo);
NSNumber *contentID = userInfo[@"content-id"];
// Do something with the content ID
completionHandler(UIBackgroundFetchResultNewData);
}
В этом обработчике вы можете загрузить нужный контент, подключиться к серверу и, например, проверить наличие вызовов (для работы с пушами рекомендую статью “Уведомления в iOS 10” от e-Legion, в котором рассмотрены вопросы более подробно).
Apple для VoIP приложений рекомендует пробуждение как раз через UIBackgroundModes, но, конечно, не по времени, а по прослушиванию входящего трафика. Мессенджер в фоне мониторит определенный сокет и при появлении в нем трафика вызывает обработчик, запускающий нужные процедуры.
Пуши Voximplant для iOS основаны как раз на VoIP варианте. Для работы нужно:
1. Подписаться на уведомления при старте приложения:
PKPushRegistry *voipRegistry = [[PKPushRegistry alloc] initWithQueue:dispatch_get_main_queue()];
voipRegistry.delegate = self;
voipRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP];
2. Обработать входящие сообщения и передать входящий токен в SDK:
- (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(PKPushType)type {
// 'self.sdk' is an instance of the 'VoxImplantSDK'
[self.sdk registerPushNotificationsToken:credentials.token];
}
3. После получения пуша, если приложение не подключено к облаку Voximplant, нужно переподключиться и получить входящий звонок:
- (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(PKPushType)type {
NSDictionary* custom = [[payload.dictionaryPayload objectForKey:@"aps"] objectForKey:@"voximplant"];
if (custom) {
// This call notifies Voximplant cloud that notification is successfully received.
[self.sdk handlePushNotification:payload.dictionaryPayload];
}
}
Пуши – мощное средство удаленного общения с приложением, а не просто средство показывать пользователю информацию о том, что чужаки разграбили его ферму. Это возможность получать информацию в фоновом режиме, «включать» приложение по звонку, обновлять пользовательские данные. В конечном счете все это – средства удобной работы и вовлечения пользователей в работу приложения.
Иллюстрация до ката: www.davidrevoy.com
Комментарии (15)
Tereks
15.03.2017 12:16+1Так если у вас VOIP приложение, зачем вам пуши? Слушайте себе сокет и стартуйте сервис по запросу извне.
aylarov
15.03.2017 12:27+2В iOS это больше не работает
creker
15.03.2017 13:55Не совсем. Все работает при компляции с SDK 9.x и ниже — оставлено в целях совместимости, потому что нельзя просто отключить что-то, что раньше всегда работало. Более того, можно компилировать на SDK 10.x, а потом пропатчить заголовок бинарника, где как раз указана версия SDK. В итоге и старое поведение работает, и SDK свежий используется. Методы все эти рабочие и последний даже есть вероятность, что в AppStore сможет попасть.
aylarov
15.03.2017 13:56-1Как вы думаете зачем в Apple решили сделать не так как раньше? Вряд ли от нечего делать :)
creker
15.03.2017 14:02Я прекрасно понимаю, зачем они это сделали, и новое поведение даже выглядит более правильным. Но здесь есть и другая сторона — внезапно они оставляют часть разработчиков за бортом без всякой альтернативы. На форумах эпл уже начитался людей, чьи приложения просто не могут обращаться на push сервера и что-то оттуда качать. И сейчас им говорят очень просто — их кейс более не поддерживается и им нужно решать вопрос самостоятельно. Уговаривать клиентов пропустить трафик на чужой сервер. Там же посоветовали первый способ. Если речь об in-house приложениях, то это отличный вариант. Остается только вопрос, будет ли эпл полностью удалять старое поведение из iOS, ведь это сломает приложения.
aylarov
15.03.2017 17:16iOS 11 прекратит поддержку 32 битных приложений, прогресс не остановить
creker
15.03.2017 17:20+3Это не прогресс, когда функциональность становится хуже. Новое решение не покрывает те задачи, которые решало прошлое.
IvanVorobei
15.03.2017 18:12-1ну тогда и электромобили — не прогресс, и вообще FlashPlayer это, оказывается, было добро.
creker
15.03.2017 18:39+2Мимо по обоим аналогиями. Электромобили не запрещают продажу всех остальных автомобилей и даже если бы запретили, то полностью покрывают их функциональность. FlashPlayer заменен целым ворохом современных технологий.
Что было — открытый приложением сокет в фоне, можно работать полностью в изолированной сети без подключения к серверам эпл и вообще интернета. Стало — подключения в фоне запрещены, приложение пробуждается только через push уведомление, что требует доступа в интернет к серверам эпл.
Налицо ухудшение функциональности. Да, старый вариант хуже в плане энергопотребления и именно по этой причине его сменили. Но новый вариант так же и не умеет того, что умел старый, а значит некоторые виды приложений теперь просто невозможно (!!) написать честными прямыми способами. Нужно извращаться с версиями сдк и патчингом бинарников и неизвестно еще, сколько это будет работать, потому что эпл не предоставила решения тех проблем, о которых она не подумала, выпиливая старый функционал, но уже поспешила все отключить.
Krizai
20.03.2017 22:47Насколько помню «content-available» перестают обрабатываться ( система перестает будить приложение), если пользователь умышленно прибил его.
Krat0S
21.03.2017 21:02Есть извлечение данных в фоновом режиме (Background fetch), описываемое UIBackgroudnModes. Оно также привязывается ко времени и может будить приложение для скачивания и обновления данных в нужный момент времени.
К сожалению и даже в этом случае все непросто.
iOS оптимизирует свои процессы, отслеживает как часто пользователь обращается к приложению и подгадывает фоновую загрузку данных к этим моментам.
Столкнулись с этим во время написания корп.приложения для трекинга мобильных сотрудников в рабочее время.
Пришлось реализовывать довольно хитрый сценарий, чтобы каждые 10 минут в фоне получать геопозицию и отправлять её на сервер.
muzzle
Разве публикация картинки без указания авторства не нарушает лицензию CC?
Автор David Revoy.
eyeofhell
Справедливо, дописал в конце attribution