React native Connection status on background / locked screen NetInfo - react-native

Description:
When the app is running in a background state or Locked, When the user unlock or foreground the app, useNetInfo(); hook return as isConnected as false. Even I tried to re-fetch the state still using NetInfo.fetch() return the same state.
It's happening in Android real device connected to Wifi
Package Name:
"#react-native-community/netinfo": "^7.1.2",
Code:
const netInfo = useNetInfo();
const [show, setShow] = useState(false);
useEffect(() => {
setShow(!(netInfo.isConnected && netInfo.isInternetReachable));
}, [netInfo]);
useEffect(() => {
fetchConnection();
}, []);
const fetchConnection = () => {
NetInfo.fetch().then((state: any) => {
setShow(!(state.isConnected && state.isInternetReachable));
});
};

I fixed this issue by reverting the package version into "#react-native-community/netinfo": "5.9.7",
Also, change the androidXCore version into 1.6.0. Now it's working as expected.
Reason:
Due to the hibernation features changes in androidXCore version 1.7.0. Netinfo does not return the state properly if the app is in a hibernation state. Please fix this issue in the upcoming release. Thanks.

add navigation focus event listener and check for network update whenever the screen is focused.

Please try this, it's from the package npm site
useEffect(() => {
const subAppState = AppState.addEventListener("change", async (nextAppState) => {
if (IS_IOS_DEVICE && nextAppState=='active') {
let newNetInfo = await NativeModules.RNCNetInfo.getCurrentState('wifi');
//your code here
}
});
const unsubNetState = NetInfo.addEventListener(state => {
//your code here
});
return () => {
if (subAppState) {
subAppState.remove();
}
unsubNetState();
};
},[]);

Related

What are the alternatives of NetInfo API in react native for checking network connectivity in mobile app?

I am looking for alternative APIs of NetInfo. I have been trying to use NetInfo API as well as react-native-offline (which uses NetInfo behind the scenes) to check constantly if the user is connected to the internet or not in the app and render network error screen based on that. We are using drawer stack for screens and our app is running on react-native "^0.64.1". But the NetInfo isn't working properly. When the app starts, it detects the internet connection correctly but then if we switch the connection type or disconnect fro app, the state is not updating. I am using useNetInfo() hook to access the states of internet. But the value is not refreshing. The code is attatched here.
import React from 'react';
import NoInternetScreen from './NoInternetScreen';
const ConnectionChecker = ({ children }: { children: any }) => {
const netInfo = useNetInfo();
console.log('NetInfo is: ', netInfo.isConnected);
console.log('NetInfo type: ', netInfo.type);
return netInfo.isConnected ? (
children
) : (
<>
<NoInternetScreen />
</>
);
};
export default ConnectionChecker;
I am wrapping the drawer stack with . Since NetInfo is not refreshing I am trying to find the alternatives of NetInfo. So are there any alternatives for NetInfo which can be used to check the network connection and which work for react-native 0.64.1 ?
You can try #react-native-community/netinfo.
import NetInfo from "#react-native-community/netinfo";
const [isConnected, setIsConnected] = useState(true);
NetInfo.fetch().then(state => {
if (state.isConnected && state.isInternetReachable) {
setIsConnected(true);
} else {
setIsConnected(false);
}
});
useEffect(() => {
const unsubscribe = NetInfo.addEventListener((state) => {
if (state.isConnected && state.isInternetReachable) {
setIsConnected(true);
} else {
setIsConnected(false);
}
});
if (isConnected) {
} else {
unsubscribe();
}
return () => {
unsubscribe();
};
}, []);

Detect coming back from app settings/background with React Native

My app asks permission to use location services.
If a user denies permission, they can click a button to go to the settings page and grant permissions.
On ios, they are given the option to return directly to the app. on Android, I think they can do something similar.
Is there a way to detect arriving back at the app so I can check their permissions again?
I've tried with React Navigation's useFocusEffect hook:
useFocusEffect(
React.useCallback(() => {
console.log("navigated")
return () => getPosition()
}, [])
)
But unfortunately, that only works when navigating between screens/routes in the app.
Is there a way to detect the app transitioning from background to foreground?
You can track app state with https://reactnative.dev/docs/appstate
in pseudo-code: if previously 'background' and now 'active' then run your effects
Ciao, when I want to manage permission, I use react-native-permissions. In this way you can manage all permissions directly in your app without exit from it.
Works well for iOs and Android. In your case, you could something like:
import {check, PERMISSIONS, RESULTS} from 'react-native-permissions';
check(<permission you need>)
.then((result) => {
switch (result) {
case RESULTS.UNAVAILABLE:
console.log(
'This feature is not available (on this device / in this context)',
);
break;
case RESULTS.DENIED:
console.log(
'The permission has not been requested / is denied but requestable',
);
break;
case RESULTS.GRANTED:
console.log('The permission is granted');
break;
case RESULTS.BLOCKED:
console.log('The permission is denied and not requestable anymore');
break;
}
})
.catch((error) => {
// …
});
Use this hook:
// hooks/useAppIsActive.ts
import { useCallback, useEffect, useRef } from "react";
import { AppState } from "react-native";
export default (callback: Function) => {
const appStateRef = useRef(AppState.currentState);
const handleAppStateChange = useCallback((nextAppState) => {
if (
appStateRef.current.match(/inactive|background/) &&
nextAppState === "active"
) {
callback();
}
appStateRef.current = nextAppState;
}, []);
useEffect(() => {
AppState.addEventListener("change", handleAppStateChange);
return () => {
AppState.removeEventListener("change", handleAppStateChange);
};
}, []);
};
And from the component you want to detect "the come back", pass by parameter the callback you want to run:
const MyView = () => {
const requestLocationAccess = useCallback(() => {
// request permissions...
}, [])
useAppIsActive(() => requestLocationAccess());
}

