Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

checkInternetConnection only works once #115

Closed
reilem opened this issue Jul 24, 2018 · 9 comments
Closed

checkInternetConnection only works once #115

reilem opened this issue Jul 24, 2018 · 9 comments
Assignees

Comments

@reilem
Copy link

reilem commented Jul 24, 2018

This is an issue I'm having (at least on iOS). The method checkInternetConnection() works perfectly fine the first time around and returns correct results. However when I call it a second time it seems to hang at this bit:

console.log("TEST 1")
return connectionChecked.then((isConnected: boolean) => {
    console.log("TEST 2")
    if (isConnected) {
      return checkInternetAccess(timeout, url);
    }
    return Promise.resolve(false);
  });

The second time around "TEST 1" is printed but "TEST 2" is not. I'm thinking that maybe the listeners are not being cleared properly which is causing the promise to not be resolved the second time around. Consequently checkInternetAccess() is never entered the second time around either and so the whole thing just hangs whenever I try to await checkInternetConnection().

I'll probably try implementing this one myself as its quite tricky to get working. I'll report back if I find a working solution.

@bgerhards
Copy link

@reilem did you find a solution? I am finding when I go offline, my queue fills up (adding retry: true to the meta). Once I am online again, the first item executes successfully but the rest remains in the queue. Future items stack in the queue as well. The only way to 'drain' the queue is to restart the app.

@reilem
Copy link
Author

reilem commented Aug 2, 2018

I ended up writing my own internet connection check by just sending a HEAD to our backend.

export async function hasAPIConnection() {
    const timeout = 2500
    try {
        return await new Promise((resolve, reject) => {
            setTimeout(() => {reject()}, timeout)
            fetch(API_ENDPOINT, {method: Method.HEAD})
                .then((response) => {resolve(response.ok)})
                .catch(() => {reject()})
        })
    } catch (e) {
        return false
    }
}

You could then use the true/false result to set the connection.

@maxammann
Copy link

Experiencing the same problem. Maybe the platform specific check is not working:

connectionChecked = new Promise((resolve: Function) => {

@IssueHuntBot
Copy link

@BoostIO funded this issue with $10. Visit this issue on Issuehunt

@fabiancook
Copy link

Looking into the native code for iOS, I don't see anything that suggests that connectionChange will be invoked each time a handler is attached, so it looks like we need to fire both the event & fetch for iOS, and just the fetch for android, so whatever gets there first wins really.

Reference here https://github.com/facebook/react-native/blob/master/React/Modules/RCTEventEmitter.m

RCTEventEmitter is what RCTNetInfo extends, see on line 82 it starts observing once the listener count is 1, and stops when it is 0, so for the first time around it will trigger, the next time it won't as now we would be at 2 listeners, or maybe one if we trigger it a while after.

Something close to this should do the trick...

export default function checkInternetConnection(
  timeout: number = 3000,
  url: string = 'http://www.google.com/',
): Promise<boolean> {
  let connectionChecked: Promise<boolean> = NetInfo.isConnected.fetch();
  if (Platform.OS === 'ios') {
    const fetchChecked = connectionChecked;
    connectionChecked = new Promise((resolve: Function, reject: Function) => {
      const handleFirstConnectivityChangeIOS = (isConnected: boolean) => {
        NetInfo.isConnected.removeEventListener(
          'connectionChange',
          handleFirstConnectivityChangeIOS,
        );
        resolve(isConnected);
      };
      NetInfo.isConnected.addEventListener(
        'connectionChange',
        handleFirstConnectivityChangeIOS,
      );
      // Wire up our fetch, if it resolves, just use that
      fetchChecked
        .then(resolve)
        .catch(reject)
        .then(() => {
          NetInfo.isConnected.removeEventListener(
            'connectionChange',
            handleFirstConnectivityChangeIOS,
          );
        })
    });
  }

  return connectionChecked.then((isConnected: boolean) => {
    if (isConnected) {
      return checkInternetAccess(timeout, url);
    }
    return Promise.resolve(false);
  });
}

@IssueHuntBot
Copy link

@issuehuntfest has funded $90.00 to this issue. See it on IssueHunt

fabiancook added a commit to fabiancook/react-native-offline that referenced this issue Dec 3, 2018
fabiancook added a commit to fabiancook/react-native-offline that referenced this issue Dec 3, 2018
@IssueHuntBot
Copy link

@fabiancook has submitted a pull request. See it on IssueHunt

@IssueHuntBot
Copy link

@rgommezz has cancelled their pull request. See it on IssueHunt

@IssueHuntBot
Copy link

@rgommezz has submitted a pull request. See it on IssueHunt

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants