iOS13 獲取StatusBar并且獲取網(wǎng)絡(luò)狀態(tài)

獲取StatusBar

項(xiàng)目中通過StatusBar來獲取手機(jī)當(dāng)前狀態(tài)窄俏,但是在iOS 13中便獲取不到了洪鸭,調(diào)試了一下發(fā)現(xiàn)是UIApplication無法獲取到statusBar。

    UIApplication *app = [UIApplication sharedApplication];
    id _statusBar = [app valueForKeyPath:@"_statusBar"];

于是改成如下的方式通過UIStatusBarManager獲取statusBar。

    UIStatusBarManager *statusBarManager = [UIApplication sharedApplication].keyWindow.windowScene.statusBarManager;
    id _statusBar = nil;
    if ([statusBarManager respondsToSelector:@selector(createLocalStatusBar)]) {
        UIView *_localStatusBar = [statusBarManager performSelector:@selector(createLocalStatusBar)];
        if ([_localStatusBar respondsToSelector:@selector(statusBar)]) {
            _statusBar = [_localStatusBar performSelector:@selector(statusBar)];
        }
    }

如果只是往StatusBar上添加View,那么到這里就已經(jīng)可以獲取到StatusBar了。

獲取網(wǎng)絡(luò)狀態(tài)

舊版本中不恭,獲取網(wǎng)絡(luò)狀態(tài)的代碼如下,原理就是獲取StatusBar中的網(wǎng)絡(luò)信號(hào)圖標(biāo)财饥,然后通過獲取信號(hào)圖標(biāo)來獲取網(wǎng)絡(luò)狀態(tài)换吧。

- (LLNetworkStatus)networkStateFromStatebar {
    __block LLNetworkStatus returnValue = LLNetworkStatusNotReachable;
    if (![[NSThread currentThread] isMainThread]) {
        dispatch_sync(dispatch_get_main_queue(), ^{
            returnValue = [self networkStateFromStatebar];
        });
        return returnValue;
    }

    UIApplication *app = [UIApplication sharedApplication];
    id _statusBar = [app valueForKeyPath:@"_statusBar"];
        
    if ([_statusBar isKindOfClass:NSClassFromString(@"UIStatusBar_Modern")]) {
        // For iPhoneX
        NSArray *children = [[[_statusBar valueForKeyPath:@"_statusBar"] valueForKeyPath:@"foregroundView"] subviews];
        for (UIView *view in children) {
            for (id child in view.subviews) {
                if ([child isKindOfClass:NSClassFromString(@"_UIStatusBarWifiSignalView")]) {
                    returnValue = LLNetworkStatusReachableViaWiFi;
                    break;
                }
                if ([child isKindOfClass:NSClassFromString(@"_UIStatusBarStringView")]) {
                    NSString *originalText = [child valueForKey:@"_originalText"];
                    if ([originalText containsString:@"G"]) {
                        if ([originalText isEqualToString:@"2G"]) {
                            returnValue = LLNetworkStatusReachableViaWWAN2G;
                        } else if ([originalText isEqualToString:@"3G"]) {
                            returnValue = LLNetworkStatusReachableViaWWAN3G;
                        } else if ([originalText isEqualToString:@"4G"]) {
                            returnValue = LLNetworkStatusReachableViaWWAN4G;
                        } else {
                            returnValue = LLNetworkStatusReachableViaWWAN;
                        }
                        break;
                    }
                }
            }
        }
    } else {
        // For others iPhone
        NSArray *children = [[_statusBar valueForKeyPath:@"foregroundView"] subviews];
        int type = -1;
        for (id child in children) {
            if ([child isKindOfClass:[NSClassFromString(@"UIStatusBarDataNetworkItemView") class]]) {
                type = [[child valueForKeyPath:@"dataNetworkType"] intValue];
            }
        }
        switch (type) {
            case 0:
                returnValue = LLNetworkStatusNotReachable;
                break;
            case 1:
                returnValue = LLNetworkStatusReachableViaWWAN2G;
                break;
            case 2:
                returnValue = LLNetworkStatusReachableViaWWAN3G;
                break;
            case 3:
                returnValue = LLNetworkStatusReachableViaWWAN4G;
                break;
            case 4:
                returnValue = LLNetworkStatusReachableViaWWAN;
                break;
            case 5:
                returnValue = LLNetworkStatusReachableViaWiFi;
                break;
            default:
                break;
        }
    }
    return returnValue;
}

雖然在iOS 13中已經(jīng)可以獲取到StatusBar,但是不斷遞推[StatusBar subviews]時(shí)钥星,卻不能發(fā)現(xiàn)任何一個(gè)有關(guān)網(wǎng)絡(luò)信息的View式散,所以舊的方式并不適用與iOS 13,所以我們打印出StatusBar中所有的屬性打颤,查找接下來的思路暴拄。