handling push notifications in android expo

I tried adding push notification with the expo, I am able to push notification from the server but even though the app is in foreground notification handler is not triggered,
I have replicated the documentation example from expo-notifications
export default function App(props) {
const [expoPushToken, setExpoPushToken] = useState('');
const [notification, setNotification] = useState(false);
const notificationListener = useRef();
const responseListener = useRef();
useEffect(() => {
registerForPushNotificationsAsync().then(token => setExpoPushToken(token));
notificationListener.current = Notifications.addNotificationReceivedListener(notification => {
setNotification(notification);
});
responseListener.current = Notifications.addNotificationResponseReceivedListener(response => {
console.log(respone)
});
}, []);
registerForPushNotificationsAsync() should be an async function that would be in your App Component here. In the example from expo it is added bellow the component as convention.
Further more the 'response' would only be logged after you press the push notification.
The other listener notificationListener is setting a state in your example here, so is not being logged maybe.
If you are using a bare workflow also add useNextNotificationsApi: true to app.json in your android object.

orientation change listener in expo react native not firing?

i want to detect the current orientation of device in expo react native, this is my code that doesn't work:
import {
Dimensions,
} from 'react-native';
import * as ScreenOrientation from 'expo-screen-orientation';**
const App = () => {
...
useEffect(() => {
const isPortrait = () => {
const dimension = Dimensions.get('screen');
return dimension.height >= dimension.width;
};
Dimensions.addEventListener('change', () => {
const orientation = isPortrait() ? 'portrait' : 'landscape';
console.log('Dimensions orientation', orientation);
});
ScreenOrientation.addOrientationChangeListener((e) => {
console.log('e ', e);
});
}, []);
how ever when i rotate the device there is no logs so it's not firing?
This works for me:
const [orientation, setOrientation] = useState(
ScreenOrientation.Orientation.PORTRAIT_UP
);
useEffect(() => {
// set initial orientation
ScreenOrientation.getOrientationAsync().then((info) => {
setOrientation(info.orientation);
});
// subscribe to future changes
const subscription = ScreenOrientation.addOrientationChangeListener((evt) => {
setOrientation(evt.orientationInfo.orientation);
});
// return a clean up function to unsubscribe from notifications
return () => {
ScreenOrientation.removeOrientationChangeListener(subscription);
};
}, []);
You should set your orientation field as default in your app.json / app.config.js. The app is locked to the specified orientation if this field is set to another value.
Related doc is here:
https://docs.expo.dev/versions/v46.0.0/config/app/#orientation
This is the line that doesn't do anything. Broken, bugged, POS? All of the above?
ScreenOrientation.addOrientationChangeListener((e) => {
console.log(e);
});
I had this same issue. The listener function was never firing.
Adding expo-sensors to my project seems to have fixed the callback for me. I think expo-screen-orientation might depend on expo-sensors
Steps for adding:
npx expo install expo-sensors
Rebuild your expo development client. (For me that command is eas build --profile simulator, but that will depend on your eas config)
After that, the listener callback function started firing.
Here's a code snippet of where I add the listener:
useEffect(() => {
ScreenOrientation.addOrientationChangeListener((e) => {
console.log(e)
})
}, [])
You're using the wrong package.
From the expo-screen-orientation docs:
Screen Orientation is defined as the orientation in which graphics are painted on the device. ... For physical device orientation, see the orientation section of Device Motion.

React Native, store information before app exits

Is this at all possible? I'm currently using react-native-track-player to stream audio files and I would love to be able to store the last position when my users exit the app and resume when they re-open (e.g. similar to how Spotify works)
Right now I'm tracking this info via a simple interval:
this.keepTime = setInterval(async () => {
const state = await TrackPlayer.getState()
if (state == TrackPlayer.STATE_PLAYING) {
const ID = await TrackPlayer.getCurrentTrack()
const position = await TrackPlayer.getPosition()
await AsyncStorage.setItem(ID, String(position))
}
}, 10000)
Problem is, I need to clear the interval when my app moves to the background or else it will crash. I would also much rather only need to call this code once as opposed to periodically if that is possible.
I know I could use headless JS on android but the app is cross platform, so my iOS user experience would be lesser.
Any suggestions?
I think you can use componentWillUnmount() function for this.
You could add a listener to get the App State and then log the position when it goes to background.
class App extends React.Component {
state = {
appState: AppState.currentState
}
componentDidMount() {
AppState.addEventListener('change', this.handleAppStateChange);
}
componentWillUnmount() {
AppState.removeEventListener('change', this.handleAppStateChange);
this.saveTrackPosition();
}
handleAppStateChange = (nextAppState) => {
if (nextAppState.match(/inactive|background/) && this.state.appState === 'active') {
this.saveTrackPosition();
}
this.setState({appState: nextAppState});
}
saveTrackPosition = () => {
if (state == TrackPlayer.STATE_PLAYING) {
const ID = await TrackPlayer.getCurrentTrack()
const position = await TrackPlayer.getPosition()
await AsyncStorage.setItem(ID, String(position))
}
}
}