Git Product home page Git Product logo

react-native-wifi-reborn's Introduction

react-native-wifi-reborn

ISC license Current npm package version Maintenance Semantic Release Downloads Total downloads Follow @JuanSeBestia

This project is based on the no longer maintained https://github.com/robwalkerco/react-native-wifi.

Getting started

$ npm install react-native-wifi-reborn --save

iOS

You need use enable Access WIFI Information, with correct profile. Hotspot Configuration is required in order to connect to networks.

iOS 13

You need put "Privacy - Location When In Use Usage Description" or "Privacy - Location Always and When In Use Usage Description" in Settings -> info

Android

ACCESS_FINE_LOCATION permission

Since Android 6, you must request the ACCESS_FINE_LOCATION permission at runtime to use the device's Wi-Fi scanning and managing capabilities. In order to accomplish this, you can use the PermissionsAndroid API or React Native Permissions.

Example:

import { PermissionsAndroid } from 'react-native';

const granted = await PermissionsAndroid.request(
      PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
      {
        title: 'Location permission is required for WiFi connections',
        message:
          'This app needs location permission as this is required  ' +
          'to scan for wifi networks.',
        buttonNegative: 'DENY',
        buttonPositive: 'ALLOW',
      },
);
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
    // You can now use react-native-wifi-reborn
} else {
    // Permission denied
}

Autolinking (React Native 60+)

This library is correctly autolinked on React Native 60+ πŸŽ‰.

React Native Link (for React Native 0.59 and below)

$ react-native link react-native-wifi-reborn

Manual linking

