iOS開發之runtime的運用-獲取當前網絡狀態

2014-04-03  skylonely  + 關注獻花(0)數組

  以前寫過runtime的一些東西,此次經過runtime獲取一些蘋果官方不想讓你拿到的東西,好比,狀態欄內部的控件屬性。本文將經過runtime帶你一步步拿到狀態欄中顯示網絡狀態的控件,而後經過監測該控件的屬性來獲取當前精確網絡狀態,好比2G/3G/4G/WIFI。首先,咱們須要拿到狀態欄,而後經過runtime去探討狀態欄內部的組成結構。網絡

一、導入運行時頭文件#import <objc/message.h>app

二、編寫運行時代碼,獲取到當前應用程序的全部成員變量複製代碼1 #import "ViewController.h"2 #import <objc/message.h>34 @interface ViewController ()56 @end78 @implementation ViewController910 - (void)viewDidAppear:(BOOL)animated11 {12     // 狀態欄是由當前app控制的,首先獲取當前app13     UIApplication *app = [UIApplication sharedApplication];1415     // 遍歷當前app的全部屬性,找到關於狀態欄的16     unsigned int outCount = 0;1718     Ivar *ivars = class_copyIvarList(app.class, &outCount);1920     for (int i = 0; i < outCount; i++) {21         Ivar ivar = ivars[i];22         printf("|%s", ivar_getName(ivar));23     }24 }2526 @end複製代碼直接運行,能夠看到打印結果爲:ide

|_delegate|_exclusiveTouchWindows|_event|_touchesEvent|_motionEvent|_remoteControlEvent|_remoteControlEventObservers|_topLevelNibObjects|_networkResourcesCurrentlyLoadingCount|_hideNetworkActivityIndicatorTimer|_editAlertView|_statusBar|_statusBarRequestedStyle|_statusBarWindow|_observerBlocks|_postCommitActions|_mainStoryboardName|_tintViewDurationStack|_statusBarTintColorLockingControllers|_statusBarTintColorLockingCount|_preferredContentSizeCategory|_applicationFlags|_defaultTopNavBarTintColor|_undoButtonIndex|_redoButtonIndex|_moveEvent|_physicalButtonsEvent|_wheelEvent|_physicalButtonMap|_physicalKeyboardEvent|_alwaysHitTestsForMainScreen|_backgroundHitTestWindow|_eventQueue|_childEventMap|_disableTouchCoalescingCount|_classicMode|_actionsPendingInitialization|_idleTimerDisabledReasons|_currentTimestampWhenFirstTouchCameDown|_currentLocationWhereFirstTouchCameDown|_currentActivityUUID|_currentActivityType|_sceneSettingsDiffInspector|_saveStateRestorationArchiveWithFileProtectionCompleteUntilFirstUserAuthentication|_simulatorShakeNotificationToken|_virtualHorizontalSizeClass|_virtualVerticalSizeClass|__expectedViewOrientation|_preferredContentSizeCategoryName|_lastTimestampWhenFirstTouchCameDown|_lastTimestampWhenAllTouchesLifted|_lastLocationWhereFirstTouchCameDown|_lastLocationWhereAllTouchesLifted|_virtualWindowSizeInSceneReferenceSpacepost

