123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175 |
- //
- // YYReachability.m
- // YYKit <https://github.com/ibireme/YYKit>
- //
- // Created by ibireme on 15/2/6.
- // Copyright (c) 2015 ibireme.
- //
- // This source code is licensed under the MIT-style license found in the
- // LICENSE file in the root directory of this source tree.
- //
- #import "YYReachability.h"
- #import <objc/message.h>
- #import <CoreTelephony/CTTelephonyNetworkInfo.h>
- static YYReachabilityStatus YYReachabilityStatusFromFlags(SCNetworkReachabilityFlags flags, BOOL allowWWAN) {
- if ((flags & kSCNetworkReachabilityFlagsReachable) == 0) {
- return YYReachabilityStatusNone;
- }
-
- if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) &&
- (flags & kSCNetworkReachabilityFlagsTransientConnection)) {
- return YYReachabilityStatusNone;
- }
-
- if ((flags & kSCNetworkReachabilityFlagsIsWWAN) && allowWWAN) {
- return YYReachabilityStatusWWAN;
- }
-
- return YYReachabilityStatusWiFi;
- }
- static void YYReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void *info) {
- YYReachability *self = ((__bridge YYReachability *)info);
- if (self.notifyBlock) {
- dispatch_async(dispatch_get_main_queue(), ^{
- self.notifyBlock(self);
- });
- }
- }
- @interface YYReachability ()
- @property (nonatomic, assign) SCNetworkReachabilityRef ref;
- @property (nonatomic, assign) BOOL scheduled;
- @property (nonatomic, assign) BOOL allowWWAN;
- @property (nonatomic, strong) CTTelephonyNetworkInfo *networkInfo;
- @end
- @implementation YYReachability
- + (dispatch_queue_t)sharedQueue {
- static dispatch_queue_t queue;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- queue = dispatch_queue_create("com.ibireme.yykit.reachability", DISPATCH_QUEUE_SERIAL);
- });
- return queue;
- }
- - (instancetype)init {
- /*
- See Apple's Reachability implementation and readme:
- The address 0.0.0.0, which reachability treats as a special token that
- causes it to actually monitor the general routing status of the device,
- both IPv4 and IPv6.
- https://developer.apple.com/library/ios/samplecode/Reachability/Listings/ReadMe_md.html#//apple_ref/doc/uid/DTS40007324-ReadMe_md-DontLinkElementID_11
- */
- struct sockaddr_in zero_addr;
- bzero(&zero_addr, sizeof(zero_addr));
- zero_addr.sin_len = sizeof(zero_addr);
- zero_addr.sin_family = AF_INET;
- SCNetworkReachabilityRef ref = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *)&zero_addr);
- return [self initWithRef:ref];
- }
- - (instancetype)initWithRef:(SCNetworkReachabilityRef)ref {
- if (!ref) return nil;
- self = super.init;
- if (!self) return nil;
- _ref = ref;
- _allowWWAN = YES;
- if (NSFoundationVersionNumber >= NSFoundationVersionNumber_iOS_7_0) {
- _networkInfo = [CTTelephonyNetworkInfo new];
- }
- return self;
- }
- - (void)dealloc {
- self.notifyBlock = nil;
- self.scheduled = NO;
- CFRelease(self.ref);
- }
- - (void)setScheduled:(BOOL)scheduled {
- if (_scheduled == scheduled) return;
- _scheduled = scheduled;
- if (scheduled) {
- SCNetworkReachabilityContext context = { 0, (__bridge void *)self, NULL, NULL, NULL };
- SCNetworkReachabilitySetCallback(self.ref, YYReachabilityCallback, &context);
- SCNetworkReachabilitySetDispatchQueue(self.ref, [self.class sharedQueue]);
- } else {
- SCNetworkReachabilitySetDispatchQueue(self.ref, NULL);
- }
- }
- - (SCNetworkReachabilityFlags)flags {
- SCNetworkReachabilityFlags flags = 0;
- SCNetworkReachabilityGetFlags(self.ref, &flags);
- return flags;
- }
- - (YYReachabilityStatus)status {
- return YYReachabilityStatusFromFlags(self.flags, self.allowWWAN);
- }
- - (YYReachabilityWWANStatus)wwanStatus {
- if (!self.networkInfo) return YYReachabilityWWANStatusNone;
- NSString *status = self.networkInfo.currentRadioAccessTechnology;
- if (!status) return YYReachabilityWWANStatusNone;
- static NSDictionary *dic;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- dic = @{CTRadioAccessTechnologyGPRS : @(YYReachabilityWWANStatus2G), // 2.5G 171Kbps
- CTRadioAccessTechnologyEdge : @(YYReachabilityWWANStatus2G), // 2.75G 384Kbps
- CTRadioAccessTechnologyWCDMA : @(YYReachabilityWWANStatus3G), // 3G 3.6Mbps/384Kbps
- CTRadioAccessTechnologyHSDPA : @(YYReachabilityWWANStatus3G), // 3.5G 14.4Mbps/384Kbps
- CTRadioAccessTechnologyHSUPA : @(YYReachabilityWWANStatus3G), // 3.75G 14.4Mbps/5.76Mbps
- CTRadioAccessTechnologyCDMA1x : @(YYReachabilityWWANStatus3G), // 2.5G
- CTRadioAccessTechnologyCDMAEVDORev0 : @(YYReachabilityWWANStatus3G),
- CTRadioAccessTechnologyCDMAEVDORevA : @(YYReachabilityWWANStatus3G),
- CTRadioAccessTechnologyCDMAEVDORevB : @(YYReachabilityWWANStatus3G),
- CTRadioAccessTechnologyeHRPD : @(YYReachabilityWWANStatus3G),
- CTRadioAccessTechnologyLTE : @(YYReachabilityWWANStatus4G)}; // LTE:3.9G 150M/75M LTE-Advanced:4G 300M/150M
- });
- NSNumber *num = dic[status];
- if (num != nil) return num.unsignedIntegerValue;
- else return YYReachabilityWWANStatusNone;
- }
- - (BOOL)isReachable {
- return self.status != YYReachabilityStatusNone;
- }
- + (instancetype)reachability {
- return self.new;
- }
- + (instancetype)reachabilityForLocalWifi {
- struct sockaddr_in localWifiAddress;
- bzero(&localWifiAddress, sizeof(localWifiAddress));
- localWifiAddress.sin_len = sizeof(localWifiAddress);
- localWifiAddress.sin_family = AF_INET;
- localWifiAddress.sin_addr.s_addr = htonl(IN_LINKLOCALNETNUM);
- YYReachability *one = [self reachabilityWithAddress:(const struct sockaddr *)&localWifiAddress];
- one.allowWWAN = NO;
- return one;
- }
- + (instancetype)reachabilityWithHostname:(NSString *)hostname {
- SCNetworkReachabilityRef ref = SCNetworkReachabilityCreateWithName(NULL, [hostname UTF8String]);
- return [[self alloc] initWithRef:ref];
- }
- + (instancetype)reachabilityWithAddress:(const struct sockaddr *)hostAddress {
- SCNetworkReachabilityRef ref = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *)hostAddress);
- return [[self alloc] initWithRef:ref];
- }
- - (void)setNotifyBlock:(void (^)(YYReachability *reachability))notifyBlock {
- _notifyBlock = [notifyBlock copy];
- self.scheduled = (self.notifyBlock != nil);
- }
- @end
|