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


之前寫過runtime的一些東西,這次通過runtime獲取一些蘋果官方不想讓你拿到的東西,比如,狀態欄內部的控件屬性。本文將通過runtime帶你一步步拿到狀態欄中顯示網絡狀態的控件,然后通過監測該控件的屬性來獲取當前精確網絡狀態,比如2G/3G/4G/WIFI。

首先,我們需要拿到狀態欄,然后通過runtime去探討狀態欄內部的組成結構。

1、導入運行時頭文件

#import <objc/message.h>

2、編寫運行時代碼,獲取到當前應用程序的所有成員變量

 1 #import "ViewController.h"
 2 #import <objc/message.h>
 3 
 4 @interface ViewController ()
 5 
 6 @end
 7 
 8 @implementation ViewController
 9 
10 - (void)viewDidAppear:(BOOL)animated
11 {
12     // 狀態欄是由當前app控制的,首先獲取當前app
13     UIApplication *app = [UIApplication sharedApplication];
14     
15     // 遍歷當前app的所有屬性,找到關於狀態欄的
16     unsigned int outCount = 0;
17     
18     Ivar *ivars = class_copyIvarList(app.class, &outCount);
19     
20     for (int i = 0; i < outCount; i++) {
21         Ivar ivar = ivars[i];
22         printf("|%s", ivar_getName(ivar));
23     }
24 }
25 
26 @end

直接運行,可以看到打印結果為:

3、可以看app里確實有個關於狀態欄的成員變量,我們通過KVC取出它

 1 - (void)viewDidAppear:(BOOL)animated
 2 {
 3     // 狀態欄是由當前app控制的,首先獲取當前app
 4     UIApplication *app = [UIApplication sharedApplication];
 5     
 6     id statusBar = [app valueForKeyPath:@"statusBar"];
 7     
 8     // 遍歷狀態欄的所有成員
 9     unsigned int outCount = 0;
10     Ivar *ivars = class_copyIvarList([statusBar class], &outCount);
11     
12     for (int i = 0; i < outCount; i++) {
13         Ivar ivar = ivars[i];
14         printf("|%s", ivar_getName(ivar));
15     }
16 }

運行后可以看到打印結果為

4、狀態欄里有foregroundView這個成員,應該代表着所有當前顯示的視圖,通過KVC取出它里面的所有子視圖

1 // 狀態欄是由當前app控制的,首先獲取當前app
2     UIApplication *app = [UIApplication sharedApplication];
3     
4     NSArray *children = [[[app valueForKeyPath:@"statusBar"] valueForKeyPath:@"foregroundView"] subviews];
5     
6     for (id child in children) {
7         NSLog(@"--%@", [child class]);
8     }

打印結果為

5、遍歷數組,取出用於顯示網絡狀態的視圖,並遍歷其內部的所有成員變量

 1 // 狀態欄是由當前app控制的,首先獲取當前app
 2     UIApplication *app = [UIApplication sharedApplication];
 3     
 4     NSArray *children = [[[app valueForKeyPath:@"statusBar"] valueForKeyPath:@"foregroundView"] subviews];
 5     
 6     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);
11             
12             for (int i = 0; i < outCount; i++) {
13                 Ivar ivar = ivars[i];
14                 printf("|%s", ivar_getName(ivar));
15             }
16         }
17     }

打印結果為

6、下面通過KVC,取出dataNetworkType

1 if ([child isKindOfClass:NSClassFromString(@"UIStatusBarDataNetworkItemView")]) {
2             id type = [child valueForKeyPath:@"dataNetworkType"];
3             NSLog(@"_dataNetworkType class is %@, value is %@", [type class], type);
4         }

打印結果為: 

可見,dataNetworkType類型是NSNumber,值是5。【以上均為模擬器測試】

經過測試,發現,可能的值為 1,2,3,5 分別對應的網絡狀態是2G、3G、4G及WIFI。 當沒有網絡時,隱藏UIStatusBarDataNetworkItemView,無法獲取dataNetworkType值

 

總結:

以下是完整的代碼,並經過真機測試:

 1 - (void)viewDidAppear:(BOOL)animated
 2 {
 3     // 狀態欄是由當前app控制的,首先獲取當前app
 4     UIApplication *app = [UIApplication sharedApplication];
 5     
 6     NSArray *children = [[[app valueForKeyPath:@"statusBar"] valueForKeyPath:@"foregroundView"] subviews];
 7     
 8     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

建議: 將獲取的UIStatusBarDataNetworkItemView保存起來,定時去取它的dataNetworkType,這樣就可以實時監控網絡狀態啦(KVO在這里是行不通的喲)

當然,此方法存在一定的局限性,比如當狀態欄被隱藏的時候,無法使用此方法。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM