Skip to content

Commit

Permalink
feat(macos): Add in a macOS implementation of NetInfo (#312 by @tom-un)
Browse files Browse the repository at this point in the history
There is currently a known issue where the network type is incorrectly reported at `ethernet`, however, the connection status is currently correct.
  • Loading branch information
tom-un authored Mar 10, 2020
1 parent 423fa62 commit b0ad866
Show file tree
Hide file tree
Showing 28 changed files with 3,762 additions and 37 deletions.
18 changes: 18 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: CI

on: [push, pull_request]

jobs:
build:

runs-on: macOS-latest

steps:
- uses: actions/checkout@master
- uses: actions/setup-node@v1
with:
node-version: '10.x'
- name: Installing Yarn dependencies
run: yarn install --frozen-lockfile
- name: Run e2e tests
run: yarn test:e2e:macos
1 change: 1 addition & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Currently we use `flow` for typechecking, `eslint` with `prettier` for linting a
* `yarn test:jest`: Run unit tests with `jest`.
* `yarn test:detox:<android|ios>:build:<debug|release>`: Build the `debug` or `release` app for end-to-end tests with `detox` on either `android` or `ios`. You need to run this before running the test command and whenever you make changes to the native code.
* `yarn test:detox:<android|ios>:test:<debug|release>`: Run the `debug` or `release` end-to-end tests with `detox` on either `android` or `ios`.
* `yarn test:e2e:macos`: Run the end-to-end tests for macOS.

## Sending a pull request
When you're sending a pull request:
Expand Down
69 changes: 43 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@

# `@react-native-community/netinfo`

[![CircleCI Status](https://img.shields.io/circleci/project/github/react-native-community/react-native-netinfo/master.svg)](https://circleci.com/gh/react-native-community/workflows/react-native-netinfo/tree/master) ![Supports Android, iOS, and Windows](https://img.shields.io/badge/platforms-android%20|%20ios%20|%20windows-lightgrey.svg) ![MIT License](https://img.shields.io/npm/l/@react-native-community/netinfo.svg) [![Lean Core Extracted](https://img.shields.io/badge/Lean%20Core-Extracted-brightgreen.svg)](https://github.com/facebook/react-native/issues/23313)
[![CircleCI Status](https://img.shields.io/circleci/project/github/react-native-community/react-native-netinfo/master.svg)](https://circleci.com/gh/react-native-community/workflows/react-native-netinfo/tree/master) ![Supports Android, iOS, macOS, and Windows](https://img.shields.io/badge/platforms-android%20|%20ios%20|%20macos%20|%20windows-lightgrey.svg) ![MIT License](https://img.shields.io/npm/l/@react-native-community/netinfo.svg) [![Lean Core Extracted](https://img.shields.io/badge/Lean%20Core-Extracted-brightgreen.svg)](https://github.com/facebook/react-native/issues/23313)

React Native Network Info API for Android, iOS & Windows. It allows you to get information on:
React Native Network Info API for Android, iOS, macOS & Windows. It allows you to get information on:

* Connection type
* Connection quality
Expand Down Expand Up @@ -61,6 +61,10 @@ Linking the package manually is not required anymore with [Autolinking](https://
}
```

- **macOS Platform:**

Autolinking is not yet available on macOS. See the [Manual linking steps for macOS](#manual-linking-macos) below.

#### Using React Native < 0.60

You then need to link the native parts of the library for the platforms you are using. The easiest way to link the library is using the CLI tool by running this command from the root of your project:
Expand All @@ -82,6 +86,19 @@ pod 'react-native-netinfo', :path => '../node_modules/@react-native-community/ne

</details>

<details id='manual-linking-macos'>
<summary>Manually link the library on macOS</summary>

1. Open your project `.xcodeproj` on xcode.

2. Right click on the Libraries folder and select `Add files to "yourProjectName"`.

3. Add `RNCNetInfo.xcodeproj` (located at `node_modules/@react-native-community/react-native-netinfo/macos`) to your project Libraries.

4. Go to `Build Phases -> Link Binary with Libraries` and add: `libRNCNetInfo-macOS.a`.

</details>

<details>
<summary>Manually link the library on Android</summary>

Expand Down Expand Up @@ -221,7 +238,7 @@ Describes the current state of the network. It is an object with these propertie
| `type` | [`NetInfoStateType`](#netinfostatetype) | The type of the current connection. |
| `isConnected` | `boolean` | If there is an active network connection. Note that this DOES NOT mean that internet is reachable. |
| `isInternetReachable` | `boolean` | If the internet is reachable with the currently active network connection. |
| `isWifiEnabled` | `boolean` | *(Android only)* Whether the device's WiFi is ON or OFF.|
| `isWifiEnabled` | `boolean` | *(Android only)* Whether the device's WiFi is ON or OFF. |
| `details` | | The value depends on the `type` value. See below. |

The `details` value depends on the `type` value.
Expand All @@ -234,23 +251,23 @@ The `details` value depends on the `type` value.

`details` has these properties:

| Property | Platform | Type | Description |
| ----------------------- | ----------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------- |
| `isConnectionExpensive` | Android, iOS, Windows, Web | `boolean` | If the network connection is considered "expensive". This could be in either energy or monetary terms. |
| `ssid` | Android, iOS (not tvOS) | `string` | The SSID of the network. May not be present, `null`, or an empty string if it cannot be determined. **On iOS, make sure your app meets at least one of the [following requirements](https://developer.apple.com/documentation/systemconfiguration/1614126-cncopycurrentnetworkinfo?language=objc#discussion). On Android, you need to have the `ACCESS_FINE_LOCATION` permission in your `AndroidManifest.xml` and accepted by the user**. |
| `strength` | Android | `number` | An integer number from `0` to `5` for the signal strength. May not be present if the signal strength cannot be determined. |
| `ipAddress` | Android, iOS | `string` | The external IP address. Can be in IPv4 or IPv6 format. May not be present if it cannot be determined. |
| `subnet` | Android, iOS | `string` | The subnet mask in IPv4 format. May not be present if it cannot be determined. |
| Property | Platform | Type | Description |
| ----------------------- | --------------------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------- |
| `isConnectionExpensive` | Android, iOS, macOS, Windows, Web | `boolean` | If the network connection is considered "expensive". This could be in either energy or monetary terms. |
| `ssid` | Android, iOS (not tvOS) | `string` | The SSID of the network. May not be present, `null`, or an empty string if it cannot be determined. **On iOS, make sure your app meets at least one of the [following requirements](https://developer.apple.com/documentation/systemconfiguration/1614126-cncopycurrentnetworkinfo?language=objc#discussion). On Android, you need to have the `ACCESS_FINE_LOCATION` permission in your `AndroidManifest.xml` and accepted by the user**. |
| `strength` | Android | `number` | An integer number from `0` to `5` for the signal strength. May not be present if the signal strength cannot be determined. |
| `ipAddress` | Android, iOS, macOS | `string` | The external IP address. Can be in IPv4 or IPv6 format. May not be present if it cannot be determined. |
| `subnet` | Android, iOS, macOS | `string` | The subnet mask in IPv4 format. May not be present if it cannot be determined. |

##### `type` is `cellular`

`details` has these properties:

| Property | Platform | Type | Description |
| ----------------------- | -------------------------- | ------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------- |
| `isConnectionExpensive` | Android, iOS, Windows, Web | `boolean` | If the network connection is considered "expensive". This could be in either energy or monetary terms. |
| `cellularGeneration` | Android, iOS, Windows | [`NetInfoCellularGeneration`](#netinfocellulargeneration) | The generation of the cell network the user is connected to. This can give an indication of speed, but no guarantees. |
| `carrier` | Android, iOS | `string` | The network carrier name. May not be present or may be empty if none can be determined. |
| Property | Platform | Type | Description |
| ----------------------- | --------------------------------- | ------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------- |
| `isConnectionExpensive` | Android, iOS, macOS, Windows, Web | `boolean` | If the network connection is considered "expensive". This could be in either energy or monetary terms. |
| `cellularGeneration` | Android, iOS, Windows | [`NetInfoCellularGeneration`](#netinfocellulargeneration) | The generation of the cell network the user is connected to. This can give an indication of speed, but no guarantees. |
| `carrier` | Android, iOS | `string` | The network carrier name. May not be present or may be empty if none can be determined. |

##### `type` is `bluetooth`, `ethernet`, `wimax`, `vpn`, or `other`

Expand All @@ -263,17 +280,17 @@ The `details` value depends on the `type` value.
#### `NetInfoStateType`
Describes the current type of network connection. It is an enum with these possible values:

| Value | Platform | Description |
| ----------- | -------------------------- | ---------------------------------------------------------- |
| `none` | Android, iOS, Windows, Web | No network connection is active |
| `unknown` | Android, iOS, Windows, Web | The network state could not or has yet to be be determined |
| `cellular` | Android, iOS, Windows, Web | Active network over cellular |
| `wifi` | Android, iOS, Windows, Web | Active network over Wifi |
| `bluetooth` | Android, Web | Active network over Bluetooth |
| `ethernet` | Android, Windows, Web | Active network over wired ethernet |
| `wimax` | Android, Web | Active network over WiMax |
| `vpn` | Android | Active network over VPN |
| `other` | Android, iOS, Windows, Web | Active network over another type of network |
| Value | Platform | Description |
| ----------- | --------------------------------- | ---------------------------------------------------------- |
| `none` | Android, iOS, macOS, Windows, Web | No network connection is active |
| `unknown` | Android, iOS, macOS, Windows, Web | The network state could not or has yet to be be determined |
| `cellular` | Android, iOS, Windows, Web | Active network over cellular |
| `wifi` | Android, iOS, macOS, Windows, Web | Active network over Wifi |
| `bluetooth` | Android, Web | Active network over Bluetooth |
| `ethernet` | Android, macOS, Windows, Web | Active network over wired ethernet |
| `wimax` | Android, Web | Active network over WiMax |
| `vpn` | Android | Active network over VPN |
| `other` | Android, iOS, macOS, Windows, Web | Active network over another type of network |

#### `NetInfoCellularGeneration`
Describes the current generation of the `cellular` connection. It is an enum with these possible values:
Expand Down
2 changes: 1 addition & 1 deletion example/e2e/testCases/HookInitialValue.spec.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ describe('HookInitialValue', () => {
});

it('should have the correct elements to perform the test', async () => {
await expect(element(by.id('results'))).toExist();
await expect(element(by.id('result'))).toExist();
});

it('should show a pass', async () => {
Expand Down
16 changes: 14 additions & 2 deletions example/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import * as React from 'react';
import {
AppRegistry,
Linking,
Platform,
SafeAreaView,
ScrollView,
StyleSheet,
Expand Down Expand Up @@ -127,18 +128,29 @@ class ExampleApp extends React.Component<{}, State> {

componentDidMount() {
Linking.getInitialURL().then(this._handleOpenURLString);
Linking.addEventListener('url', this._handleOpenURL);
if (Platform.OS === 'macos') {
Linking.addEventListener('url', this._handleOpenURLMacOS);
} else {
Linking.addEventListener('url', this._handleOpenURL);
}
}

componentWillUnmount() {
Linking.removeEventListener('url', this._handleOpenURL);
if (Platform.OS === 'macos') {
Linking.removeEventListener('url', this._handleOpenURLMacOS);
} else {
Linking.removeEventListener('url', this._handleOpenURL);
}
}

// Receives commands from the test runner when it opens the app with a given URL
// We use this to decide which test case to show
_handleOpenURL = ({url}: {url: string}) => {
this._handleOpenURLString(url);
};
_handleOpenURLMacOS = (url: any) => {
this._handleOpenURLString(url);
};
_handleOpenURLString = (url: string | null) => {
if (!url) {
return;
Expand Down
16 changes: 16 additions & 0 deletions example/macos/NetInfoExample-macOS/AppDelegate.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

#import <Cocoa/Cocoa.h>

@class RCTBridge;

@interface AppDelegate : NSObject <NSApplicationDelegate>

@property (nonatomic, readonly) RCTBridge *bridge;

@end
43 changes: 43 additions & 0 deletions example/macos/NetInfoExample-macOS/AppDelegate.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

#import "AppDelegate.h"

#import <React/RCTUIKit.h>
#import <React/RCTBridge.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTLinkingManager.h>

@interface AppDelegate () <RCTBridgeDelegate>

@end

@implementation AppDelegate

- (void)awakeFromNib {
[super awakeFromNib];

_bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:nil];
}

- (void)applicationWillFinishLaunching:(NSNotification *)__unused aNotification
{
// initialize the url event listeners for Linking module
// this example registers the netinfoexample scheme in Info.plist
[[NSAppleEventManager sharedAppleEventManager] setEventHandler:[RCTLinkingManager class]
andSelector:@selector(getUrlEventHandler:withReplyEvent:)
forEventClass:kInternetEventClass
andEventID:kAEGetURL];
}

#pragma mark - RCTBridgeDelegate Methods

- (NSURL *)sourceURLForBridge:(__unused RCTBridge *)bridge {
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"example/index" fallbackResource:@"main"]; // .jsbundle;
}

@end
50 changes: 50 additions & 0 deletions example/macos/NetInfoExample-macOS/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>com.reactnativecommunity.netinfo.example</string>
<key>CFBundleURLSchemes</key>
<array>
<string>netinfoexample</string>
</array>
</dict>
</array>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2020 Facebook. All rights reserved.</string>
<key>NSMainStoryboardFile</key>
<string>Main</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
</plist>
Loading

0 comments on commit b0ad866

Please sign in to comment.