iOS

  1. In XCode, in the project navigator, right click Libraries ➜ Add Files to [your project's name]
  2. Go to node_modules ➜ react-native-wifi-reborn and add RNWifi.xcodeproj
  3. In XCode, in the project navigator, select your project. Add libRNWifi.a to your project's Build Phases ➜ Link Binary With Libraries
  4. Run your project (Cmd+R)<

Android

  1. Open up android/app/src/main/java/[...]/MainActivity.java
  • Add import com.reactlibrary.rnwifi.RNWifiPackage; to the imports at the top of the file
  • Add new RNWifiPackage() to the list returned by the getPackages() method
  1. Append the following lines to android/settings.gradle:
    include ':react-native-wifi-reborn'
    project(':react-native-wifi-reborn').projectDir = new File(rootProject.projectDir, 	'../node_modules/react-native-wifi-reborn/android')
    
  2. Insert the following lines inside the dependencies block in android/app/build.gradle:
      implementation project(':react-native-wifi-reborn')
    

Prebuild Plugin

This package cannot be used in the "Expo Go" app because it requires custom native code.

After installing this npm package, add the config plugin to the plugins array of your app.json or app.config.js:

{
  "expo": {
    "plugins": ["react-native-wifi-reborn"]
  }
}

Next, rebuild your app as described in the "Adding custom native code" guide.

Props

The plugin provides props for extra customization. Every time you change the props or plugins, you'll need to rebuild (and prebuild) the native app. If no extra properties are added, defaults will be used.

  • fineLocationPermission (false | undefined): When false, the android.permission.ACCESS_FINE_LOCATION will not be added to the AndroidManifest.xml.

Example

{
  "plugins": [
    [
      "react-native-wifi-reborn",
      {
        "fineLocationPermission": false
      }
    ]
  ]
}

Usage

import WifiManager from "react-native-wifi-reborn";

WifiManager.connectToProtectedWifiSSID(ssid, password, isWep).then(
  () => {
    console.log("Connected successfully!");
  },
  () => {
    console.log("Connection failed!");
  }
);

WifiManager.getCurrentWifiSSID().then(
  ssid => {
    console.log("Your current connected wifi SSID is " + ssid);
  },
  () => {
    console.log("Cannot get current SSID!");
  }
);

Methods

The api documentation is in progress.

Android & iOS

The following methods work on both Android and iOS

### NEW VERSION WITH OPTIONAL PARAMETERS ###

connectToProtectedWifiSSID({
      ssid: string;
      password: string | null;
      isWEP?: boolean;
      isHidden?: boolean;
      timeout?: number
  ;}): Promise

connectToProtectedSSID(SSID: string, password: string, isWEP: boolean, isHidden: boolean): Promise

Returns a promise that resolves when connected or rejects with the error when it couldn't connect to the wifi network.

SSID

Type: string

The SSID of the wifi network to connect with.

password

Type: string

The password of the wifi network to connect with.

isWep

Type: boolean Used on iOS. If true, the network is WEP Wi-Fi; otherwise it is a WPA or WPA2 personal Wi-Fi network.

isHidden

Type: boolean Used on Android. If true, the network is a hidden Wi-Fi network.

timeout - ONLY NEW VERSION

TypeL number Used on Android to set a timeout in seconds. Default 15 seconds.

Errors:

  • iOS:
    • unavailableForOSVersion: Starting from iOS 11, NEHotspotConfigurationError is available.
    • invalid: If an unknown error is occurred.
    • invalidSSID: If the SSID is invalid.
    • invalidSSIDPrefix: If the SSID prefix is invalid.
    • invalidPassphrase: If the passphrase is invalid.
    • userDenied: If the user canceled the request to join the asked network.
    • locationPermissionDenied: Starting from iOS 13, location permission is denied.
    • locationPermissionRestricted: Starting from iOS 13, location permission is restricted.
    • couldNotDetectSSID: If the SSID couldn't be detected.
  • Android:
    • locationPermissionMissing: Starting android 6, location permission needs to be granted for wifi scanning.
    • locationServicesOff: Starting Android 6, location services needs to be on to scan for wifi networks.
    • couldNotEnableWifi: Starting Android 10, apps are no longer allowed to enable wifi. User has to manually do this.
    • couldNotScan: Starting Android 9, it's only allowed to scan 4 times per 2 minuts in a foreground app.
    • didNotFindNetwork: If the wifi network is not in range, the security type is unknown and WifiUtils doesn't support connecting to the network.
    • authenticationErrorOccurred: Authentication error occurred while trying to connect. The password could be incorrect or the user could have a saved network configuration with a different password!
    • android10ImmediatelyDroppedConnection : Firmware bugs on OnePlus prevent it from connecting on some firmware versions. More info: ThanosFisherman/WifiUtils#63.
    • timeoutOccurred: Could not connect in the timeout window. - ONLY NEW VERSION
  • Both:
    • unableToConnect: When an unknown error occurred.

getCurrentWifiSSID(): Promise

Returns the SSID of the current WiFi network.

Errors:

  • couldNotDetectSSID: Not connected or connecting.

Only iOS

The following methods work only on iOS

connectToSSID(ssid: string): Promise

connectToSSIDPrefix(ssid: string): Promise

disconnectFromSSID(ssid: string): Promise

connectToProtectedSSIDOnce(SSID: string, password: string, isWEP: boolean, joinOnce: boolean): Promise

connectToProtectedSSIDPrefix(SSIDPrefix: string, password: string, isWep: boolean): Promise

Use this function when you want to match a known SSID prefix, but don’t have a full SSID. If the system finds multiple Wi-Fi networks whose SSID string matches the given prefix, it selects the network with the greatest signal strength.

SSIDPrefix

Type: string A prefix string to match the SSID of a Wi-Fi network.

password

Type: string The password of the wifi network to connect with.

isWep

Type: boolean Used on iOS. If YES, the network is WEP Wi-Fi; otherwise it is a WPA or WPA2 personal Wi-Fi network.

joinOnce

Type: boolean Used on iOS. Optional param. Defaults to false. When joinOnce is set to true, the hotspot remains configured and connected only as long as the app that configured it is running in the foreground. The hotspot is disconnected and its configuration is removed when any of the following events occurs:

  • The app stays in the background for more than 15 seconds.

  • The device sleeps.

  • The app crashes, quits, or is uninstalled.

  • The app connects the device to a different Wi-Fi network.

  • The user connects the device to a different Wi-Fi network.

Errors:

  • unavailableForOSVersion: Starting from iOS 11, NEHotspotConfigurationError is available.
  • invalid: If an unknown error is occurred.
  • invalidSSID: If the SSID is invalid.
  • invalidSSIDPrefix: If the SSID prefix is invalid.
  • invalidPassphrase: If the passphrase is invalid.
  • userDenied: If the user canceled the request to join the asked network.
  • locationPermissionDenied: Starting from iOS 13, location permission is denied.
  • locationPermissionRestricted: Starting from iOS 13, location permission is restricted.
  • couldNotDetectSSID: If the SSID couldn't be detected.
  • unableToConnect: When an unknown error occurred.

Only Android

The following methods work only on Android

loadWifiList(): Promise<Array<WifiEntry>>

Returns a list of nearby WiFI networks.

  • SSID: The network name.
  • BSSID: The WiFi BSSID.
  • capabilities: Describes the authentication, key management, and encryption schemes supported by the access point.
  • frequency: The primary 20 MHz frequency (in MHz) of the channel over which the client is communicating with the access point.
  • level: The detected signal level in dBm, also known as the RSSI.
  • timestamp: timestamp in microseconds (since boot) when this result was last seen.

Errors:

  • locationPermissionMissing: Starting android 6, location permission needs to be granted for wifi
  • locationServicesOff: Starting Android 6, location services needs to be on to scan for wifi networks.
  • exception: Any other caught exception.

reScanAndLoadWifiList(): Promise<Array<WifiEntry>>

Similar to loadWifiList but it forcefully starts a new WiFi scan and only passes the results when the scan is done.

isEnabled(): Promise<boolean>

Method to check if WiFi is enabled.

const enabled = await WifiManager.isEnabled();
this.setState({wifiIsEnabled: enabled});

setEnabled(enabled: boolean)

Method to set the WiFi on or off on the user's device.

WifiManager.setEnabled(true); //set WiFi ON
WifiManager.setEnabled(false); //set WiFi OFF

connectionStatus(): Promise<boolean>

Returns if the device is currently connected to a WiFi network.

disconnect()

Disconnect currently connected WiFi network.

getBSSID(): Promise<string>

Returns the BSSID (basic service set identifier) of the currently connected WiFi network.

getCurrentSignalStrength(): Promise<number>

Returns the RSSI (received signal strength indicator) of the currently connected WiFi network.

getFrequency(): Promise<number>

Returns the frequency of the currently connected WiFi network.

getIP(): Promise<number>

Returns the IP of the currently connected WiFi network.

isRemoveWifiNetwork(ssid: String): Promise<boolean>

This method will remove the wifi network configuration. If you are connected to that network, it will disconnect.

Errors:

  • locationPermissionMissing: Starting android 6, location permission needs to be granted for wifi

forceWifiUsage(useWifi: boolean): Promise<void>

Deprecated; see forceWifiUsageWithOptions.

forceWifiUsageWithOptions(useWifi: boolean, options<Record<string, unknown>): Promise<void>

Use this to execute api calls to a wifi network that does not have internet access. Useful for commissioning IoT devices. This will route all app network requests to the network (instead of the mobile connection). It is important to disable it again after using as even when the app disconnects from the wifi network it will keep on routing everything to wifi.

options

  • noInternet: Boolean: Indicate the wifi network does not have internet connectivity.

Conventions

react-native-wifi-reborn's People

Contributors

alexma01 avatar arosca avatar bitcrumb avatar brookflok avatar ca057 avatar davideviolante avatar dependabot[bot] avatar eliaslecomte avatar elliottkember avatar ethanswe avatar gabrielrra avatar gitisaac avatar itisnathaniel avatar jcarrag avatar johnwilliamforcier-spiria avatar juansebestia avatar kristfal avatar marcotoniut avatar matthewcarlreetz avatar mikeislearning avatar mvanroon avatar pczek avatar petterive avatar rapsssito avatar robrechtme avatar robwalkerco avatar scarlac avatar semantic-release-bot avatar vanenshi avatar zpengyu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

react-native-wifi-reborn's Issues

connectToProtectedSSID not working on iOS

getCurrentWifiSSID is working fine, but I am trying to connect to another SSID and it doesn't work.

It was working fine with react-native-wifi library.

Is there is something special I need to add to my configurations?

It's been a while I haven't touch to that.

thanks

connection error

import WifiManager from "react-native-wifi-reborn";
    WifiManager.connectToProtectedSSID(wifiNameText, wifiPasswordText, false)
            .then(() => {
                alert('success')
                console.log('Connected successfully!')
            }, () => {
                alert('failure')
                console.log('Connection failed!')
            })

Expectation

It should connect to wifi when i enter correct ssid, password

Reality

When i enter correct ssid and wrong password it says ''Connected successfully!'' and in wifi list it shows the ssid that i were trying to connect with

OS: Android

Now i rebuild the application , and i try to connect it says failure all the time even if i enter correct credentials

android:allowBackup is forced to true - security impact

Hi

I try to install https://github.com/JuanSeBestia/react-native-wifi-reborn library

$ npm install react-native-wifi-reborn --save
$ npx react-native run-android --verbose

After this command the build start and stop with this error message

error Failed to install the app. Make sure you have the Android development environment set up: https://facebook.github.io/react-native/docs/getting-started.html#android-development-environment.
Error: Command failed: ./gradlew app:installDebug -PreactNativeDevServerPort=8081
/home/mycoco/web/DevMob/myapp/mydev/mobile/android/app/src/debug/AndroidManifest.xml:12:7-34 Error:
	Attribute application@allowBackup value=(false) from AndroidManifest.xml:12:7-34
	is also present at [com.thanosfisherman.wifiutils:wifiutils:1.5.1] AndroidManifest.xml:18:9-35 value=(true).
	Suggestion: add 'tools:replace="android:allowBackup"' to <application> element at AndroidManifest.xml:7:5-117 to override.

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:processDebugManifest'.
> Manifest merger failed : Attribute application@allowBackup value=(false) from AndroidManifest.xml:12:7-34
  	is also present at [com.thanosfisherman.wifiutils:wifiutils:1.5.1] AndroidManifest.xml:18:9-35 value=(true).
  	Suggestion: add 'tools:replace="android:allowBackup"' to <application> element at AndroidManifest.xml:7:5-117 to override.

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 10s

Thank you for help me

getCurrentWifiSSID() not detected

I'm using WifiManager.getCurrentWifiSSID();
but it creates error. Running on iOS 13.4 device. Any idea maybe?

Error: Cannot detect SSID
    at Object.fn [as getCurrentWifiSSID] (NativeModules.js:99)
    at getCurrentWifi$ (index.js:11)
    at tryCatch (runtime.js:45)
    at Generator.invoke [as _invoke] (runtime.js:274)
    at Generator.prototype.<computed> [as next] (runtime.js:97)
    at tryCatch (runtime.js:45)
    at invoke (runtime.js:135)
    at runtime.js:170
    at tryCallTwo (core.js:45)
    at doResolve (core.js:200)

package.json

"react": "16.9.0",
"react-native": "0.61.5",
"react-native-wifi-reborn": "^3.1.1"

Info.plist

<key>NSLocationWhenInUseUsageDescription</key>
<string></string>

isRemoveWifiNetwork does not work

I'm trying to forget about a network, I pass to the ISRemoveWifiNetwork its SSID, and the callback returns me true, but the network is not forgotten. Has anyone ever experienced this?

I am granting WRITE_SETTINGS permission

Should connectToProtectedSSIDPrefix work in the iPhone Simulator?

I've been trying to get connectToProtectedSSIDPrefix to work.
The JS error states
Error while configuring WiFi
Whereas the XCode console states
NEHotspotConfigurationHelper failed to communicate to helper server.

The answer in the apple dev forums says I need to have certain entitlements enabled.
https://forums.developer.apple.com/thread/127834

I double-checked and surely have all the mentioned entitlements enabled. Even enabled the NetworkExtension entitlement (https://developer.apple.com/documentation/networkextension).
Which was also talked about in this issue => #32

Nevertheless, it does not work in the simulator and shows the same error. On the phone, however, it works, even without the NetworkExtension entitlements and only the ones mentioned in the apple dev forum.

So my assumption is that at least connectToProtectedSSIDPrefix is not usable in the simulator? Quite a pain if so, as it's also unpleasant to work with the phone especially if it's connecting to another wifi without the metro bundler running πŸ™ƒ

Lint Error in Android from using wifi.getConfiguredNetworks

Running an android build after installing this module causes the build to fail because of this linter error:

* What went wrong:
Execution failed for task ':react-native-wifi-reborn:lint'.
> Lint found errors in the project; aborting build.
  
  Fix the issues identified by lint, or add the following to your build script to proceed with errors:
  ...
  android {
      lintOptions {
          abortOnError false
      }
  }
  ...
  
  Errors found:
  
  /Users/cashc/repos/my-project/node_modules/react-native-wifi-reborn/android/src/main/java/com/reactlibrary/rnwifi/RNWifiModule.java:283: Error: Missing permissions required by WifiManager.getConfiguredNetworks: android.permission.ACCESS_FINE_LOCATION [MissingPermission]
          final List<WifiConfiguration> mWifiConfigList = wifi.getConfiguredNetworks();

I believe the fix is to ask for permission to use location services before calling the getConfiguredNetworks function, as outlined in this SO answer https://stackoverflow.com/a/33731050. I'm happy to take a stab at implementing this if the maintainer of this repo is open to a PR from an android novice like me (:

My temporary workaround: I'm not using the isRemoveWifiNetwork function in my project so I've forked this repo and commented out the body to the function so it's not calling getConfiguredNetworks and it works fine.

loadWifiList - How to know error location or permission or not network

Hi

Well done for this new version , but i have a big problem

Use case : Connect to wifi
To do this I would like know the list of available access point wifi and connect to one of them.
So I using loadWifiList() function.

Or If I forgot to active wifi and location i have any error message.
Could you put this error in loadWifiList like connectToProtectedSSID()

  • location permission missing: The location permission (ACCESS_FINE_LOCATION) is not granted (android 6+).
  • location off: The location service needs to be turned on (android 6+).
  • failed: Could not connect to the network. Could be due to multiple reasons; not in rang or wrong password.

Thanks

"connectToProtectedSSIDPrefix" isnt available

The documented function connectToProtectedSSIDPrefix() is not implemented in Android.

WifiManager.connectToProtectedSSIDPrefix("test", null, false).then(
      () => {
        console.log("Connected successfully!");
      },
      () => {
        console.log("Connection failed!");
      }
    )

This function is also not included in react-native-wifi-reborn/android/src/main/java/com/reactlibrary/rnwifi/RNWifiModule.java

connectToProtectedSSID does not behave as expected on Android

package.json dependency versions:

"react": "16.8.6",
"react-native": "0.60.3",
"react-native-wifi-reborn": "^3.1.2"

Tested on Xiaomi A2 Lite running Android Q:

When running connectToProtectedSSID() on Android, my app seems to be connecting to the network, the Android notification pane status for Wifi changes to "Connected via using app-name-here", but it does not seem to have internet connectivity.

If I "forget" the network and connect to it from within the OS, my internet connectivity works as expected.

TypeError: null is not an object (evaluating '_reactNativeWifiReborn.default.getBSSID')

Hi, whenever i try a function from this lib it gets me this error:
TypeError: null is not an object (evaluating '_reactNativeWifiReborn.default.getBSSID')

I ve read #52 but couldnt relate at all. Im using android and didnt use expo. Here is my package.json:

{
"name": "hihts",
"version": "0.0.1",
"private": true,
"scripts": {
"android": "react-native run-android",
"ios": "react-native run-ios",
"start": "start cmd.exe /c react-native start && cd src && cd server && start cmd.exe /c node cassandraServer.js && node mysqlServer.js",
"test": "jest",
"lint": "eslint ."
},
"dependencies": {
"@react-native-community/async-storage": "^1.7.1",
"@react-native-community/picker": "^1.1.2",
"@rodrigogs/mysql-events": "^0.6.0",
"@xmpp/client": "^0.9.2",
"@xmpp/time": "^0.11.0",
"assert": "^2.0.0",
"axios": "^0.19.0",
"bcryptjs": "^2.4.3",
"body-parser": "^1.19.0",
"cassandra-driver": "^4.5.1",
"child_process": "^1.0.2",
"connect-timeout": "^1.9.0",
"crypto": "^1.0.1",
"dns": "^0.2.2",
"eslint-config-rallycoding": "^3.2.0",
"express": "^4.17.1",
"firebase": "^7.2.2",
"gyp": "^0.5.0",
"https": "^1.0.0",
"https-browserify": "0.0.1",
"kerberos": "^1.1.3",
"lodash": "^4.17.15",
"moment": "^2.24.0",
"moment-timezone": "^0.5.28",
"mysql": "^2.17.1",
"native-base": "^2.13.8",
"navigationbar-react-native": "0.0.5",
"net": "^1.0.2",
"nodemon": "^2.0.2",
"prop-types": "^15.7.2",
"react": "16.9.0",
"react-native": "0.61.2",
"react-native-autogrow-input": "^0.2.1",
"react-native-dimension": "^1.0.6",
"react-native-elements": "^1.2.7",
"react-native-htmlview": "^0.15.0",
"react-native-keyboard-spacer": "^0.4.1",
"react-native-level-fs": "^2.0.0",
"react-native-loading-spinner-overlay": "^1.0.1",
"react-native-popup-dialog": "^0.18.3",
"react-native-randombytes": "^2.0.0",
"react-native-render-html": "^4.1.2",
"react-native-router-flux": "^3.45.0",
"react-native-simple-radio-button": "^2.7.4",
"react-native-smart-picker": "^1.0.5",
"react-native-svg": "^9.13.6",
"react-native-vector-icons": "^6.6.0",
"react-native-wifi-reborn": "^3.1.1",
"react-redux": "^7.1.1",
"redux": "^4.0.4",
"redux-thunk": "^2.3.0",
"socket.io": "^2.3.0",
"socket.io-client": "^2.3.0",
"stream": "0.0.2",
"url": "^0.11.0"
},
"devDependencies": {
"@babel/core": "7.6.4",
"@babel/plugin-transform-runtime": "^7.7.4",
"@babel/preset-env": "^7.7.4",
"@babel/runtime": "^7.6.3",
"@react-native-community/eslint-config": "0.0.3",
"babel-jest": "24.9.0",
"eslint": "6.6.0",
"jest": "24.9.0",
"metro-react-native-babel-preset": "0.51.1",
"path": "^0.12.7",
"react-test-renderer": "16.9.0",
"rn-nodeify": "^6.0.1"
},
"jest": {
"preset": "react-native"
},
"react-native": {
"crypto": "react-native-crypto",
"https": "https-browserify",
"fs": "react-native-level-fs"
},
"browser": {
"crypto": "react-native-crypto",
"https": "https-browserify",
"fs": "react-native-level-fs"
}
}

How to install on Android RN 6.0+

Hi could I get better clearity on how to install on versions on RN 6.0 and above. Im new to rn.

  1. I understand the library supports autolinking, I did a normal install via yarn add, however functions still fail at runtime, as they are undefined.

  2. Do we still need to use "import com.reactlibrary.RNWifiPackage;" in RN 6.0. also is if so it in MainActivity.java or MainApplication.java. documentation says MainActivity.java not sure if there's a typo or intentional.

  3. adding "import com.reactlibrary.RNWifiPackage;" MainApplication causes a compilation error, with a complaint that the package doesn't not exist.

Cannot detect SSID

In iOS 13 with "example/AwesomeProject" always get:

"Cannot get current SSID! Cannot detect SSID"

I granted location permissions.

  • iPhome model: iPhone 7
  • iOS Version: 13.1.3

Thanks you!

Can't disconnect from WiFi in IOS

I connected fine when using
const ssid = await WifiManager.getCurrentWifiSSID();
but, I can't disconnect it in IOS, when I try:

<TouchableOpacity onPress={async () => {
            try {
             const ssid = 'MyWifi'
              const disconnect = await WifiManager.disconnectFromSSID('MyWifi');
              console.log(disconnect);
            } catch (error) {
              console.log(error);
            }
}}>
          <Text>disconnect</Text>
 </TouchableOpacity>

It just, nothing happen.

I try to find in native code, then I got:

RCT_EXPORT_METHOD(disconnectFromSSID:(NSString*)ssid
                  resolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject) {
    
    if (@available(iOS 11.0, *)) {
        [[NEHotspotConfigurationManager sharedManager]  getConfiguredSSIDsWithCompletionHandler:^(NSArray<NSString *> *ssids) {
            if (ssids != nil && [ssids indexOfObject:ssid] != NSNotFound) {
                [[NEHotspotConfigurationManager sharedManager] removeConfigurationForSSID:ssid];
            }
            resolve(nil);
        }];
    } else {
        reject(@"ios_error", @"Not supported in iOS<11.0", nil);
    }
    
}

ssids always null each time a press button disconnect, otherwise when I try to hardcode:

RCT_EXPORT_METHOD(disconnectFromSSID:(NSString*)ssid
                  resolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject) {
    
    if (@available(iOS 11.0, *)) {
        [[NEHotspotConfigurationManager sharedManager]  getConfiguredSSIDsWithCompletionHandler:^(NSArray<NSString *> *ssids) {
         [[NEHotspotConfigurationManager sharedManager] removeConfigurationForSSID:@"MySSID"];
            resolve(nil);
        }];
    } else {
        reject(@"ios_error", @"Not supported in iOS<11.0", nil);
    }
    
}

still can't disconnect, please help

Version:
"react-native": "0.61.4",
Xcode Version 11.2.1
IOS: 11.2.6 and 12.4.1

[iOS] connectToProtectedSSID NEHotspotConfigurationManager completionHandler always returns nil

There appears to be an iOS bug where NEHotspotConfigurationManager errors are only shown to the user and are not sent to the completion handler. This results in the user being shown an "Unable to connect to" error message but the connectToProtectedSSID Promise is always resolved and never rejected. Here is a StackOverflow reference to this issue:

https://stackoverflow.com/questions/57393333/nehotspotconfigurationmanager-unable-to-join

A workaround could be to implement a delay of a few seconds allowing your WiFi network to switch and use getCurrentWifiSSID to confirm the correct WiFi network is connected before proceeding.

connectToProtectedSSID should update network configuration if password changed

When there is a configured wrong Wifi hotspot in the Android wifi setting, the connectToProtectedSSID failure.
Reproduce steps:

  1. on the Android WiFi setting page, join a WiFi, such as 'WiFi 1', with a wrong password. No doubt, it will fail.
  2. then call connectToProtectedSSID with the correct password

Expected:
connectToProtectedSSID return sucess

Actually:
connectToProtectedSSID timeout

By looking at the code, found the code does not check if the existed network configuration is the same as passed in network SSID and password. here should have some code to update the network if the password has changed.

Android functions providing empty responses

I have successfully implemented react-native-wifi-reborn into my app, but none of the functions are responding properly on Android.

For example getCurrentWifiSSID is giving the following logged response "Your current connected wifi SSID is "

connectToProtectedSSID is catching a failure, and loadWifiList is succeeding but returning an empty array.

I am using React Native 0.61.2, and did not link. Do I need to manually request WiFi permissions from the user?

Thank you!

IoT Device Disconnects After a Few Seconds in iOS 13

In iOS 13, there is a known issue that causes hotspot devices to connect and then disconnect after a few seconds.

Apparently this can be fixed by setting configuration.joinOnce = false; on lines 61 and 84 in RNWifi.m.

I'm going to do some independent testing as well, but wanted to create an issue for reference.

forceWifiUsage false and true

Hi all, I have an issue that I cannot solve, not sure what's going on

I have a raspberry pi with a hotspot, in my RN app I want to hit an endpoint to get a command to then send it to my hotspot.

The thing is that if I use it like this

    // Not needed since is by default
    // WifiManager.forceWifiUsage(false);

    fetch('api_call')
        .then((response) => response.json())
        .then((responseJson) => {
            console.log(responseJson);
        })
        .catch((error) => {
          console.error(error);
        });

I get the right data, then if I do

      WifiManager.forceWifiUsage(true);
      let config = {user: 'user', host: 'xx.x.x.x.x', password: 'pass'};

      SSH.execute(config, 'ls').then(
          result => console.log(result),
          error =>  console.log('Error:', error)
      );

it works too, BUT if I use them both together the SSH command does not work

    fetch('api_call')
        .then((response) => response.json())
        .then((responseJson) => {
           WifiManager.forceWifiUsage(true);
           let config = {user: 'user', host: 'xx.x.x.x.x', password: 'pass'};

            SSH.execute(config,responseJson).then(
                result => console.log(result),
                error =>  console.log('Error:', error)
            );
            console.log(responseJson);
        })
        .catch((error) => {
          console.error(error);
        });

This is my AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="com.appname">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_SETTINGS" />

    <application
      android:name=".MainApplication"
      android:label="@string/app_name"
      android:icon="@mipmap/ic_launcher"
      android:roundIcon="@mipmap/ic_launcher_round"
      android:allowBackup="false"
      android:theme="@style/AppTheme">
      <activity
        android:name=".MainActivity"
        android:label="@string/app_name"
        android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
        android:windowSoftInputMode="adjustResize">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
      </activity>
      <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
    </application>

</manifest>

I don't really get what's the problem.

Thanks,
Fernando.

[iOS] getWifiSSID returns nil

In iOS, getWifiSSID (triggered within getCurrentWifiSSID after iOS version and location permissions check) is returning nil.

The breakdown appears to be at CNCopyCurrentNetworkInfo which returns a null dictionary despite having location permissions. CNCopySupportedInterfaces is returning (en0).

iOS: loadWifiList()

Will a loadWifiList() function to show available networks for iOS be created? And can one connect to one of the networks by selecting the network on the list on the app?

WifiManager is undefined while importing from react-native-wifi-reborn

Hi, I'm trying to detect the ssid of currently connected wifi with the function WifiManager.getCurrentWifiSSID() but it's not working giving me error like "Cannot read property getCurrentWifiSSID of undefined" I logged the WifiManager in console just before and it was undefined. I'm sharing the code below for each of the file that are in use. I auto linked the library using react-native link react-native-wifi-reborn

PS. I'm bit new to RN and i'm kind of pretty sure that I'm missing something stupid.

App.js

import { createAppContainer } from "react-navigation";
import { createStackNavigator } from "react-navigation-stack";
import Home from "./screens/Home";
import Connecting from "./screens/Connecting";
import Connection_Success from "./screens/Connection_Success";
import Connection_Failure from "./screens/Connection_Failure";
import AutoDetect from "./screens/AutoDetect";

const AppNavigator = createStackNavigator(
    {
        Home: { screen: Home },
        Connecting: { screen: Connecting },
        Connection_Success: { screen: Connection_Success },
        Connection_Failure: { screen: Connection_Failure },
        AutoDetect: { screen: AutoDetect }
    },
    { initialRouteName: "AutoDetect" }
);

export default createAppContainer(AppNavigator);

./screens/AutoDetect.js

import React, { useState, useEffect } from "react";
import Heading from "../components/Heading";
import { View, Text } from "../css/styled_css";
import { ActivityIndicator } from "react-native";
import WifiManager from "react-native-wifi-reborn";

export default function AutoDetect() {
    let [detecting, setDetecting] = useState(true);
    console.log(WifiManager); //-----> This is undefined
    WifiManager.getCurrentWifiSSID().then( //-------> Error occurs here. 
        ssid => {
            console.log(ssid);
        },
        () => {
            console.log("error");
        }
    );
    return (
        <View>
            <Heading />
            {detecting ? (
                <View>
                    <ActivityIndicator />
                    <Text>
                        Detecting the product. Make sure you are connected to
                        the wifi or bluetooth.
                    </Text>
                </View>
            ) : (
                <Text>Detecting the device</Text>
            )}
        </View>
    );
}
AutoDetect.navigationOptions = {
    title: "Home"
};

./android/src/main/java/com/app/MainApplication.java

package com.companionapp;

import android.app.Application;

import com.facebook.react.ReactApplication;
import com.reactlibrary.rnwifi.RNWifiPackage;
import com.peel.react.TcpSocketsModule;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;
import com.facebook.soloader.SoLoader;
import com.companionapp.generated.BasePackageList;
import com.swmansion.rnscreens.RNScreensPackage;
import com.swmansion.gesturehandler.react.RNGestureHandlerPackage;

import org.unimodules.adapters.react.ReactAdapterPackage;
import org.unimodules.adapters.react.ModuleRegistryAdapter;
import org.unimodules.adapters.react.ReactModuleRegistryProvider;
import org.unimodules.core.interfaces.Package;
import org.unimodules.core.interfaces.SingletonModule;
import expo.modules.constants.ConstantsPackage;
import expo.modules.permissions.PermissionsPackage;
import expo.modules.filesystem.FileSystemPackage;

import java.util.Arrays;
import java.util.List;

public class MainApplication extends Application implements ReactApplication {
  private final ReactModuleRegistryProvider mModuleRegistryProvider = new ReactModuleRegistryProvider(
      new BasePackageList().getPackageList(), Arrays.<SingletonModule>asList());

  private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
    @Override
    public boolean getUseDeveloperSupport() {
      return BuildConfig.DEBUG;
    }

    @Override
    protected List<ReactPackage> getPackages() {
      return Arrays.<ReactPackage>asList(new RNWifiPackage(), new MainReactPackage(), new TcpSocketsModule(),
          new RNGestureHandlerPackage(), new RNScreensPackage(), new ModuleRegistryAdapter(mModuleRegistryProvider));
    }

    @Override
    protected String getJSMainModuleName() {
      return "index";
    }
  };

  @Override
  public ReactNativeHost getReactNativeHost() {
    return mReactNativeHost;
  }

  @Override
  public void onCreate() {
    super.onCreate();
    SoLoader.init(this, /* native exopackage */ false);
  }
}

dependencies from build.gradle

dependencies {
    implementation project(':react-native-wifi-reborn')
    implementation project(':react-native-tcp')
    implementation project(':react-native-screens')
    implementation project(':react-native-gesture-handler')
    implementation fileTree(dir: "libs", include: ["*.jar"])
    implementation "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}"
    implementation "com.facebook.react:react-native:0.59.10"  // From node_modules
    addUnimodulesDependencies()
}

./android/settings.gradle

apply from: '../node_modules/react-native-unimodules/gradle.groovy'
include ':react-native-wifi-reborn'
project(':react-native-wifi-reborn').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-wifi-reborn/android')
include ':react-native-tcp'
project(':react-native-tcp').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-tcp/android')
include ':react-native-screens'
project(':react-native-screens').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-screens/android')
include ':react-native-reanimated'
project(':react-native-reanimated').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-reanimated/android')
include ':react-native-gesture-handler'
project(':react-native-gesture-handler').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-gesture-handler/android')
includeUnimodulesProjects()

rootProject.name = 'companionApp'

include ':app'

minSdkVersion cannot be smaller than version declared in library

FAILURE: Build failed with an exception.

What went wrong:

Execution failed for task ':app:processDebugManifest'.
Manifest merger failed : uses-sdk:minSdkVersion 16 cannot be smaller than version 21 declared in library
[:react-native-wifi-reborn] 
path\node_modules\react-native-wifi-reborn\android\build\intermediates\library_manifest\debug\AndroidManifest.xml 
as the library might be using APIs not available in 16        
Suggestion: use a compatible library with a minSdk of at most 16,
                or increase this project's minSdk version to at least 21,
                or use tools:overrideLibrary="com.reactlibrary.rnwifi" to force usage (may lead to runtime failures)

Expo: null is not an object (evaluating '_reactNativeWifiReborn.default.getCurrentWifiSSID')

Hi,
following instructions, I tried to test this lib in my expo project:

import WifiManager from "react-native-wifi-reborn";

...
WifiManager.getCurrentWifiSSID().then(
ssid => {
console.log("Your current connected wifi SSID is " + ssid);
},
() => {
console.log("Cannot get current SSID!");
}
);
...

but have the following error:

null is not an object (evaluating '_reactNativeWifiReborn.default.getCurrentWifiSSID')

What to do?

Regards

loadWifiList for iOS

The loadWifiList function is available on Android, Is there a way to implement it for iOS as well?

Unable to run the app after adding the package.

I'm using react native 0.61.5, for some reason i can't use react-native run-android after installing this package. here is the error reported

> Task :app:processSandboxDebugManifest FAILED

See http://g.co/androidstudio/manifest-merger for more information about the manifest merger.


Deprecated Gradle features were used in this build, making it incompatible with Gradle 6.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/5.5/userguide/command_line_interface.html#sec:command_line_warnings
213 actionable tasks: 2 executed, 211 up-to-date
D:\_crypto-defense-source-codes\Zynesis\nzia-wallet\android\app\src\debug\AndroidManifest.xml:13:7-34 Error:        
        Attribute application@allowBackup value=(false) from AndroidManifest.xml:13:7-34
        is also present at [com.thanosfisherman.wifiutils:wifiutils:1.5.0] AndroidManifest.xml:18:9-35 value=(true).
        Suggestion: add 'tools:replace="android:allowBackup"' to <application> element at AndroidManifest.xml:7:5-117 to override.

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:processSandboxDebugManifest'.
> Manifest merger failed : Attribute application@allowBackup value=(false) from AndroidManifest.xml:13:7-34
        is also present at [com.thanosfisherman.wifiutils:wifiutils:1.5.0] AndroidManifest.xml:18:9-35 value=(true).
        Suggestion: add 'tools:replace="android:allowBackup"' to <application> element at AndroidManifest.xml:7:5-117 to override.

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 16s

error Failed to install the app. Make sure you have the Android development environment set up: https://facebook.github.io/react-native/docs/getting-started.html#android-development-environment. Run CLI with --verbose flag for more details.
Error: Command failed: gradlew.bat app:installSandboxDebug -PreactNativeDevServerPort=8081
D:\_crypto-defense-source-codes\Zynesis\nzia-wallet\android\app\src\debug\AndroidManifest.xml:13:7-34 Error:
        Attribute application@allowBackup value=(false) from AndroidManifest.xml:13:7-34
        is also present at [com.thanosfisherman.wifiutils:wifiutils:1.5.0] AndroidManifest.xml:18:9-35 value=(true).
        Suggestion: add 'tools:replace="android:allowBackup"' to <application> element at AndroidManifest.xml:7:5-117 to override.

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:processSandboxDebugManifest'.
> Manifest merger failed : Attribute application@allowBackup value=(false) from AndroidManifest.xml:13:7-34
        is also present at [com.thanosfisherman.wifiutils:wifiutils:1.5.0] AndroidManifest.xml:18:9-35 value=(true).
        Suggestion: add 'tools:replace="android:allowBackup"' to <application> element at AndroidManifest.xml:7:5-117 to override.

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 16s

forceWifiUsage causes all network requests to fail

I'm trying to connect to an IoT-like device that has a hotspot but does not have internet. If I don't call forceWifiUsage(true), then I can get successful responses using fetch and RNFetchBlob. If I try to force wifi usage, however, all of my proceeding requests fail. When using fetch, I see TypeError: Network request failed and when using RNFetchBlob I'm seeing Error: socket failed: ENONET (Machine is not on the network).

I'm having a hell of a time trying to understand what's happening. Any help would be greatly appreciated.

Cannot get current SSID on iOS simulator

I followed the instructions for iOS and I can't make it work on the simulator.

First, I spent several hours on a 'real' project to no avail.
Now I was trying do it with the simplest react app that I just created to test this library but no luck.

Here is what I see on the console:
[Mon Apr 20 2020 11:51:22.160] LOG Running "wifi" with {"rootTag":1,"initialProps":{}}
[Mon Apr 20 2020 11:51:22.161] LOG Connection failed!
[Mon Apr 20 2020 11:51:22.161] LOG Cannot get current SSID!

Here is my json:

{ "name": "wifi", "version": "0.0.1", "private": true, "scripts": { "android": "react-native run-android", "ios": "react-native run-ios", "start": "react-native start", "test": "jest", "lint": "eslint ." }, "dependencies": { "react": "16.11.0", "react-native": "0.62.2", "react-native-wifi-reborn": "^3.1.2" }, "devDependencies": { "@babel/core": "^7.9.0", "@babel/runtime": "^7.9.2", "@react-native-community/eslint-config": "^1.1.0", "babel-jest": "^25.4.0", "eslint": "^6.8.0", "jest": "^25.4.0", "metro-react-native-babel-preset": "^0.59.0", "react-test-renderer": "16.11.0" }, "jest": { "preset": "react-native" } }

Here is my App.js

`import React from 'react';
import {
SafeAreaView,
StyleSheet,
ScrollView,
View,
Text,
StatusBar,
} from 'react-native';
import WifiManager from 'react-native-wifi-reborn';
import {
Header,
LearnMoreLinks,
Colors,
DebugInstructions,
ReloadInstructions,
} from 'react-native/Libraries/NewAppScreen';

const App = () => {
WifiManager.connectToProtectedSSID('wifiName', 'dshfhjdsfga' , false).then(
() => {
console.log("Connected successfully!");
},
() => {
console.log("Connection failed!");
}
);
WifiManager.getCurrentWifiSSID().then(
ssid => {
console.log("Your current connected wifi SSID is " + ssid);
},
() => {
console.log("Cannot get current SSID!");
}
)
return (
<>




{global.HermesInternal == null ? null : (

Engine: Hermes

)}


Step One

Edit App.js to change this
screen and then come back to see your edits.



See Your Changes





Debug





Learn More

Read the docs to discover what to do next:






</>
);
};

const styles = StyleSheet.create({
scrollView: {
backgroundColor: Colors.lighter,
},
engine: {
position: 'absolute',
right: 0,
},
body: {
backgroundColor: Colors.white,
},
sectionContainer: {
marginTop: 32,
paddingHorizontal: 24,
},
sectionTitle: {
fontSize: 24,
fontWeight: '600',
color: Colors.black,
},
sectionDescription: {
marginTop: 8,
fontSize: 18,
fontWeight: '400',
color: Colors.dark,
},
highlight: {
fontWeight: '700',
},
footer: {
color: Colors.dark,
fontSize: 12,
fontWeight: '600',
padding: 4,
paddingRight: 12,
textAlign: 'right',
},
});

export default App;`

I appreciate any help!

Thanks

build for android issues

react-native version: 0.59.10

error: cannot find symbol public void onAvailable(@NonNull final Network network) {
^symbol: class NonNull
...

I have to add the following in node_modules/react-native-wifi-reborn/android/gradle.properties

android.useAndroidX=true
android.enableJetifier=true

uses-sdk:minSdkVersion 16 cannot be smaller than version 21 declared in ...
so this library can not support version below 21?

addOrUpdateFailed

Hi,

I'm getting the following error message :
Error: Could not add or update network configuration with SSID <SSID>
When trying to use connectToProtectedSSID on android with an IoT Amazon Button.

The capabilities of the network are [WPA2-PSK-CCMP+TKIP][WPA-PSK-TKIP+CCMP][ESS]

This is my code
await WifiManager.reScanAndLoadWifiList( wifiList => { let wifiArray = JSON.parse(wifiList); let ssids = wifiArray.map(value => value.SSID); let buttonWifi = ssids.find(value => value.startsWith('Button ConfigureMe'), ); console.warn('buttonWifi: ' + JSON.stringify(wifiArray)); WifiManager.connectToProtectedSSID( buttonWifi, '8367H28S', false, // isWep ).then( success => console.warn( 'Connected successfully! ' + JSON.stringify(success), ), error => console.warn('Connection failed! ' + error.toString()), ); }, error => console.warn( 'Error getting wi-fi list: ' + error.toString(), ), );

I've also tried connecting to other wi-fi networks with the same error.
I've made sure that PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION is GRANTED

Any tips on what could be going wrong ?

Functions aren't responding properly on Android

This is maybe a bad question :|

I have successfully implemented react-native-wifi-reborn into my app, but none of the functions are responding properly on Android.

For example getCurrentWifiSSID is giving the following logged response "Your current connected wifi SSID is "

connectToProtectedSSID is catching a failure, and loadWifiList is succeeding but returning an empty array.

I am using React Native 0.61.3, and did not link. Do I need to manually request WiFi permissions from the user?

Thank you!

How to enable Access WIFI Information, with correct profile from EXPO

Hi,

First of all, thanks for making this code available.

I'm running a react native app directly from expo(V0.61).
I'm not running any emulator, is it possible to add the profile as specified in the instructions directly in expo or in react native? Sorry I'm a bit confused there.

Thanks in advance!!!

FM

Add Types

I'm considering adding typing for TypeScript which is the one I use the most,

Remove allowBackup=true

Unable to build on Android due to an error caused by allowBackup set to false in my app but in the library it's set to true. The conflict means app devs have to override the setting for all tools which seems unnecessary.
The setting can be removed from the library.

Please see this dicussion on the topic which describes what I just said:
OfficeDev/msa-auth-for-android#21

error: package androidx.core.content does not exist

Task :react-native-wifi-reborn:compileDebugJavaWithJavac
C:\Project\node_modules\react-native-wifi-reborn\android\src\main\java\com\react
library\utils\PermissionUtils.java:10:
error: package androidx.core.content does not exist
import androidx.core.content.ContextCompat;

Any ideas for solving this?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.