(lldb) po [[[_statusBar valueForKeyPath:@"_statusBar"] class] LL_getPropertyNames]
<__NSArrayM 0x600000192be0>(
items,
displayItemStates,
updateCompletionHandler,
foregroundView,
targetActionable,
accessibilityHUDGestureManager,
visualProviderClassName,
visualProviderClass,
visualProvider,
regions,
dataAggregator,
currentAggregatedData,
containerView,
animationContextId,
animationsEnabled,
styleAttributes,
action,
targetScreen,
style,
foregroundColor,
mode,
orientation,
currentData,
dependentDataEntryKeys,
overlayData,
actionGestureRecognizer,
enabledPartIdentifiers,
avoidanceFrame,
hash,
superclass,
description,
debugDescription
)

在打印的屬性中,我們只需要具體分析currentData就可以编饺。(為什么只分析currentData乖篷,因?yàn)榭刂茖?dǎo)航欄信息的數(shù)據(jù)都存在currentData中)

(lldb) po [[_statusBar valueForKeyPath:@"_statusBar"] valueForKeyPath:@"currentData"]
<_UIStatusBarData: 0x7fdc464362e0: 

mainBatteryEntry=<_UIStatusBarDataBatteryEntry: 0x600000187c30: isEnabled=1, capacity=100, state=2, saverModeActive=0, prominentlyShowsDetailString=0, detailString=100%>, 

secondaryCellularEntry=<_UIStatusBarDataCellularEntry: 0x600002b25440: isEnabled=1, rawValue=0, displayValue=0, displayRawValue=0, status=0, lowDataModeActive=0, type=5, wifiCallingEnabled=0, callForwardingEnabled=0, showsSOSWhenDisabled=0>,

dateEntry=<_UIStatusBarDataStringEntry: 0x600000f17f00: isEnabled=1, stringValue=Tue Aug 27>,

timeEntry=<_UIStatusBarDataStringEntry: 0x600000f17640: isEnabled=1, stringValue=6:34 PM>,

cellularEntry=<_UIStatusBarDataCellularEntry: 0x600002b254a0: isEnabled=1, rawValue=0, displayValue=0, displayRawValue=0, status=1, lowDataModeActive=0, type=5, string=Carrier, wifiCallingEnabled=0, callForwardingEnabled=0, showsSOSWhenDisabled=0>,

wifiEntry=<_UIStatusBarDataWifiEntry: 0x600001aa1c40: isEnabled=1, rawValue=0, displayValue=3, displayRawValue=0, status=5, lowDataModeActive=0, type=0>,

shortTimeEntry=<_UIStatusBarDataStringEntry: 0x600000f16ac0: isEnabled=1, stringValue=6:34>,

// some descriptions.

這里只是展示了一部分log,如果你想查看全部的屬性透且,可以自己調(diào)試看看撕蔼,在這些屬性中豁鲤,我們可以看到這里有關(guān)于時(shí)間的dateEntrytimeEntry,還有關(guān)于網(wǎng)絡(luò)的cellularEntrywifiEntry鲸沮,在所有的Entry中都有isEnabled屬性琳骡,只有當(dāng)isEnabledtrue時(shí),這個(gè)屬性才有意義讼溺。通過判斷wifiEntry是否可用楣号,來確定是否是WiFi,通過判斷cellularEntrytype來判斷具體是4G/3G怒坯,所以獲取網(wǎng)絡(luò)狀態(tài)的代碼如下:

id _statusBar = nil;
    if (@available(iOS 13.0, *)) {
        /*
         We can still get statusBar using the following code, but this is not recommended.
         */
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"
        UIStatusBarManager *statusBarManager = [UIApplication sharedApplication].keyWindow.windowScene.statusBarManager;
        if ([statusBarManager respondsToSelector:@selector(createLocalStatusBar)]) {
            UIView *_localStatusBar = [statusBarManager performSelector:@selector(createLocalStatusBar)];
            if ([_localStatusBar respondsToSelector:@selector(statusBar)]) {
                _statusBar = [_localStatusBar performSelector:@selector(statusBar)];
            }
        }
#pragma clang diagnostic pop
        if (_statusBar) {
            // _UIStatusBarDataCellularEntry
            id currentData = [[_statusBar valueForKeyPath:@"_statusBar"] valueForKeyPath:@"currentData"];
            id _wifiEntry = [currentData valueForKeyPath:@"wifiEntry"];
            id _cellularEntry = [currentData valueForKeyPath:@"cellularEntry"];
            if (_wifiEntry && [[_wifiEntry valueForKeyPath:@"isEnabled"] boolValue]) {
                // If wifiEntry is enabled, is WiFi.
                returnValue = LLNetworkStatusReachableViaWiFi;
            } else if (_cellularEntry && [[_cellularEntry valueForKeyPath:@"isEnabled"] boolValue]) {
                NSNumber *type = [_cellularEntry valueForKeyPath:@"type"];
                if (type) {
                    switch (type.integerValue) {
                        case 5:
                            returnValue = LLNetworkStatusReachableViaWWAN4G;
                            break;
                        case 4:
                            returnValue = LLNetworkStatusReachableViaWWAN3G;
                            break;
                            //                        case 1: // Return 1 when 1G.
                            //                            break;
                        case 0:
                            // Return 0 when no sim card.
                            returnValue = LLNetworkStatusNotReachable;
                        default:
                            returnValue = LLNetworkStatusReachableViaWWAN;
                            break;
                    }
                }
            }
        }
    }

