From 310aef9dcc5266d5be76c985295dced3e2087d94 Mon Sep 17 00:00:00 2001 From: Eric Vicenti Date: Mon, 16 Mar 2015 13:57:43 -0700 Subject: [PATCH] [ReactNative] NetworkInformation.reachability API w/ example --- Examples/UIExplorer/NetInfoExample.js | 135 +++++++++++++++++++++++ Examples/UIExplorer/UIExplorerList.js | 1 + Libraries/AppState/AppState.js | 18 ---- Libraries/Network/NetInfo.js | 143 +++++++++++++++++++++++++ Libraries/react-native/react-native.js | 1 + 5 files changed, 280 insertions(+), 18 deletions(-) create mode 100644 Examples/UIExplorer/NetInfoExample.js create mode 100644 Libraries/Network/NetInfo.js diff --git a/Examples/UIExplorer/NetInfoExample.js b/Examples/UIExplorer/NetInfoExample.js new file mode 100644 index 000000000..017da9921 --- /dev/null +++ b/Examples/UIExplorer/NetInfoExample.js @@ -0,0 +1,135 @@ +/** + * Copyright 2004-present Facebook. All Rights Reserved. + */ +'use strict'; + +var React = require('react-native'); +var { + NetInfo, + Text, + View +} = React; + +var ReachabilitySubscription = React.createClass({ + getInitialState() { + return { + reachabilityHistory: [], + }; + }, + componentDidMount: function() { + NetInfo.reachabilityIOS.addEventListener( + 'change', + this._handleReachabilityChange + ); + }, + componentWillUnmount: function() { + NetInfo.reachabilityIOS.removeEventListener( + 'change', + this._handleReachabilityChange + ); + }, + _handleReachabilityChange: function(reachability) { + var reachabilityHistory = this.state.reachabilityHistory.slice(); + reachabilityHistory.push(reachability); + this.setState({ + reachabilityHistory, + }); + }, + render() { + return ( + + {JSON.stringify(this.state.reachabilityHistory)} + + ); + } +}); + +var ReachabilityCurrent = React.createClass({ + getInitialState() { + return { + reachability: null, + }; + }, + componentDidMount: function() { + NetInfo.reachabilityIOS.addEventListener( + 'change', + this._handleReachabilityChange + ); + NetInfo.reachabilityIOS.fetch().done( + (reachability) => { this.setState({reachability}); } + ); + }, + componentWillUnmount: function() { + NetInfo.reachabilityIOS.removeEventListener( + 'change', + this._handleReachabilityChange + ); + }, + _handleReachabilityChange: function(reachability) { + this.setState({ + reachability, + }); + }, + render() { + return ( + + {this.state.reachability} + + ); + } +}); + +var IsConnected = React.createClass({ + getInitialState() { + return { + isConnected: null, + }; + }, + componentDidMount: function() { + NetInfo.isConnected.addEventListener( + 'change', + this._handleConnectivityChange + ); + NetInfo.isConnected.fetch().done( + (isConnected) => { this.setState({isConnected}); } + ); + }, + componentWillUnmount: function() { + NetInfo.isConnected.removeEventListener( + 'change', + this._handleConnectivityChange + ); + }, + _handleConnectivityChange: function(isConnected) { + this.setState({ + isConnected, + }); + }, + render() { + return ( + + {this.state.isConnected ? 'Online' : 'Offline'} + + ); + } +}); + +exports.title = 'NetInfo'; +exports.description = 'Monitor network status'; +exports.examples = [ + { + title: 'NetInfo.isConnected', + description: 'Asyncronously load and observe connectivity', + render() { return ; } + }, + { + title: 'NetInfo.reachabilityIOS', + description: 'Asyncronously load and observe iOS reachability', + render() { return ; } + }, + { + title: 'NetInfo.reachabilityIOS', + description: 'Observed updates to iOS reachability', + render() { return ; } + }, +]; diff --git a/Examples/UIExplorer/UIExplorerList.js b/Examples/UIExplorer/UIExplorerList.js index b7108681e..a4f70fbcd 100644 --- a/Examples/UIExplorer/UIExplorerList.js +++ b/Examples/UIExplorer/UIExplorerList.js @@ -42,6 +42,7 @@ var EXAMPLES = [ require('./MapViewExample'), require('./WebViewExample'), require('./AppStateIOSExample'), + require('./NetInfoExample'), require('./AlertIOSExample'), require('./AdSupportIOSExample'), require('./AppStateExample'), diff --git a/Libraries/AppState/AppState.js b/Libraries/AppState/AppState.js index 43b9db1a5..ca5a7e607 100644 --- a/Libraries/AppState/AppState.js +++ b/Libraries/AppState/AppState.js @@ -25,22 +25,4 @@ var AppState = { }; -// This check avoids redboxing if native RKReachability library isn't included in app -// TODO: Move reachability API into separate JS module to prevent need for this -if (RKReachability) { - AppState.networkReachability = new Subscribable( - RCTDeviceEventEmitter, - 'reachabilityDidChange', - (resp) => resp.network_reachability, - RKReachability.getCurrentReachability - ); -} - -AppState.NetworkReachability = keyMirror({ - wifi: true, - cell: true, - none: true, - unknown: true, -}); - module.exports = AppState; diff --git a/Libraries/Network/NetInfo.js b/Libraries/Network/NetInfo.js new file mode 100644 index 000000000..59c29cb07 --- /dev/null +++ b/Libraries/Network/NetInfo.js @@ -0,0 +1,143 @@ +/** + * Copyright 2004-present Facebook. All Rights Reserved. + * + * @providesModule NetInfo + * @flow + */ +'use strict'; + +var NativeModules = require('NativeModules'); +var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter'); +var RKReachability = NativeModules.RKReachability; + +var DEVICE_REACHABILITY_EVENT = 'reachabilityDidChange'; + +type ChangeEventName = $Enum<{ + change: string; +}>; + + +/** + * NetInfo exposes info about online/offline status + * + * == iOS Reachability + * + * Asyncronously determine if the device is online and on a cellular network. + * + * - "none" - device is offline + * - "wifi" - device is online and connected via wifi, or is the iOS simulator + * - "cell" - device is connected via Edge, 3G, WiMax, or LTE + * - "unknown" - error case and the network status is unknown + * + * ``` + * NetInfo.reachabilityIOS.fetch().done((reach) => { + * console.log('Initial: ' + reach); + * }); + * function handleFirstReachabilityChange(reach) { + * console.log('First change: ' + reach); + * NetInfo.reachabilityIOS.removeEventListener( + * 'change', + * handleFirstReachabilityChange + * ); + * } + * NetInfo.reachabilityIOS.addEventListener( + * 'change', + * handleFirstReachabilityChange + * ); + * ``` + */ + +var NetInfo = {}; + +if (RKReachability) { + var _reachabilitySubscriptions = {}; + + NetInfo.reachabilityIOS = { + addEventListener: function ( + eventName: ChangeEventName, + handler: Function + ): void { + _reachabilitySubscriptions[handler] = RCTDeviceEventEmitter.addListener( + DEVICE_REACHABILITY_EVENT, + (appStateData) => { + handler(appStateData.network_reachability); + } + ); + }, + + removeEventListener: function( + eventName: ChangeEventName, + handler: Function + ): void { + if (!_reachabilitySubscriptions[handler]) { + return; + } + _reachabilitySubscriptions[handler].remove(); + _reachabilitySubscriptions[handler] = null; + }, + + fetch: function(): Promise { + return new Promise((resolve, reject) => { + RKReachability.getCurrentReachability( + (resp) => { + resolve(resp.network_reachability); + }, + reject + ); + }); + }, + }; + + /** + * + * == NetInfo.isConnected + * + * Available on all platforms. Asyncronously fetch a boolean to determine + * internet connectivity. + * + * ``` + * NetInfo.isConnected.fetch().done((isConnected) => { + * console.log('First, is ' + (isConnected ? 'online' : 'offline')); + * }); + * function handleFirstConnectivityChange(isConnected) { + * console.log('Then, is ' + (isConnected ? 'online' : 'offline')); + * NetInfo.isConnected.removeEventListener( + * 'change', + * handleFirstConnectivityChange + * ); + * } + * NetInfo.isConnected.addEventListener( + * 'change', + * handleFirstConnectivityChange + * ); + * ``` + * + */ + var _isConnectedSubscriptions = {}; + NetInfo.isConnected = { + addEventListener: function ( + eventName: ChangeEventName, + handler: Function + ): void { + _isConnectedSubscriptions[handler] = (reachability) => { + handler(reachability !== 'none'); + }; + NetInfo.reachabilityIOS.addEventListener(eventName, _isConnectedSubscriptions[handler]); + }, + + removeEventListener: function( + eventName: ChangeEventName, + handler: Function + ): void { + NetInfo.reachabilityIOS.removeEventListener(eventName, _isConnectedSubscriptions[handler]); + }, + + fetch: function(): Promise { + return NetInfo.reachabilityIOS.fetch().then( + (reachability) => reachability !== 'none' + ); + }, + }; +} + +module.exports = NetInfo; diff --git a/Libraries/react-native/react-native.js b/Libraries/react-native/react-native.js index 00be3f65a..5e164b5fc 100644 --- a/Libraries/react-native/react-native.js +++ b/Libraries/react-native/react-native.js @@ -24,6 +24,7 @@ var ReactNative = { ListViewDataSource: require('ListViewDataSource'), MapView: require('MapView'), NavigatorIOS: require('NavigatorIOS'), + NetInfo: require('NetInfo'), PickerIOS: require('PickerIOS'), PixelRatio: require('PixelRatio'), ScrollView: require('ScrollView'),