From bd271bbf70e95397e098ede172424bd042e2e304 Mon Sep 17 00:00:00 2001 From: mengyanluo Date: Fri, 11 Jun 2021 18:01:15 +0800 Subject: [PATCH] feat(ios): users can get cell type from hippynetinfo module --- .../HippyDemo.xcodeproj/project.pbxproj | 24 +- ios/sdk/module/netinfo/HippyNetInfo.h | 2 - ios/sdk/module/netinfo/HippyNetInfo.m | 123 +++-------- ios/sdk/module/netinfo/HippyNetInfoIntenal.h | 68 ++++++ ios/sdk/module/netinfo/HippyNetInfoIntenal.m | 205 ++++++++++++++++++ 5 files changed, 304 insertions(+), 118 deletions(-) create mode 100644 ios/sdk/module/netinfo/HippyNetInfoIntenal.h create mode 100644 ios/sdk/module/netinfo/HippyNetInfoIntenal.m diff --git a/examples/ios-demo/HippyDemo.xcodeproj/project.pbxproj b/examples/ios-demo/HippyDemo.xcodeproj/project.pbxproj index bab5b5320..d23b539ad 100644 --- a/examples/ios-demo/HippyDemo.xcodeproj/project.pbxproj +++ b/examples/ios-demo/HippyDemo.xcodeproj/project.pbxproj @@ -171,6 +171,7 @@ 85BCD46F2578C58000638DB4 /* js_native_api_jsc.cc in Sources */ = {isa = PBXBuildFile; fileRef = 85BCD4342578C58000638DB4 /* js_native_api_jsc.cc */; }; 85BCD47C257A0AFE00638DB4 /* ios_loader.cc in Sources */ = {isa = PBXBuildFile; fileRef = 85BCD477257A0AFD00638DB4 /* ios_loader.cc */; }; AC63515623F92C99007FABA5 /* TTTGB-Medium.otf in Resources */ = {isa = PBXBuildFile; fileRef = AC63515523F92C99007FABA5 /* TTTGB-Medium.otf */; }; + F43BE80F26733F620080999C /* HippyNetInfoIntenal.m in Sources */ = {isa = PBXBuildFile; fileRef = F43BE80E26733F620080999C /* HippyNetInfoIntenal.m */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -475,7 +476,6 @@ 06FF8EED2511C20900C03900 /* NSData+DataType.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSData+DataType.h"; sourceTree = ""; }; 06FF8EEE2511C20900C03900 /* NSData+DataType.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSData+DataType.m"; sourceTree = ""; }; 851AD1F32656388E007AF2B0 /* string_view_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = string_view_utils.h; sourceTree = ""; }; - 851AD1F42656455D007AF2B0 /* unicode_string_view.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = unicode_string_view.h; sourceTree = ""; }; 851AD1F526564568007AF2B0 /* unicode_string_view.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = unicode_string_view.cc; sourceTree = ""; }; 854FC5C8262F0D88002EAD41 /* logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = logging.h; sourceTree = ""; }; 854FC5C9262F0D88002EAD41 /* log_level.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = log_level.h; sourceTree = ""; }; @@ -539,6 +539,8 @@ 85BCD475257A0AFD00638DB4 /* ios_loader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ios_loader.h; sourceTree = ""; }; 85BCD477257A0AFD00638DB4 /* ios_loader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ios_loader.cc; sourceTree = ""; }; AC63515523F92C99007FABA5 /* TTTGB-Medium.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "TTTGB-Medium.otf"; sourceTree = ""; }; + F43BE80D26733F620080999C /* HippyNetInfoIntenal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HippyNetInfoIntenal.h; sourceTree = ""; }; + F43BE80E26733F620080999C /* HippyNetInfoIntenal.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HippyNetInfoIntenal.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -719,6 +721,8 @@ children = ( 064C58EC23AB1A51001E80DD /* HippyNetInfo.h */, 064C58ED23AB1A51001E80DD /* HippyNetInfo.m */, + F43BE80D26733F620080999C /* HippyNetInfoIntenal.h */, + F43BE80E26733F620080999C /* HippyNetInfoIntenal.m */, ); path = netinfo; sourceTree = ""; @@ -1279,7 +1283,6 @@ children = ( 85BCD3EC2578C57F00638DB4 /* engine.h */, 85BCD3ED2578C57F00638DB4 /* core.h */, - 85BCD3EE2578C57F00638DB4 /* platform */, 85BCD3F02578C57F00638DB4 /* task */, 85BCD3F52578C57F00638DB4 /* modules */, 85BCD3FB2578C57F00638DB4 /* scope.h */, @@ -1289,14 +1292,6 @@ path = core; sourceTree = ""; }; - 85BCD3EE2578C57F00638DB4 /* platform */ = { - isa = PBXGroup; - children = ( - 85BCD3EF2578C57F00638DB4 /* logging_impl.h */, - ); - path = platform; - sourceTree = ""; - }; 85BCD3F02578C57F00638DB4 /* task */ = { isa = PBXGroup; children = ( @@ -1365,7 +1360,6 @@ children = ( 85BCD4152578C58000638DB4 /* scope.cc */, 85BCD4162578C58000638DB4 /* engine.cc */, - 85BCD4172578C58000638DB4 /* platform */, 85BCD4192578C58000638DB4 /* task */, 85BCD41E2578C58000638DB4 /* modules */, 85BCD4232578C58000638DB4 /* base */, @@ -1374,13 +1368,6 @@ path = src; sourceTree = ""; }; - 85BCD4172578C58000638DB4 /* platform */ = { - isa = PBXGroup; - children = ( - ); - path = platform; - sourceTree = ""; - }; 85BCD4192578C58000638DB4 /* task */ = { isa = PBXGroup; children = ( @@ -1642,6 +1629,7 @@ 064C5A0B23AB1A51001E80DD /* HippyRefreshWrapperItemViewManager.m in Sources */, 064C5A1323AB1A51001E80DD /* HippyTextViewManager.mm in Sources */, 854FC5E5262F0D88002EAD41 /* log_settings.cc in Sources */, + F43BE80F26733F620080999C /* HippyNetInfoIntenal.m in Sources */, 0612F03423A8BE330079E622 /* main.m in Sources */, 064C5A5623AB1A51001E80DD /* HippyModuleData.mm in Sources */, 064C5A4723AB1A51001E80DD /* HippyTouchHandler.m in Sources */, diff --git a/ios/sdk/module/netinfo/HippyNetInfo.h b/ios/sdk/module/netinfo/HippyNetInfo.h index 9193f94f8..a1da3614f 100644 --- a/ios/sdk/module/netinfo/HippyNetInfo.h +++ b/ios/sdk/module/netinfo/HippyNetInfo.h @@ -27,6 +27,4 @@ @interface HippyNetInfo : HippyEventObserverModule -- (instancetype)initWithHost:(NSString *)host; - @end diff --git a/ios/sdk/module/netinfo/HippyNetInfo.m b/ios/sdk/module/netinfo/HippyNetInfo.m index c91ba8d2d..37d8e6f8e 100644 --- a/ios/sdk/module/netinfo/HippyNetInfo.m +++ b/ios/sdk/module/netinfo/HippyNetInfo.m @@ -25,108 +25,49 @@ #import "HippyAssert.h" #import "HippyBridge.h" #import "HippyEventDispatcher.h" -#import "netinet/in.h" +#import "HippyNetInfoIntenal.h" -static NSString *const HippyReachabilityStateUnknown = @"UNKNOWN"; -static NSString *const HippyReachabilityStateNone = @"NONE"; -static NSString *const HippyReachabilityStateWifi = @"WIFI"; -static NSString *const HippyReachabilityStateCell = @"CELL"; +@interface HippyNetInfo () { +} -@implementation HippyNetInfo { - SCNetworkReachabilityRef _reachability; - NSString *_networkType; - NSString *_host; +@end + +@implementation HippyNetInfo + +static NSDictionary *callbackParamFromCellType(HippyNetworkTypeObject *object) { + if (!object) { + return @{}; + } + NSString *networkType = object.networkType?:HippyNetworkTypeUnknown; + NSString *cellType = object.cellType?:HippNetworkCellTypeUnknown; + return @{@"network_info": networkType, @"network_type":cellType}; } HIPPY_EXPORT_MODULE() -static NSString *hippyReachabilityTypeFromFlags(SCNetworkReachabilityFlags flags) { - NSString *networkType = HippyReachabilityStateUnknown; - if ((flags & kSCNetworkReachabilityFlagsReachable) == 0 || (flags & kSCNetworkReachabilityFlagsConnectionRequired) != 0) { - networkType = HippyReachabilityStateNone; - } else if ((flags & kSCNetworkReachabilityFlagsIsWWAN) != 0) { - networkType = HippyReachabilityStateCell; - } else { - networkType = HippyReachabilityStateWifi; - } - return networkType; -} - -static NSString *currentReachabilityType(SCNetworkReachabilityRef reachabilityRef) { - SCNetworkReachabilityFlags flags; - BOOL success = SCNetworkReachabilityGetFlags(reachabilityRef, &flags); - if (success) { - NSString *type = hippyReachabilityTypeFromFlags(flags); - return type ?: HippyReachabilityStateUnknown; - } else { - return HippyReachabilityStateUnknown; - } -} - -static SCNetworkReachabilityRef createReachabilityRefWithZeroAddress() { - struct sockaddr_in zeroAddress; - bzero(&zeroAddress, sizeof(zeroAddress)); - zeroAddress.sin_len = sizeof(zeroAddress); - zeroAddress.sin_family = AF_INET; - SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (struct sockaddr *)&zeroAddress); - return reachability; -} - -static void HippyReachabilityCallback(__unused SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void *info) { - HippyNetInfo *self = (__bridge id)info; - NSString *networkType = hippyReachabilityTypeFromFlags(flags); - if (![networkType isEqualToString:self->_networkType]) { - self->_networkType = networkType; - [self sendEvent:@"networkStatusDidChange" params:@ { @"network_info": networkType }]; - } -} - -#pragma mark - Lifecycle - -- (instancetype)initWithHost:(NSString *)host { - HippyAssertParam(host); - HippyAssert(![host hasPrefix:@"http"], @"Host value should just contain the domain, not the URL scheme."); - - if ((self = [self init])) { - _host = [host copy]; - } - return self; -} - - (void)addEventObserverForName:(NSString *)eventName { if ([eventName isEqualToString:@"networkStatusDidChange"]) { - if (!_reachability) { - _reachability = createReachabilityRefWithZeroAddress(); - SCNetworkReachabilityContext context = { 0, (__bridge void *)self, NULL, NULL, NULL }; - SCNetworkReachabilitySetCallback(_reachability, HippyReachabilityCallback, &context); - SCNetworkReachabilityScheduleWithRunLoop(_reachability, CFRunLoopGetMain(), kCFRunLoopCommonModes); - } - _networkType = currentReachabilityType(_reachability); - [self sendEvent:@"networkStatusDidChange" params:@{ @"network_info": _networkType }]; + HippyNetworkTypeObject *networkType = [[HippyNetInfoIntenal sharedInstance] addNetworkTypeChangeObserver:self]; + NSDictionary *params = callbackParamFromCellType(networkType); + [self sendEvent:@"networkStatusDidChange" params:params]; + } } - (void)removeEventObserverForName:(NSString *)eventName { if ([eventName isEqualToString:@"networkStatusDidChange"]) { - [self releaseReachability]; + [[HippyNetInfoIntenal sharedInstance] removeNetworkTypeChangeObserver:self]; } } - (void)invalidate { - [self releaseReachability]; } -- (void)releaseReachability { - if (_reachability) { - SCNetworkReachabilityUnscheduleFromRunLoop(_reachability, CFRunLoopGetMain(), kCFRunLoopCommonModes); - CFRelease(_reachability); - _reachability = NULL; - } +- (void)hippyNetworkTypeChanged:(HippyNetworkTypeObject *)networkType { + NSDictionary *params = callbackParamFromCellType(networkType); + [self sendEvent:@"networkStatusDidChange" params:params]; } -- (void)dealloc { - [self releaseReachability]; -} #pragma mark - Public API // clang-format off @@ -135,23 +76,9 @@ HIPPY_EXPORT_METHOD(getCurrentConnectivity:(HippyPromiseResolveBlock)resolve if (!resolve) { return; } - //return network type if it was set and not unknown type - if (_networkType) { - resolve(@{@"network_info": _networkType}); - } - //else try to get network type - else { - SCNetworkReachabilityRef reachability = NULL; - if (_reachability) { - reachability = CFRetain(_reachability); - } - else { - reachability = createReachabilityRefWithZeroAddress(); - } - NSString *type = currentReachabilityType(reachability); - resolve(@{@"network_info": type}); - CFRelease(reachability); - } + HippyNetworkTypeObject *obj = [[HippyNetInfoIntenal sharedInstance] currentNetworkType]; + NSDictionary *dic = callbackParamFromCellType(obj); + resolve(dic); } // clang-format on diff --git a/ios/sdk/module/netinfo/HippyNetInfoIntenal.h b/ios/sdk/module/netinfo/HippyNetInfoIntenal.h new file mode 100644 index 000000000..d22c4e477 --- /dev/null +++ b/ios/sdk/module/netinfo/HippyNetInfoIntenal.h @@ -0,0 +1,68 @@ +// +// HippyNetInfoIntenal.h +// HippyDemo +// +// Created by mengyanluo on 2021/6/11. +// Copyright © 2021 tencent. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +extern NSString *const HippyNetworkTypeUnknown; +extern NSString *const HippyNetworkTypeNone; +extern NSString *const HippyNetworkTypeWifi; +extern NSString *const HippyNetworkTypeCell; + +extern NSString *const HippNetworkCellTypeUnknown; +extern NSString *const HippNetworkCellTypeNone; +extern NSString *const HippyNetworkCellType2G; +extern NSString *const HippyNetworkCellType3G; +extern NSString *const HippyNetworkCellType4G; +extern NSString *const HippyNetworkCellType5G; + +@interface HippyNetworkTypeObject : NSObject + +/** + * indicate network type + * value:HippyNetworkTypeUnknown,HippyNetworkTypeNone,HippyNetworkTypeWifi,HippyNetworkTypeCell + */ +@property(nonatomic, readonly) NSString *networkType; + +/** + * indicate cell type + */ +@property(nonatomic, readonly) NSString *cellType; + +- (instancetype)initWithNetworkType:(NSString *)networkType cellType:(NSString *)cellType; + +- (BOOL)isEqual:(id)object; + +- (BOOL)isEqualToNetowrkTypeObject:(HippyNetworkTypeObject *)object; + +@end + +@protocol HippyNetworkTypeChangedDelegate + +- (void)hippyNetworkTypeChanged:(HippyNetworkTypeObject *)networkType; + +@end + +@interface HippyNetInfoIntenal : NSObject + ++ (instancetype)sharedInstance; + +- (HippyNetworkTypeObject *)currentNetworkType; + +/** + * set an observer for network changed event. + * return current network info immediately + */ +- (HippyNetworkTypeObject *)addNetworkTypeChangeObserver:(id)observer; + +- (void)removeNetworkTypeChangeObserver:(id)observer; + +@end + +NS_ASSUME_NONNULL_END diff --git a/ios/sdk/module/netinfo/HippyNetInfoIntenal.m b/ios/sdk/module/netinfo/HippyNetInfoIntenal.m new file mode 100644 index 000000000..6da456028 --- /dev/null +++ b/ios/sdk/module/netinfo/HippyNetInfoIntenal.m @@ -0,0 +1,205 @@ +// +// HippyNetInfoIntenal.m +// HippyDemo +// +// Created by mengyanluo on 2021/6/11. +// Copyright © 2021 tencent. All rights reserved. +// + +#import "HippyNetInfoIntenal.h" +#import "HippyAssert.h" +#import "HippyBridge.h" +#import "HippyEventDispatcher.h" +#import "netinet/in.h" +#import +#import +#import + +NSString *const HippyNetworkTypeUnknown = @"UNKNOWN"; +NSString *const HippyNetworkTypeNone = @"NONE"; +NSString *const HippyNetworkTypeWifi = @"WIFI"; +NSString *const HippyNetworkTypeCell = @"CELL"; + +NSString *const HippNetworkCellTypeUnknown = @"UNKNOWN"; +NSString *const HippNetworkCellTypeNone = @"NONE"; +NSString *const HippyNetworkCellType2G = @"2G"; +NSString *const HippyNetworkCellType3G = @"3G"; +NSString *const HippyNetworkCellType4G = @"4G"; +NSString *const HippyNetworkCellType5G = @"5G"; + +static HippyNetInfoIntenal *instance = nil; + +@implementation HippyNetworkTypeObject + +- (instancetype)initWithNetworkType:(NSString *)networkType cellType:(NSString *)cellType { + self = [super init]; + if (self) { + _networkType = networkType; + _cellType = cellType; + } + return self; +} + +- (BOOL)isEqual:(id)object { + return [self isEqualToNetowrkTypeObject:object]; +} + +- (BOOL)isEqualToNetowrkTypeObject:(HippyNetworkTypeObject *)object { + if ([object isKindOfClass:[HippyNetworkTypeObject class]]) { + if ([self.networkType isEqualToString:object.networkType] && + [self.cellType isEqualToString:object.cellType]) { + return YES; + } + } + return NO; +} + +@end + +@interface HippyNetInfoIntenal () { + SCNetworkReachabilityRef _reachability; + NSString *_networkType; + NSString *_host; + CTTelephonyNetworkInfo *_cellNetType; + NSHashTable *_observers; +} + +@end + +@implementation HippyNetInfoIntenal + +static NSString *hippyReachabilityGetCellType(NSString *cellType) { + if ([cellType isEqualToString:CTRadioAccessTechnologyEdge] || + [cellType isEqualToString:CTRadioAccessTechnologyGPRS] || + [cellType isEqualToString:CTRadioAccessTechnologyCDMA1x]) { + return HippyNetworkCellType2G; + } + else if ([cellType isEqualToString:CTRadioAccessTechnologyHSDPA] || + [cellType isEqualToString:CTRadioAccessTechnologyWCDMA] || + [cellType isEqualToString:CTRadioAccessTechnologyHSUPA] || + [cellType isEqualToString:CTRadioAccessTechnologyCDMAEVDORev0] || + [cellType isEqualToString:CTRadioAccessTechnologyCDMAEVDORevA] || + [cellType isEqualToString:CTRadioAccessTechnologyCDMAEVDORevB] || + [cellType isEqualToString:CTRadioAccessTechnologyeHRPD]) { + return HippyNetworkCellType3G; + } + else if ([cellType isEqualToString:CTRadioAccessTechnologyLTE]) { + return HippyNetworkCellType4G; + } + else if (@available(iOS 14.1, *)) { + if ([cellType isEqualToString:CTRadioAccessTechnologyNRNSA] || + [cellType isEqualToString:CTRadioAccessTechnologyNR]) { + return HippyNetworkCellType5G; + } + } + return HippNetworkCellTypeUnknown; +} + +static SCNetworkReachabilityRef createReachabilityRefWithZeroAddress() { + struct sockaddr_in zeroAddress; + bzero(&zeroAddress, sizeof(zeroAddress)); + zeroAddress.sin_len = sizeof(zeroAddress); + zeroAddress.sin_family = AF_INET; + SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (struct sockaddr *)&zeroAddress); + return reachability; +} + +static NSString *hippyReachabilityTypeFromFlags(SCNetworkReachabilityFlags flags) { + NSString *networkType = HippyNetworkTypeUnknown; + if ((flags & kSCNetworkReachabilityFlagsReachable) == 0 || (flags & kSCNetworkReachabilityFlagsConnectionRequired) != 0) { + networkType = HippNetworkCellTypeNone; + } else if ((flags & kSCNetworkReachabilityFlagsIsWWAN) != 0) { + networkType = HippyNetworkTypeCell; + } else { + networkType = HippyNetworkTypeWifi; + } + return networkType; +} + +static NSString *currentReachabilityType(SCNetworkReachabilityRef reachabilityRef) { + SCNetworkReachabilityFlags flags; + BOOL success = SCNetworkReachabilityGetFlags(reachabilityRef, &flags); + if (success) { + NSString *type = hippyReachabilityTypeFromFlags(flags); + return type ?: HippyNetworkTypeUnknown; + } else { + return HippyNetworkTypeUnknown; + } +} + +static void reachabilityCallback(__unused SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void *info) { + HippyNetInfoIntenal *netinfo = (__bridge HippyNetInfoIntenal *)info; + NSString *networkType = hippyReachabilityTypeFromFlags(flags); + NSString *cellType = hippyReachabilityGetCellType(netinfo->_cellNetType.currentRadioAccessTechnology); + HippyNetworkTypeObject *obj = [[HippyNetworkTypeObject alloc] initWithNetworkType:networkType cellType:cellType]; + [netinfo notifyObserversNetworkTypeChanged:obj]; +} + ++ (instancetype)sharedInstance { + return [[self alloc] init]; +} + +- (instancetype)init { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + instance = [super init]; + [instance setup]; + }); + return instance; +} + +- (void)setup { + _observers = [NSHashTable weakObjectsHashTable]; + _reachability = createReachabilityRefWithZeroAddress(); + _cellNetType = [[CTTelephonyNetworkInfo alloc] init]; + + [self registerNetworkChangedListener]; + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(radioAccessTechnologyDidChange:) name:CTRadioAccessTechnologyDidChangeNotification object:nil]; +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +- (void)radioAccessTechnologyDidChange:(NSNotification *)notification { + HippyNetworkTypeObject *object = [self currentNetworkType]; + [self notifyObserversNetworkTypeChanged:object]; +} + +- (void)registerNetworkChangedListener { + SCNetworkReachabilityContext context = { 0, (__bridge void *)self, NULL, NULL, NULL }; + SCNetworkReachabilitySetCallback(_reachability, reachabilityCallback, &context); + SCNetworkReachabilityScheduleWithRunLoop(_reachability, CFRunLoopGetMain(), kCFRunLoopCommonModes); +} + +- (HippyNetworkTypeObject *)addNetworkTypeChangeObserver:(id)observer { + HippyAssert([observer respondsToSelector:@selector(hippyNetworkTypeChanged:)], @"observer shoud conform HippyNetworkTypeChangedDelegate"); + if (observer) { + [_observers addObject:observer]; + } + return [self currentNetworkType]; +} + +- (void)removeNetworkTypeChangeObserver:(id)observer { + [_observers removeObject:observer]; +} + +- (HippyNetworkTypeObject *)currentNetworkType { + NSString *networkType = currentReachabilityType(_reachability); + NSString *cellType = hippyReachabilityGetCellType(_cellNetType.currentRadioAccessTechnology); + HippyNetworkTypeObject *obj = [[HippyNetworkTypeObject alloc] initWithNetworkType:networkType cellType:cellType]; + return obj; +} + +- (void)notifyObserversNetworkTypeChanged:(HippyNetworkTypeObject *)object { + NSArray> *observers = [_observers allObjects]; + for (id observer in observers) { + HippyAssert([observer respondsToSelector:@selector(hippyNetworkTypeChanged:)], @"observer shoud conform HippyNetworkTypeChangedDelegate"); + if ([observer respondsToSelector:@selector(hippyNetworkTypeChanged:)]) { + [observer hippyNetworkTypeChanged:object]; + } + } +} + +@end