Почему ваше приложение для iPhone не может включить или выключить системный VPN
Публичное приложение не может переключать системный VPN, читать его состояние или принудительно устанавливать соединение. Правила On Demand, профили Always On на контролируемых устройствах и MDM — это варианты.
Продакт-менеджер просит кнопку, которая включает корпоративный VPN, и запрос звучит банально. В iOS это не мелкая функция; она находится вне публичного контракта, и любой обход либо не проходит проверку, либо ломается в следующем релизе. Проведите запрос через то, что платформа действительно разрешает, и дизайн во многом напишется сам. Приложение может владеть конфигурацией VPN и запускать её. Приложение не может дотянуться до системного переключателя, не может прочитать состояние профиля, который само не создавало, и не может удерживать пользователя подключённым против его воли.
Начните с трёх вещей, которые имеет в виду пользователь
Разделите смыслы, прежде чем разделять API. Иногда пользователь хочет, чтобы туннель вашего приложения был подключён, иногда — чтобы переключатель в Настройках включился для профиля, установленного кем-то другим, а иногда — чтобы телефон не мог выйти в интернет без туннеля. Это соответствует трём разным механизмам, и только первый открыт обычному приложению.
Второй смысл и порождает вопросы на Stack Overflow, и поддерживаемого ответа на него нет. Переключатель в Настройках принадлежит пользователю, а на управляемых устройствах — профилю. Ни один публичный API не перечисляет конфигурации VPN, не сообщает, поднят ли системный туннель, и не переключает его.
Что приложение действительно может создать
NetworkExtension даёт приложению собственную конфигурацию через NEVPNManager. С правом Personal VPN и согласием пользователя приложение сохраняет конфигурацию, которая появляется в Настройках под его именем, и может запустить или остановить именно это соединение. Это реальная, проверяемая возможность, и это же весь объём: менеджер читает и пишет только то, что создал сам.
Право не выдаётся автоматически. Вы запрашиваете его у Apple и обосновываете, зачем приложению вообще нужен туннель, а у клиента, единственная цель которого — включить чужой профиль, хорошего ответа нет. Поставщики пакетных туннелей следуют тому же правилу с другим классом: NETunnelProviderManager владеет конфигурациями на основе поставщика, которые установило само приложение. Ни один из путей не достигает профиля, доставленного MDM.
Согласие действует и в момент сохранения. Запись конфигурации спрашивает пользователя, и этот запрос не то, что приложение может подавить ради удобства.
Чтение состояния упирается в ту же стену
Статус выглядит дружелюбнее управления и так же закрыт. NEVPNStatus сообщает недействительно, отключено, подключение, подключено, повторное подтверждение или отключение для собственной конфигурации приложения, и при каждом изменении срабатывает уведомление. Он ничего не говорит о туннеле, установленном профилем управления, а именно это состояние и хочет видеть служба поддержки.
Мониторинг сетевого пути и изменения интерфейса предлагают в качестве замены на обзорах дизайна. Они описывают путь, по которому идёт трафик приложения, а он меняется по причинам, не связанным с состоянием VPN, и использование их как индикатора VPN даёт интерфейс, который лжёт в обе стороны.
On Demand и Always On — настоящие рычаги
Поддерживаемые рычаги живут в профиле, а не в приложении. Правила On Demand говорят системе, когда подключаться: упорядоченный список условий с действиями, который оценивает операционная система, а не ваш код. Правило, которое подключается на любом интерфейсе, создаёт ощущение постоянного подключения, не давая приложению никакого контроля.
Always On VPN — это механизм принуждения, и он привязан к надзору. На устройстве под надзором MDM устанавливает профиль, который держит туннель поднятым; на личном телефоне без надзора те же ключи не дают того же поведения. Эта асимметрия намеренна, и никакая комбинация ключей полезной нагрузки её не убирает. Когда требование действительно в том, что VPN должен быть включён, требование на самом деле в том, что устройством нужно управлять.
Между ними сидит более слабый родственник: правило, которое переподключается после того, как пользователь отключился. Оно подключается при следующей оценке правила, что не то же самое, что сразу, и пользователь, отключившийся нарочно, заметит разницу. Проектируйте интерфейс вокруг этого зазора, а не обещайте замок.
Поставляйте поддерживаемый путь
Четыре вопроса решают механизм до того, как появится код: кому принадлежит устройство, под надзором ли оно, какой клиент завершает туннель и откуда берётся профиль. Если что-то из этого неизвестно, запрос на функцию не готов к оценке.
Приватный API, который ковыряется в системном VPN, пройдёт демонстрацию и провалит проверку, а если его поставят иным способом, он сломается в следующем релизе iOS. Нет версии этой сделки, которая стоила бы одного переключателя.
Телеметрия управления — отдельный канал: она сообщает, что профиль установлен и соответствует ли устройство требованиям, а это отчётность, а не поверхность управления для каждого приложения. Тестируйте поток на реальном устройстве после каждого обновления, потому что поддерживаемое поведение живёт в ОС, а ОС движется.