iOS10國行網路許可權問題

yan325098發表於2016-11-10

以前iOS9上只有蜂窩訪問許可權,不過預設都是允許訪問,可以自行去設定裡面關閉。

而iOS10針對國行手機多了一個無線和蜂窩訪問許可權的選擇。許多應用在第一次安裝的時候會自動彈出一個alertview詢問使用者是否允許應用使用包括無線和蜂窩的資料。但也有部分是不會彈出的(iOS10系統bug,解決辦法可自行百度)。注意這個彈窗只會在該手機第一個安裝該應用的時候才會彈出,解除安裝重灌也不會彈,類似keychain機制。

所以為了防止使用者在第一次彈窗的時候點了不允許而後面不能正常連線網路的情況,做出了相應的處理。(由於蘋果並沒有給出相應的api,無法獲知使用者在第一次是否點了允許還是不允許,所以通過間接的方式去判斷,有誤判,不過都是極少情況的概率出現)

所有因為我們應用有引導頁,所以在引導處自己寫了一個請求百度HEAD的方法(為了去彈出系統網路彈窗,如果沒有請求不會彈出,寫HEAD請求也是為了節省流量)。然後在過渡到登陸頁面的時候用AF去判斷當前的網路狀態,如果是AFNetworkReachabilityStatusNotReachable,即表示當前網路不可用。

然後在對此情況做出兩種判斷:

wifi:

- (NSDictionary *)fetchSSIDInfo {

    NSArray *ifs = (__bridge_transfer NSArray *)CNCopySupportedInterfaces();

    if (!ifs) {

        return nil;

    }


    NSDictionary *info = nil;

    for (NSString *ifnam in ifs) {

        info = (__bridge_transfer NSDictionary *)CNCopyCurrentNetworkInfo((__bridge CFStringRef)ifnam);

        if (info && [info count]) { break; }

    }

    return info;

}

如果獲取到的info不為nil,則當前是wifi情況下沒有網路連線。


蜂窩:

獲取運營商資訊

- (NSString *)fetchMobileInfo {

    CTTelephonyNetworkInfo *info = [[CTTelephonyNetworkInfo allocinit];

    return  info.currentRadioAccessTechnology;

}

可以去判斷是否為2G,2G情況下我是直接排除判斷範圍,因為2G環境下有可能會出現發生了網路請求,但是系統沒有彈窗。

然後用了一個ios9的api去判斷當前設定的蜂窩允許狀態:(使用者第一次彈窗選擇了不允許,是指蜂窩和無線都不允許,那麼可以通過這個蜂窩的狀態間接去判斷)

- (void)startValidateNetworkAuthorization:(NetworkAuthorizationStatus)block {

    CTCellularData *cellularData = [[CTCellularData alloc]init];

    cellularData.cellularDataRestrictionDidUpdateNotifier =  ^(CTCellularDataRestrictedState state){

        //獲取聯網狀態

        block(state);

        switch (state) {

            case kCTCellularDataRestricted:

                CDLogDebug(@"Restricrted");

                break;

            case kCTCellularDataNotRestricted:

                CDLogDebug(@"Not Restricted");

                break;

            case kCTCellularDataRestrictedStateUnknown:

                CDLogDebug(@"Unknown");

                break;

            default:

                break;

        };

    };

}


通過上面的判斷最後可以得出在wifi情況下/蜂窩非2G情況下到登陸頁面無網路連線,並且蜂窩狀態是被拒絕的狀態,就這樣得出使用者在第一次彈窗的時候點了不允許。
判斷條件是iOS10以上,然後再通過keychain儲存了一個值,只在第一次安裝的時候才去判斷,其他時候不用管。

存在誤判情況:
1、完全無網模式下進入應用,包括關閉wifi、蜂窩,或者是直接飛航模式進入,當然這種情況下比較少。
2、有wifi但是wifi是不能聯網的,也是比較少見。
所以通過這種方式可以減少誤判範圍,最主要的原因蘋果只針對國行才有這個許可權,沒有給出相應的api。

有一種方式可以判斷是否是飛航模式下進入應用:

- (void)checkNetworkConnectTest {

    // 建立零地址,0.0.0.0的地址表示查詢本機的網路連線狀態

    struct sockaddr_in zeroAddress;//sockaddr_in是與sockaddr等價的資料結構

    bzero(&zeroAddress, sizeof(zeroAddress));

    zeroAddress.sin_len = sizeof(zeroAddress);

    zeroAddress.sin_family = AF_INET;//sin_family是地址家族,一般都是“AF_xxx”的形式。通常大多用的是都是AF_INET,代表TCP/IP協議族


    /**

     *  SCNetworkReachabilityRef: 用來儲存建立測試連線返回的引用

     *

     *  SCNetworkReachabilityCreateWithAddress: 根據傳入的地址測試連線.

     *  第一個引數可以為NULLkCFAllocatorDefault

     *  第二個引數為需要測試連線的IP地址,當為0.0.0.0時則可以查詢本機的網路連線狀態.

     *  同時返回一個引用必須在用完後釋放.

     *  PS: SCNetworkReachabilityCreateWithName: 這個是根據傳入的網址測試連線,

     *  第二個引數比如為"www.apple.com",其他和上一個一樣.

     *

     *  SCNetworkReachabilityGetFlags: 這個函式用來獲得測試連線的狀態,

     *  第一個引數為之前建立的測試連線的引用,

     *  第二個引數用來儲存獲得的狀態,

     *  如果能獲得狀態則返回TRUE,否則返回FALSE

     *

     */

    SCNetworkReachabilityRef defaultRouteReachability = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&zeroAddress); //建立測試連線的引用:

    SCNetworkReachabilityFlags flags;


    BOOL didRetrieveFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags);

    CFRelease(defaultRouteReachability);

    if (didRetrieveFlags && flags == 0) {

        //當前是沒有開啟網路情況進入,不應該獲取網路許可權之後彈窗

        CDLogDebug(@"%u",flags);

    }

}

如果獲取到的flags是0,就是相當於關閉蜂窩和無線,或者飛航模式進入,在這裡我沒有用,畢竟覺得佔少數可以不用去考慮。

相關文章