Как узнать, отключен ли сотовый доступ для моего приложения iOS?

У меня есть приложение iOS, которое делает небольшие сетевые запросы при запуске приложения (обновления ресурсов и т.д.). Если пользователь отключает сотовый доступ для приложения в настройках iOS, они получают приглашение от iOS о сетевом использовании при каждом запуске. Есть ли способ узнать программно, что сотовые данные для этого приложения были отключены, поэтому я могу отключить запросы при запуске?

Ответ 1

Так что я нашел это на форумах Apple Dev от инженера Apple (https://devforums.apple.com/message/1059332#1059332).

Другой разработчик написал в DTS, и у меня была возможность подробно изучить это. Увы, новости такие же, как я ожидал: нет поддерживаемого способа определить, что ваше приложение находится в этом состоянии. Также нет способа сделать сетевое соединение "без взаимодействия с пользователем", то есть запросить сбой соединения, а не представлять подобный интерфейс. Если эти ограничения создают проблемы для вашего приложения, я рекомендую вам сообщить об ошибке, описывающей ваши конкретные требования.
https://developer.apple.com/bug-reporting/

Таким образом, похоже, что невозможно определить, были ли отключены сотовые данные для вашего приложения.

редактировать

Я подал радар для этого с просьбой добавить его. Я только что получил это уведомление в моем радаре

Мы считаем, что эта проблема была решена в последней бета-версии iOS 9.

Я просмотрел различия API, но пока не могу найти новый API.

Ответ 2

Начиная с iOS9, возможность проверки установки для включения/выключения использования сотовых данных для вашего приложения (Settings/Cellular/AppName) доступна с использованием класса Apple CTCellularData. Следующий код будет устанавливать cellDataRestrictedState, когда он запускается изначально, а затем устанавливает его и регистрирует при каждом изменении:

import CoreTelephony
var cellularDataRestrictedState = CTCellularDataRestrictedState.restrictedStateUnknown
let cellState = CTCellularData.init()
cellState.cellularDataRestrictionDidUpdateNotifier = { (dataRestrictedState) in
  if cellularDataRestrictedState != .restrictedStateUnknown { // State has changed - log to console
    print("cellularDataRestrictedState: " + "\(dataRestrictedState == .restrictedStateUnknown ? "unknown" : dataRestrictedState == .restricted ? "restricted" : "not restricted")")
  }
  cellularDataRestrictedState = dataRestrictedState
}

К сожалению (с iOS11), похоже, проверяется только состояние переключателя приложения - если ваш переключатель приложения настроен на включение, и пользователь переключает главный переключатель Cellular Data на отключенный, этот API вернет состояние приложения как "не ограничивается".

Ответ 3

Просто хотел добавить версию Objective C вышеуказанного кода Swift для будущих путешественников.

- (void)monitorCanUseCellularData {
    if (GCIsiOS9) {
        CTCellularData *cellularData = [[CTCellularData alloc] init];
        NSLog(@"%ld", cellularData.restrictedState);
        // 0, kCTCellularDataRestrictedStateUnknown
        [cellularData setCellularDataRestrictionDidUpdateNotifier:^(CTCellularDataRestrictedState state) {
            NSLog(@"%ld", state);
            self.canUseCellularData = cellularData.restrictedState ==2?true:false;
        }];
    }
}

Ответ 4

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

class CellularRestriction: NSObject {
    private static var cellularData = CTCellularData()
    private static var currentState = CTCellularDataRestrictedState.restrictedStateUnknown

    static var isRestricted: Bool {
        currentState = cellularData.restrictedState
        return currentState == .restricted
    }

    static func prepare() {
        if currentState == .restrictedStateUnknown {
            cellularData.cellularDataRestrictionDidUpdateNotifier = { state in
                currentState = cellularData.restrictedState // This value may be inconsistent, however the next read of isRestricted should be correct.
            }
        }
    }
}

Ответ 5

Добавив ответ dirkgroten, вы можете использовать класс Apple Reachability, который можно найти здесь:

https://developer.apple.com/Library/ios/samplecode/Reachability/Introduction/Intro.html

Он использует SCNetworkReachability, и он очень прост в использовании, он обнаруживает возможность подключения через Cell и WiFi, поскольку вам нужно будет проверить их при запуске.

Ответ 6

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

reachableViaWWAN
reachableViaWiFi 

Существует также измененный статусный блок достижимости, который вы можете установить:

– setReachabilityStatusChangeBlock:

AFNetworking Github

AFNetworkReachabilityManager