Использование Hotspot Helper Extension

Автор: admin от 7-08-2017, 15:10, посмотрело: 234

В современном мире наличие публичного Wi-Fi в общественных заведениях считается само собой разумеющимся. Посещая кафе, торговые центры, отели, аэропорты, парки отдыха и многие другие места, мы сразу ищем заветный сигнал без пароля. А это бывает нелегко, поскольку, во-первых, точек в списке может оказаться несколько, а во-вторых, бесплатный Wi-Fi может быть запаролен, так что единственный выход — ловить сотрудника, который сможет указать на правильную сеть и назвать пароль. Но даже после этого случается так, что ничего не работает. Пользователь должен догадаться о том, что ему необходимо открыть браузер (причем еще вопрос, какую страницу следует загружать) и совершить дополнительные действия (авторизоваться, просмотреть рекламу, подтвердить пользовательское соглашение), прежде чем ему предоставят полноценный доступ в сеть.



Впрочем, сейчас многие популярные заведения предлагают приложения, облегчающие подключение к бесплатным точкам. Уверен, что каждый из нас сможет легко припомнить пару-тройку подобных примеров, поэтому обойдусь без названий и рекламы. Тем более что ниже пойдет речь о другом варианте решения этой проблемы — мы будем писать собственный Network Helper! С таким подходом больше не придется гадать, к какой сетке подключаться. Даже дополнительные действия для получения доступа в сеть можно будет производить в удобном нативном UI и гораздо быстрее, чем в браузере.



Все просто. Достаточно задействовать технологию NEHotspotHelper, которая стала доступна разработчикам еще со времен выхода iOS 9. Основная задача этого инструмента — классификация Wi-Fi-сетей и авторизация пользователя в них. NEHotspotHelper входит в состав фреймворка NetworkExtension. Чуть ниже вы найдете схему входящих в него на момент выхода iOS 11 инструментов:



Использование Hotspot Helper Extension



Основная документация находится тут: Hotspot Network Subsystem Programming Guide. Помимо этого никакой информации в сети обнаружить не удалось, в связи с чем я и пишу эту статью. Надеюсь, мой материал поможет восполнить пробелы документации и объяснит, как реализовать свой собственный Hotspot Helper. Пример использования этой технологии можно найти на GitHub.



Принцип работы



В основе работы Hotspot Helper — машина состояний Wi-Fi-соединения и посылаемые системой Helper команды, обработка которых переводит машину из одного состояния в другое. Ниже представлена приблизительная схема состояний, которую приводит сама Apple в своей документации:



Использование Hotspot Helper Extension



Поначалу столь сложная картинка пугает, однако не стоит беспокоиться — на практике все довольно просто.



