From dbafc29e60aba1d5b24c2b0d321834c40e0b9bca Mon Sep 17 00:00:00 2001 From: Adam Burdette Date: Tue, 27 Feb 2018 14:11:51 -0800 Subject: [PATCH] Fix #8615: NetInfo.isConnected for iOS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: This is fixing #8615. The problem was that, on initialization, the `_connectionType` variable was still set to its default value of `RCTConnectionTypeUnknown`. The exposed API method did nothing to determine this unless a subscription had be established and then the method would simply return the last reported value. Instead, the exposed oneshot API call now actually checks the connection status through the same methods as the subscription and updates RCTNetInfo’s values before returning. In order to avoid reporting events without a subscription, a flag is set and unset on calls to start/stopObserving. - start app - observe the (in)correct reporting of the manual status - change network status to offline - press refresh - observe the manual fetch - start subscription - change network status to online - press refresh to show that the manual refresh works (only now working for current RN version) - change network status to offline - stop subscription - change network status to online - press refresh to show manual refresh does(n't) work without subscription - start subscription to show it updates to current Current Behavior: https://drive.google.com/file/d/1Ods6HORgp_vfm1mQVjGwhtH1D7issxjo/view?usp=sharing Fixed Behavior: https://drive.google.com/file/d/11H1UOF33LeMGvXEOoapU62ARDSb7qoYv/view?usp=sharing [IOS] [BUGFIX] [Libraries\Network\RCTNetInfo.m] - Fixed #8615, `iOS: NetInfo.isConnected returns always false`, by decoupling the fetch from the status of the subscription. Closes https://github.com/facebook/react-native/pull/17397 Differential Revision: D7102771 Pulled By: hramos fbshipit-source-id: ea11eb0b1a7ca641fc43da2fe172cf7b2597de4a --- Libraries/Network/RCTNetInfo.m | 101 ++++++++++++++++++++------------- 1 file changed, 61 insertions(+), 40 deletions(-) diff --git a/Libraries/Network/RCTNetInfo.m b/Libraries/Network/RCTNetInfo.m index e41079b89699cd..afc3d1db33334c 100644 --- a/Libraries/Network/RCTNetInfo.m +++ b/Libraries/Network/RCTNetInfo.m @@ -41,6 +41,7 @@ @implementation RCTNetInfo NSString *_effectiveConnectionType; NSString *_statusDeprecated; NSString *_host; + BOOL _isObserving; } RCT_EXPORT_MODULE() @@ -48,6 +49,61 @@ @implementation RCTNetInfo static void RCTReachabilityCallback(__unused SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void *info) { RCTNetInfo *self = (__bridge id)info; + if ([self setReachabilityStatus:flags] && self->_isObserving) { + [self sendEventWithName:@"networkStatusDidChange" body:@{@"connectionType": self->_connectionType, + @"effectiveConnectionType": self->_effectiveConnectionType, + @"network_info": self->_statusDeprecated}]; + } +} + +#pragma mark - Lifecycle + +- (instancetype)initWithHost:(NSString *)host +{ + RCTAssertParam(host); + RCTAssert(![host hasPrefix:@"http"], @"Host value should just contain the domain, not the URL scheme."); + + if ((self = [self init])) { + _host = [host copy]; + } + return self; +} + +- (NSArray *)supportedEvents +{ + return @[@"networkStatusDidChange"]; +} + +- (void)startObserving +{ + _isObserving = YES; + _connectionType = RCTConnectionTypeUnknown; + _effectiveConnectionType = RCTEffectiveConnectionTypeUnknown; + _statusDeprecated = RCTReachabilityStateUnknown; + _reachability = [self getReachabilityRef]; +} + +- (void)stopObserving +{ + _isObserving = NO; + if (_reachability) { + SCNetworkReachabilityUnscheduleFromRunLoop(_reachability, CFRunLoopGetMain(), kCFRunLoopCommonModes); + CFRelease(_reachability); + } +} + +- (SCNetworkReachabilityRef)getReachabilityRef +{ + SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, _host.UTF8String ?: "apple.com"); + SCNetworkReachabilityContext context = { 0, ( __bridge void *)self, NULL, NULL, NULL }; + SCNetworkReachabilitySetCallback(reachability, RCTReachabilityCallback, &context); + SCNetworkReachabilityScheduleWithRunLoop(reachability, CFRunLoopGetMain(), kCFRunLoopCommonModes); + + return reachability; +} + +- (BOOL)setReachabilityStatus:(SCNetworkReachabilityFlags)flags +{ NSString *connectionType = RCTConnectionTypeUnknown; NSString *effectiveConnectionType = RCTEffectiveConnectionTypeUnknown; NSString *status = RCTReachabilityStateUnknown; @@ -96,47 +152,10 @@ static void RCTReachabilityCallback(__unused SCNetworkReachabilityRef target, SC self->_connectionType = connectionType; self->_effectiveConnectionType = effectiveConnectionType; self->_statusDeprecated = status; - [self sendEventWithName:@"networkStatusDidChange" body:@{@"connectionType": connectionType, - @"effectiveConnectionType": effectiveConnectionType, - @"network_info": status}]; - } -} - -#pragma mark - Lifecycle - -- (instancetype)initWithHost:(NSString *)host -{ - RCTAssertParam(host); - RCTAssert(![host hasPrefix:@"http"], @"Host value should just contain the domain, not the URL scheme."); - - if ((self = [self init])) { - _host = [host copy]; - } - return self; -} - -- (NSArray *)supportedEvents -{ - return @[@"networkStatusDidChange"]; -} - -- (void)startObserving -{ - _connectionType = RCTConnectionTypeUnknown; - _effectiveConnectionType = RCTEffectiveConnectionTypeUnknown; - _statusDeprecated = RCTReachabilityStateUnknown; - _reachability = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, _host.UTF8String ?: "apple.com"); - SCNetworkReachabilityContext context = { 0, ( __bridge void *)self, NULL, NULL, NULL }; - SCNetworkReachabilitySetCallback(_reachability, RCTReachabilityCallback, &context); - SCNetworkReachabilityScheduleWithRunLoop(_reachability, CFRunLoopGetMain(), kCFRunLoopCommonModes); -} - -- (void)stopObserving -{ - if (_reachability) { - SCNetworkReachabilityUnscheduleFromRunLoop(_reachability, CFRunLoopGetMain(), kCFRunLoopCommonModes); - CFRelease(_reachability); + return YES; } + + return NO; } #pragma mark - Public API @@ -144,6 +163,8 @@ - (void)stopObserving RCT_EXPORT_METHOD(getCurrentConnectivity:(RCTPromiseResolveBlock)resolve reject:(__unused RCTPromiseRejectBlock)reject) { + SCNetworkReachabilityRef reachability = [self getReachabilityRef]; + CFRelease(reachability); resolve(@{@"connectionType": _connectionType ?: RCTConnectionTypeUnknown, @"effectiveConnectionType": _effectiveConnectionType ?: RCTEffectiveConnectionTypeUnknown, @"network_info": _statusDeprecated ?: RCTReachabilityStateUnknown});