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