Достаточно понимать следующее:




  • При первом подключении к сети после перезагрузки устройства выбирается Helper, который будет её обслуживать (Evaluate).

  • Как только выбор сделан, запускается авторизация в сети с помощью выбранного Hotspot Helper (Authenticating).

  • Если в процессе авторизации необходимо отобразить UI, Hotspot Helper его явно запрашивает (PresentingUI). Если такой нужды нет, Helper в фоне совершает необходимые действия по авторизации пользователя в сети (Authenticated).

  • Периодически система пробуждает выбранный Hotspot Helper для поддержки сессии, если это необходимо (Maintain).

  • Во время поддержки сессии Helper может ничего не делать, а может запросить повторную авторизацию или спровоцировать повторное подключение к сети.



  • Единственный неочевидный момент: после первого подключения к сети система кеширует выбранный для нее Hotspot Helper, поэтому при последующем подключении машина cразу переключается в состояние Maintain, минуя все предыдущие.



    Hotspot Helper участвует в авторизации пользователя в Wi-Fi-сети на всех этапах — от отображения списка сетей и подключения к выбранной до поддержки авторизации и самостоятельного логаута. При этом для установки соединения Hotspot Helper обрабатывает все требуемые команды, благодаря чему система обеспечивает его запуск в любой ситуации (даже если пользователь принудительно выключит приложение (что привело бы к игнорированию silent-push уведомлений). Ведь от этого зависит работа всего устройства. Надо понимать, что для пользователя весь процесс протекает прозрачно. Таким образом, наиболее частый сценарий — это запуск приложения в фоне.



    Итак, повторим: для установки Wi-Fi-соединения Hotspot Helper должен обработать все требуемые команды. Иными словами, устройство не будет считать себя подключенным к сети до тех пор, пока StateMachine не перейдет в состояние Authenticated. И это несмотря на то, что Hotspot Helper начнет видеть соединение уже при получении команды Evaluate. Этот момент отлично отслеживается средствами Reachability, о чем мы поговорим чуть ниже.



    Надо сказать, что NEHotspotHelper — не отдельный target, как это часто бывает с другими extension, а основное приложение, зарегистрированное как Hotspot Helper. Это значит, что, как только ему потребуется обработать какую-либо команду, будет запущено основное приложение со всеми вытекающими последствиями. То есть у приложения будет возможность выполнять любой код, однако при запуске в фоне оно может развернуть полномасштабные действия, как будто инициированные самим пользователем. Однако такая деятельность будет означать лишь расход ресурсов впустую, поэтому за происходящим в фоне стоит следить.



    Предварительная подготовка



    Для регистрации приложения как Hotspot Helper нужно получить разрешение у Apple. Для этого Team Agent должен перейти по ссылке и заполнить опросник.

    На момент написания статьи он выглядит так:






    Использование Hotspot Helper ExtensionИспользование Hotspot Helper Extension


    Если все пройдет хорошо, то при создании provisioning profile на https://developer.apple.com появится возможность выбрать для него entitlement с ключом com.apple.developer.networking.HotspotHelper, дающий право на использование всех плюшек.



    Использование Hotspot Helper Extension

    Кроме того, необходимо включить в проекте Background Mode Capability и прописать в Info.plist в раздел UIBackgroundModes строку network-authentication. После этого можно приступать к самому интересному — кодингу.



    Регистрация



    Для того чтобы приложение стало Hotspot Helper, его необходимо зарегистрировать в системе. Для этого надо вызвать следующий метод:



    class NEHotspotHelper 
        class func register(options: [String : NSObject]? = nil, queue: DispatchQueue, 
                            handler: @escaping NetworkExtension.NEHotspotHelperHandler) -> Bool
    
     

    Метод принимает три параметра:




    • Опциональный словарь параметров. Сейчас поддерживается единственный параметр: kNEHotspotHelperOptionDisplayName — имя Hotspot Helper, которое будет отображаться в списке доступных Wi-Fi-сетей рядом с теми сетями, которые HH поддерживает (об этом ниже). Сменить это имя можно только после перезапуска приложения, передав новое имя в качестве параметра. Согласно требованиям Apple, имя должно быть максимально коротким.




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




    • Блок — обработчик команд. Это ключевой элемент конструкции. Его сигнатура проста:



      typealias NEHotspotHelperHandler = (NEHotspotHelperCommand) -> Void
      


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



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



    Отменить регистрацию никак нельзя. Можно только перестать регистрировать блок, тогда приложение никак не будет обрабатывать соединение, но запускатьcя все равно будет —  подробнее тут.



    Кроме того, в отличие от многих других функций системы (таких как фотогалерея, календарь и даже уведомления), обработка Wi-Fi-соединения средствами Hotspot Helper не требует никаких разрешений от пользователя и происходит прозрачно для него (он попросту не сталкивается с подобными понятиями).



    Обработка команд



    Команда представляет собой объект класса NEHotspotHelperCommand, содержащий тип и набор данных, характерный для каждой из команд (сеть либо список сетей, если это подразумевает команда).



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

    Объект NEHotspotHelperResponse создается вызовом на полученной команде данного метода:



     func createResponse(_ result: NEHotspotHelperResult) -> NEHotspotHelperResponse


    Кроме того, использование объекта команды позволяет установить TCP- либо UDP-соединение на основании сети, к которой команда относится, вызывая соответствующие методы:

     

     func createTCPConnection(_ endpoint: NWEndpoint) -> NWTCPConnection
     func createUDPSession(_ endpoint: NWEndpoint) -> NWUDPSession
     

    Для более высокоуровневого общения с сервером можно создать NSURLRequest. Приложив к нему команду, Hotspot Helper получает возможность взаимодействия с сервером в условиях, когда устройство не видит Wi-Fi-соединения. Установленное таким образом соединение можно использовать для авторизации «по-своему». IYKWIM

     

     func bind(to command: NEHotspotHelperCommand)


    Ниже рассмотрим каждую команду, которую может получить Hotspot Helper, в порядке, соответствующем базовому сценарию подключения к сети. Большинство команд названы аналогично состояниям State Machine, при которых они вызываются.



    Официально на выполнение каждой команды отводится не более 45 секунд (однако, если посмотреть на доступное время работы в фоне, можно увидеть цифру 60 секунд). После этого команда считается необработанной, а работа Hotspot Helper приостанавливается. Это ограничение необходимо, чтобы устранить излишние задержки при подключении к сети, ведь пока команда не будет обработана, пользователь не увидит заветного значка Wi-Fi в Status Bar. При этом надо понимать, что, если в системе несколько Hotspot Helper, которые обрабатывают одну и ту же сеть, будет выбран самый быстрый из них (об этом опять же ниже).



    NEHotspotHelperCommandType.filterScanList



    Это особенная команда, которая, в отличие от остальных, не привязана ни к одному из состояний StateMachine и может быть вызвана в любой момент. Команда вызывается на всех Hotspot Helper, известных системе, каждые 5 секунд. Происходит это все время, пока пользователь находится на экране списка Wi-Fi-сетей в системном Settings.app.



    Команда служит единственной цели — продемонстрировать пользователю, какие из сетей обрабатывает Hotspot Helper. Для этого команда содержит список доступных сетей в соответствующем поле:



    var networkList: [NEHotspotNetwork]? { get }


    Это тот же список, который увидит пользователь. При этом список сетей может меняться с каждым новым вызовом команды.



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



    У тех сетей в списке, которые вернул Hotspot Helper в ответ на эту команду, появится подпись. Она будет соответствовать тому значению, которое было передано при последней регистрации Hotspot Helper в качестве опции kNEHotspotHelperOptionDisplayName. Значение подписи может быть только одно. Оно задается при регистрации и не может быть изменено до следующей регистрации (а это происходит после перезапуска приложения), так что подписывать сети по-разному, увы, не получится.



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



    В итоге обрабатывать команду следует так:

     

    let network = [leech=https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/Hotspot_Network_Subsystem_Guide/Contents/ImportantGuidelines.html#//apple_ref/doc/uid/TP40016639-CH5-SW1]Apple настоятельно дает понять[/leech], что уровень confidence надо выбирать тщательно и не следует бездумно выставлять всем сетям high (и даже low), так как это напрямую сказывается на UX всей системы.
    
     
    
    В итоге обрабатывать команду следует так:
    
    
    
    [code]let network = command.network
     
    // Оценить сеть и определить уровень confidence...
     
    network.setConfidence([leech=https://github.com/GusevAndrey/HotspotHelperExample]В примере[/leech] приведен код, позволяющий избежать этих ситуаций. 
    
    
    
    [b]Note:[/b] C выходом iOS 11 эта проблема [leech=https://developer.apple.com/documentation/networkextension/nehotspothelper/1618921-supportednetworkinterfaces?changes=latest_minor]устранена[/leech].
    
    
    
    </li>
    <li> Подключение к сети для всего устройства появляется только после того, как StateMachine перейдет в состояние Authenticated. Это хорошо видно с использованием reachbility, который не будет видеть соединения до тех пор, пока Hotspot Helper не обработает все необходимые команды.
    
    
    
    Следует отметить, что существует единственная ситуация, в которой reachability уже видит Wi-Fi, а Hotspot Helper не получает никаких команд. Происходит это, когда пользователь может видеть следующее состояние в настройках:
    
    
    
    [img]http://habrastorage.org/web/faa/8fd/4ca/faa8fd4ca2e846d5a07aba24072e3ac1.png[/img]
    
    
    
    Чем обусловлена такая ситуация, понять сложно. Если у вас есть идеи, поделитесь ими, пожалуйста.
    
    
    
    </li>
    <li>Несколько Helper в системе.
    
     Не существует никаких ограничений на количество Hotspot Helper, одновременно зарегистрированных в системе. Это значит, что возможна ситуация, при которой за обработку одной и той же сети будут конфликтовать несколько приложений.
    
    
    
    Конфликт решается на этапе обработки команды evaluate: выбирается тот Hotspot Helper, который вернул high-confidence для сети быстрее остальных. Вся дальнейшая обработка для этой сети происходит с использованием только этого Helper. Выбранный Helper может потом отказаться от обработки данной сети, вернув соответствующий код результата в процессе обработки очередной команды. Но если он этого не сделает, для остальных Hotspot Helper нет никакой возможности поучаствовать в обработке соединения. 
    
     
    
    Ситуация усугубляется еще и тем, что пользователь ничего не знает и не может знать о существовании каких-либо Helper. Все это происходит незаметно для него: нигде не указывается данный функционал, никакие разрешения у него не запрашиваются. Именно по этой причине одно из [leech=https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/Hotspot_Network_Subsystem_Guide/Contents/ImportantGuidelines.html#//apple_ref/doc/uid/TP40016639-CH5-SW1]требований Apple[/leech] заключается в необходимости предоставить пользователю в UI приложения возможность отключить обработку всех сетей либо конкретной сети (по SSID).
    
     
    
    Следует отметить, что какого-либо надежного способа определить наличие другого Hotspot Helper в системе нет. Единственное, что можно сделать, — проверить, выбран ли в текущий момент Hotspot Helper основным для активной сети. Это можно сделать так:
    
     
    
    [code]let network = NEHotspotHelper.supportedNetworkInterfaces().first
    if !network.isChosenHelper {
         // Hotspot Helper не обрабатывает активную сеть
    }


    Заметьте, false в этом флаге может означать, что для сети выбран другой Helper или даже что пока не выбран никакой (например, в процессе evaluate). Кроме того, сеть может уже появиться, но обработка подключения еще не начаться. Такая ситуация описана выше.




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



    func createTCPConnection(_ endpoint: NWEndpoint) -> NWTCPConnection
    func createUDPSession(_ endpoint: NWEndpoint) -> NWUDPSession


    А также расширение на NSMutableURLRequest:



    func bind(to command: NEHotspotHelperCommand)



  • С выходом iOS10.3, очевидно в целях экономии ресурсов, система начала производить самовольные отключения от сети при засыпании устройства с последующим переподключением к той же сети. Интервалы отключения-подключения не поддаются прогнозированию и зависят от текущего состояния системы, устройства и установленных на нём приложений. Интервалы могут быть самые разные: от долей секунд до нескольких часов. Более того, не удаётся найти какой-либо возможности отличить автоматическое переподключение к сети от выполненного самим пользователем — для устройства они оба происходят одинаково.



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




  • С выходом iOS 11 функционал NEHotspotHelper дополнит новый класс  NEHotspotConfigurationManager, с помощью которого можно подключаться к Wi-Fi прямо из приложения. Больше не надо заставлять пользователя идти в чуждые для него настройки и выбирать сеть из огромного списка с замороченными названиями. Это полезно в двух ситуациях:




    • для приложений, предоставляющих публичные сервисы (кафе, бизнес-центры и др.);

    • для приложений, производящих конфигурацию устройств по их собственной Wi-Fi-сети (например, видеокамеры). Для этого можно временно подключиться к заданной сетке до момента выхода из приложения.




  • Заключение



    Технология NEHotspotHelper, появившаяся несколько лет назад, не утратила своей актуальности и по сей день. Этот инструмент позволяет значительно улучшить и облегчить процесс пользования сетевыми сервисами. Здесь я рассмотрел основные принципы работы, способы применения и все шаги, которые следует предпринять для его эффективного использования. Кроме того, рассказал и о некоторых особенностях Helper, о которых тактично умалчивает документация.



    Надеюсь, теперь вы имеете полное представление о том, для чего и как стоит использовать эту штуку в вашем проекте. Впрочем, если у вас возникли какие-либо вопросы, напишите, я готов ответить на них.



    Полезные ссылки




  • Пример реализации на GitHub

  • Hotspot Network Subsystem Programming Guide

  • Network Extension

  • NEHotspotHelper reference

  • WWDC’15 What's New in Network Extension and VPN и её конспект

  • WWDC’17 Advances in Networking, Part 1

  • Forum: How to cancel register an app as a Hotspot Helper (NEHotspotHelper)?

  • Forum: Как получить entitlements через почту или через прямую ссылку на форму запроса

  • Forum: Как показать UI

  • Небольшая статья про HotspotHelper


  • Источник: Хабрахабр

    Категория: Веб-разработка, Game Development, iOS

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

    Добавление комментария

    Имя:*
    E-Mail:
    Комментарий:
    Полужирный Наклонный текст Подчеркнутый текст Зачеркнутый текст | Выравнивание по левому краю По центру Выравнивание по правому краю | Вставка смайликов Выбор цвета | Скрытый текст Вставка цитаты Преобразовать выбранный текст из транслитерации в кириллицу Вставка спойлера
    Введите два слова, показанных на изображении: *