三、能夠看app裏確實有個關於狀態欄的成員變量,咱們經過KVC取出它複製代碼1 - (void)viewDidAppear:(BOOL)animated2 {3     // 狀態欄是由當前app控制的,首先獲取當前app4     UIApplication *app = [UIApplication sharedApplication];56     id statusBar = [app valueForKeyPath:@"statusBar"];78     // 遍歷狀態欄的全部成員9     unsigned int outCount = 0;10     Ivar *ivars = class_copyIvarList([statusBar class], &outCount);1112     for (int i = 0; i < outCount; i++) {13         Ivar ivar = ivars[i];14         printf("|%s", ivar_getName(ivar));15     }16 }複製代碼運行後能夠看到打印結果爲測試

|_statusBarWindow|_statusBarServer|_inProcessProvider|_showsForeground|_backgroundView|_foregroundView|_doubleHeightLabel|_doubleHeightLabelContainer|_currentDoubleHeightText|_currentRawData|_interruptedAnimationCompositeViews|_newStyleBackgroundView|_newStyleForegroundView|_slidingStatusBar|_requestedStyle|_styleOverrides|_styleAttributes|_orientation|_hidden|_suppressesHiddenSideEffects|_foreground|_registered|_waitingOnCallbackAfterChangingStyleOverridesLocally|_suppressGlow|_translucentBackgroundAlpha|_showOnlyCenterItems|_localDataOverrides|_tintColor|_lastUsedBackgroundColor|_nextTintTransition|_overrideHeight|_disableRasterizationReasons|_persistentAnimationsEnabled|_simulatesLegacyAppearance|_serverUpdatesDisabled|_homeItemsDisabled|_styleDelegate|_foregroundColor|_legibilityStylespa

四、狀態欄裏有foregroundView這個成員,應該表明着全部當前顯示的視圖,經過KVC取出它裏面的全部子視圖複製代碼1 // 狀態欄是由當前app控制的,首先獲取當前app2     UIApplication *app = [UIApplication sharedApplication];34     NSArray *children = [[[app valueForKeyPath:@"statusBar"] valueForKeyPath:@"foregroundView"] subviews];56     for (id child in children) {7         NSLog(@"--%@", [child class]);8   }複製代碼打印結果爲.net

 --UIStatusBarServiceItemVieworm

2016-02-29 14:51:56.538 runtime[16977:130523] --UIStatusBarDataNetworkItemViewserver

2016-02-29 14:51:56.538 runtime[16977:130523] --UIStatusBarBatteryItemView

2016-02-29 14:51:56.538 runtime[16977:130523] --UIStatusBarTimeItemView


五、遍歷數組,取出用於顯示網絡狀態的視圖,並遍歷其內部的全部成員變量複製代碼1 // 狀態欄是由當前app控制的,首先獲取當前app2     UIApplication *app = [UIApplication sharedApplication];34     NSArray *children = [[[app valueForKeyPath:@"statusBar"] valueForKeyPath:@"foregroundView"] subviews];56     for (id child in children) {7         if ([child isKindOfClass:NSClassFromString(@"UIStatusBarDataNetworkItemView")]) {8             // 遍歷當前狀態欄的全部屬性,找到關於狀態欄的9             unsigned int outCount = 0;10             Ivar *ivars = class_copyIvarList([child class], &outCount);1112             for (int i = 0; i < outCount; i++) {13                 Ivar ivar = ivars[i];14                 printf("|%s", ivar_getName(ivar));15             }16         }17     }複製代碼打印結果爲


|_dataNetworkType|_wifiStrengthRaw|_wifiStrengthBars|_enableRSSI|_showRSSI



六、下面經過KVC,取出dataNetworkType1 if ([child isKindOfClass:NSClassFromString(@"UIStatusBarDataNetworkItemView")]) {2             id type = [child valueForKeyPath:@"dataNetworkType"];3             NSLog(@"_dataNetworkType class is %@, value is %@", [type class], type);4         }打印結果爲:

_dataNetworkType class is __NSCFNumber, value is 5

可見,dataNetworkType類型是NSNumber,值是5。


【以上均爲模擬器測試】通過測試,發現,可能的值爲 1,2,3,5 分別對應的網絡狀態是2G、3G、4G及WIFI。 當沒有網絡時,隱藏UIStatusBarDataNetworkItemView,沒法獲取dataNetworkType值總結:如下是完整的代碼,並通過真機測試:複製代碼1 - (void)viewDidAppear:(BOOL)animated2 {3     // 狀態欄是由當前app控制的,首先獲取當前app4     UIApplication *app = [UIApplication sharedApplication];56     NSArray *children = [[[app valueForKeyPath:@"statusBar"] valueForKeyPath:@"foregroundView"] subviews];78     int type = 0;9     for (id child in children) {10         if ([child isKindOfClass:NSClassFromString(@"UIStatusBarDataNetworkItemView")]) {11             type = [[child valueForKeyPath:@"dataNetworkType"] intValue];12         }13     }14     NSLog(@"----%d", type);15 }複製代碼打印出的type數字對應的網絡狀態依次是:0 - 無網絡; 1 - 2G; 2 - 3G; 3 - 4G; 5 - WIFI

相關文章
相關標籤/搜索