總結(jié)

完整的代碼如下炫狱,當(dāng)然你也可以查看LLDebugTool - LLNetworkHelper.m 來查看具體的代碼。

- (LLNetworkStatus)networkStateFromStatebar {
    __block LLNetworkStatus returnValue = LLNetworkStatusNotReachable;
    if (![[NSThread currentThread] isMainThread]) {
        dispatch_sync(dispatch_get_main_queue(), ^{
            returnValue = [self networkStateFromStatebar];
        });
        return returnValue;
    }
    id _statusBar = nil;
    if (@available(iOS 13.0, *)) {
        /*
         We can still get statusBar using the following code, but this is not recommended.
         */
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"
        UIStatusBarManager *statusBarManager = [UIApplication sharedApplication].keyWindow.windowScene.statusBarManager;
        if ([statusBarManager respondsToSelector:@selector(createLocalStatusBar)]) {
            UIView *_localStatusBar = [statusBarManager performSelector:@selector(createLocalStatusBar)];
            if ([_localStatusBar respondsToSelector:@selector(statusBar)]) {
                _statusBar = [_localStatusBar performSelector:@selector(statusBar)];
            }
        }
#pragma clang diagnostic pop
        if (_statusBar) {
            // _UIStatusBarDataCellularEntry
            id currentData = [[_statusBar valueForKeyPath:@"_statusBar"] valueForKeyPath:@"currentData"];
            id _wifiEntry = [currentData valueForKeyPath:@"wifiEntry"];
            id _cellularEntry = [currentData valueForKeyPath:@"cellularEntry"];
            if (_wifiEntry && [[_wifiEntry valueForKeyPath:@"isEnabled"] boolValue]) {
                // If wifiEntry is enabled, is WiFi.
                returnValue = LLNetworkStatusReachableViaWiFi;
            } else if (_cellularEntry && [[_cellularEntry valueForKeyPath:@"isEnabled"] boolValue]) {
                NSNumber *type = [_cellularEntry valueForKeyPath:@"type"];
                if (type) {
                    switch (type.integerValue) {
                        case 5:
                            returnValue = LLNetworkStatusReachableViaWWAN4G;
                            break;
                        case 4:
                            returnValue = LLNetworkStatusReachableViaWWAN3G;
                            break;
                            //                        case 1: // Return 1 when 1G.
                            //                            break;
                        case 0:
                            // Return 0 when no sim card.
                            returnValue = LLNetworkStatusNotReachable;
                        default:
                            returnValue = LLNetworkStatusReachableViaWWAN;
                            break;
                    }
                }
            }
        }
    } else {
        UIApplication *app = [UIApplication sharedApplication];
        _statusBar = [app valueForKeyPath:@"_statusBar"];
        
        if ([_statusBar isKindOfClass:NSClassFromString(@"UIStatusBar_Modern")]) {
            // For iPhoneX
            NSArray *children = [[[_statusBar valueForKeyPath:@"_statusBar"] valueForKeyPath:@"foregroundView"] subviews];
            for (UIView *view in children) {
                for (id child in view.subviews) {
                    if ([child isKindOfClass:NSClassFromString(@"_UIStatusBarWifiSignalView")]) {
                        returnValue = LLNetworkStatusReachableViaWiFi;
                        break;
                    }
                    if ([child isKindOfClass:NSClassFromString(@"_UIStatusBarStringView")]) {
                        NSString *originalText = [child valueForKey:@"_originalText"];
                        if ([originalText containsString:@"G"]) {
                            if ([originalText isEqualToString:@"2G"]) {
                                returnValue = LLNetworkStatusReachableViaWWAN2G;
                            } else if ([originalText isEqualToString:@"3G"]) {
                                returnValue = LLNetworkStatusReachableViaWWAN3G;
                            } else if ([originalText isEqualToString:@"4G"]) {
                                returnValue = LLNetworkStatusReachableViaWWAN4G;
                            } else {
                                returnValue = LLNetworkStatusReachableViaWWAN;
                            }
                            break;
                        }
                    }
                }
            }
        } else {
            // For others iPhone
            NSArray *children = [[_statusBar valueForKeyPath:@"foregroundView"] subviews];
            int type = -1;
            for (id child in children) {
                if ([child isKindOfClass:[NSClassFromString(@"UIStatusBarDataNetworkItemView") class]]) {
                    type = [[child valueForKeyPath:@"dataNetworkType"] intValue];
                }
            }
            switch (type) {
                case 0:
                    returnValue = LLNetworkStatusNotReachable;
                    break;
                case 1:
                    returnValue = LLNetworkStatusReachableViaWWAN2G;
                    break;
                case 2:
                    returnValue = LLNetworkStatusReachableViaWWAN3G;
                    break;
                case 3:
                    returnValue = LLNetworkStatusReachableViaWWAN4G;
                    break;
                case 4:
                    returnValue = LLNetworkStatusReachableViaWWAN;
                    break;
                case 5:
                    returnValue = LLNetworkStatusReachableViaWiFi;
                    break;
                default:
                    break;
            }
        }
    }
    
    return returnValue;
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末剔猿,一起剝皮案震驚了整個(gè)濱河市视译,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌归敬,老刑警劉巖酷含,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異汪茧,居然都是意外死亡第美,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門陆爽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來什往,“玉大人,你說我怎么就攤上這事慌闭”鹜” “怎么了?”我有些...
    開封第一講書人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵驴剔,是天一觀的道長省古。 經(jīng)常有香客問我,道長丧失,這世上最難降的妖魔是什么豺妓? 我笑而不...
    開封第一講書人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮布讹,結(jié)果婚禮上琳拭,老公的妹妹穿的比我還像新娘。我一直安慰自己描验,他們只是感情好白嘁,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著膘流,像睡著了一般絮缅。 火紅的嫁衣襯著肌膚如雪鲁沥。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,146評(píng)論 1 297
  • 那天耕魄,我揣著相機(jī)與錄音画恰,去河邊找鬼。 笑死吸奴,一個(gè)胖子當(dāng)著我的面吹牛允扇,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播奄抽,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼蔼两,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼甩鳄!你這毒婦竟也來了逞度?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤妙啃,失蹤者是張志新(化名)和其女友劉穎档泽,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體揖赴,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡馆匿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了燥滑。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片渐北。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖铭拧,靈堂內(nèi)的尸體忽然破棺而出赃蛛,到底是詐尸還是另有隱情,我是刑警寧澤搀菩,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布呕臂,位于F島的核電站,受9級(jí)特大地震影響肪跋,放射性物質(zhì)發(fā)生泄漏歧蒋。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一州既、第九天 我趴在偏房一處隱蔽的房頂上張望谜洽。 院中可真熱鬧,春花似錦吴叶、人聲如沸褥琐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽敌呈。三九已至贸宏,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間磕洪,已是汗流浹背吭练。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留析显,地道東北人鲫咽。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像谷异,于是被迫代替她去往敵國和親分尸。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,097評(píng)論 1 32
  • 據(jù)說裝飾行業(yè)的網(wǎng)絡(luò)營銷比其他行業(yè)慢了4~5年歹嘹,一點(diǎn)都不夸張箩绍,當(dāng)其他行業(yè)都進(jìn)入自媒體時(shí)代的時(shí)候,很多裝企還在做百度競...
    婧言靜語閱讀 385評(píng)論 0 1
  • 停電了 中國臺(tái)灣謝武彰 停電了尺上,好暗呀材蛛! 媽媽伸出手 摸到了我的臉 摸到了我的胳膊 終于,拉著我的手怎抛,說: “別怕...
    笑笑8閱讀 1,237評(píng)論 0 2
  • 二零一八年六月三日 星期天 天氣晴 今天早上卑吭,終于有時(shí)間檢查了作業(yè)了。發(fā)現(xiàn)練習(xí)冊(cè)上马绝,竟然有沒有寫的...
    鐘京芬閱讀 196評(píng)論 0 0
  • 一豆赏、如何理解“課程”這一概念? 課程可分為狹義和廣義兩個(gè)方面:狹義的課程是指教學(xué)內(nèi)容富稻,主要體現(xiàn)在教科書掷邦、課程計(jì)劃(...
    呆呆地閱讀 3,199評(píng)論 0 17