I have an Android app that its built with React Native + Expo. My Expo is currently in version 39.0.0.
The user starts a location service by clicking in a button and when users changes position the app with its new position execute some rules based on location and show some notifications depending of user position.
Everything works great when the app is in foreground, in every tested devices. But, when the app goes to background it stops to work in some devices.
For example, in Xiaomi devices the app works great but in Samsung don't. =[
Can anyone help me?
Here`s part of my "app.json":
"android": {
"package": "br.i.dont.know.whats.going.on",
"versionCode": 86,
"permissions": [
"ACCESS_COARSE_LOCATION",
"ACCESS_FINE_LOCATION",
"ACCESS_BACKGROUND_LOCATION",
"CAMERA",
"READ_EXTERNAL_STORAGE",
"WRITE_EXTERNAL_STORAGE",
"NOTIFICATIONS",
"USER_FACING_NOTIFICATIONS",
"FOREGROUND_SERVICE"
],
This is the location task registered when app starts:
export async function registerFetchTask() {
TaskManager.defineTask(LOCATION_TASK, async ({ data: { locations }, error }) => {
if (error) {
console.error(error);
return;
}
const [location] = locations;
try {
if (location) {
AppState.currentState === "background" && updateChart(location);
}
} catch (err) {
console.error("Error while getting user location: ", err);
}
});
const status = await BackgroundFetch.getStatusAsync();
switch (status) {
case BackgroundFetch.Status.Restricted:
case BackgroundFetch.Status.Denied:
console.log("Background execution is disabled");
return;
default: {
console.debug("Background execution allowed");
let tasks = await TaskManager.getRegisteredTasksAsync();
if (tasks.find(f => f.taskName === LOCATION_TASK) == null) {
console.log("Registering task");
await BackgroundFetch.registerTaskAsync(LOCATION_TASK);
tasks = await TaskManager.getRegisteredTasksAsync();
console.debug("Registered tasks", tasks);
} else {
console.log(`Task ${LOCATION_TASK} already registered, skipping`);
}
console.log("Setting interval to", 5);
await BackgroundFetch.setMinimumIntervalAsync(5);
}
}
}
Task location started when user press the button
await Location.startLocationUpdatesAsync(LOCATION_TASK, {
accuracy: Location.Accuracy.Balanced,
timeInterval: 5000,
distanceInterval: 1, // minimum change (in meters) betweens updates
deferredUpdatesTimeout: 5000,
deferredUpdatesInterval: 5000, // minimum interval (in milliseconds) between updates
// foregroundService is how you get the task to be updated as often as would be if the app was open
foregroundService: {
notificationTitle: 'App is using your location',
notificationBody: 'To turn off, go back to the app.',
},
});
Related
I'm a beginner at React Native.
I am trying to access a native(built-in) camera app on Android device.
I used React-Native-Image-Picker to open the camera app but I would like to record a video somehow automatically(?) I mean not using my finger.
I need codes that make it to record and stop the video.
(I don't mean to give me a code rather, please advise if it is even possible?)
Any help would be very appreciated.
Thank you!
It is possible.
Package: https://github.com/mrousavy/react-native-vision-camera
Review the API and Guide section to see how to start and stop recording programmatically.
They also show an example app that demonstrates different types of capture including video recording, ref: https://github.com/mrousavy/react-native-vision-camera/blob/28fc6a68a5744efc85b532a338e2ab1bc8fa45fe/example/src/views/CaptureButton.tsx
...
const onStoppedRecording = useCallback(() => {
isRecording.current = false;
cancelAnimation(recordingProgress);
console.log('stopped recording video!');
}, [recordingProgress]);
const stopRecording = useCallback(async () => {
try {
if (camera.current == null) throw new Error('Camera ref is null!');
console.log('calling stopRecording()...');
await camera.current.stopRecording();
console.log('called stopRecording()!');
} catch (e) {
console.error('failed to stop recording!', e);
}
}, [camera]);
const startRecording = useCallback(() => {
try {
if (camera.current == null) throw new Error('Camera ref is null!');
console.log('calling startRecording()...');
camera.current.startRecording({
flash: flash,
onRecordingError: (error) => {
console.error('Recording failed!', error);
onStoppedRecording();
},
onRecordingFinished: (video) => {
console.log(`Recording successfully finished! ${video.path}`);
onMediaCaptured(video, 'video');
onStoppedRecording();
},
});
// TODO: wait until startRecording returns to actually find out if the recording has successfully started
console.log('called startRecording()!');
isRecording.current = true;
} catch (e) {
console.error('failed to start recording!', e, 'camera');
}
}, [camera, flash, onMediaCaptured, onStoppedRecording]);
//#endregion
...
I am developing an app that would send data to my server based on the user entering and exiting a region using Expo Location. Currently testing on an Android emulator.
However, the exit event is triggered for all regions upon the app startup. Is this the expected behavior or am I doing something wrong?
Geolocation:
useEffect(() => {
(async () => {
await Location.startGeofencingAsync(GEO_LOC, region)
})();
return async() =>{
await Location.stopGeofencingAsync(GEO_LOC)
}
}, []);
TaskManager :
TaskManager.defineTask(GEO_LOC, ({ data: { eventType, region }, error }) => {
if (error) {
// check `error.message` for more details.
return;
}
if (eventType === Location.GeofencingEventType.Enter) {
console.log("You've entered region:", region.identifier);
socket.emit('court:increment', region.identifier)
}
if (eventType === Location.GeofencingEventType.Exit) {
console.log("You've left region:", region.identifier);
socket.emit('court:decrement', region.identifier)
}
});
I am using plugin
https://github.com/seididieci/capacitor-backround-geolocation
to watch the user's location. then I am tracking that location with the help of a pusher. this background location works only for 5 minutes after that it just stops. I am using Capacitor's Background task. But that plugin also keeps data on phone after the user opens the app. the Background task sends data to the pusher.
Here is watch location function
getLocation: async function () {
BackgroundGeolocation.initialize({
notificationText: "Your app is running, tap to open.",
notificationTitle: "App Running",
updateInterval: 10000,
requestedAccuracy: BgGeolocationAccuracy.HIGH_ACCURACY,
// Small icon has to be in 'drawable' resources of your app
// if you does not provide one (or it is not found) a fallback icon will be used.
smallIcon: "ic_small_icon",
// Start getting location updates right away. You can set this to false or not set at all (se below).
startImmediately: true,
});
// const geolocation = new Geolocation.Geolocation();
BackgroundGeolocation.addListener("onLocation", (location) => {
// console.log("Got new location", location);
this.subscribe(location.longitude, location.latitude);
console.log(location)
});
BackgroundGeolocation.addListener("onPermissions", (location) => {
// console.log("BGLocation permissions:", location);
this.subscribe(location.longitude, location.latitude);
// Do something with data
});
BackgroundGeolocation.start();
},
Then calling function in mounted()
mounted(){
this.getLocation
App.addListener("appStateChange", (state) => {
setInterval(this.getLocation, 120000);
if (!state.isActive) {
BackgroundTask.beforeExit(async () => {
setInterval(this.getLocation, 120000);
console.og('Why')
});
}
if (state.isActive) {
setInterval(this.getLocation, 120000);
console.log('Active')
}
});
}
You need to use https://ionicframework.com/docs/native/foreground-service like this for running the background.
I am testing background location tasks in react native with Expo's taskmanager to test when I enter a geofence. I've got the basics working but I am now trying to access the values within a promise that is returned from one of the tasks so i can display if you've entered or exited the geofence. Can anyone help me figure out how to properly access the values I want?
Below is the task portion relevant to the geofence. I return the value region which comes as a promise. I haven't been able to figure out how to send directly from task manager yet:
// 3 Define geofencing task
TaskManager.defineTask(TASK_CHECK_GEOFENCE, ({ data: { eventType, region }, error }) => {
if (error) {
// check `error.message` for more details.
return;
}
if (eventType === Location.GeofencingEventType.Enter) {
console.log("You've entered region:", region);
//this.props.setEnterRegion({ inRegion: region })
const final = region
return final
} else if (eventType === Location.GeofencingEventType.Exit) {
console.log("You've left region:", region);
const final = region
return final
}
});
Then within App.js I call the app in componentDidMount:
componentDidMount() {
this.getLocationsPermissions();
this.startBackgroundUpdate();
this.startGeofence();
}
//define and start geofence
startGeofence = async () => {
console.log('starting geofencing test ...')
let x = Location.startGeofencingAsync('TASK_CHECK_GEOFENCE',
[
{
identifier: 'court',
latitude: this.state.myLocation.latitude,
longitude: this.state.myLocation.longitude,
radius: 20,
notifyOnEnter: true,
notifyOnExit: true,
}
]
)
this.sendTask(x)
};
When I try to access the value I can see the promise and I am unsure where I am going wrong. I would perfer to send to the store directly from taskmanager but I am having trouble with that:
//send to store from task
sendTask = (x) => {
console.log('entered region...', x)
this.props.setEnterRegion(x)
entered region... Promise {
"_40": 0,
"_55": null,
"_65": 0,
"_72": null,
}
I'm using React Native with Expo Location.startLocationUpdatesAsync. I have created three functions in the same file, the first two are in my export default App function, with TaskManager defined globally in the file.
async startBackgroundUpdate() {
await Location.startLocationUpdatesAsync(taskName, {
accuracy: Location.Accuracy.Highest,
timeInterval: 0,
distanceInterval: 0,
forgroundService: {
notificationTitle: "I'm a notification title",
notificationBody: "I'm a notification body",
notificationBody: "#abcdef"
}
});
}
async stopBackgroundUpdate() {
await Location.stopLocationUpdatesAsync(taskName)
}
TaskManager.defineTask(taskName, async ({ data, error }) => {
if (error) {
return console.log(error)
}
if (data) {
const { locations } = data;
locationGlobal = locations[0];
let date = new Date(locationGlobal.timestamp).toISOString().slice(-13, -5)
// App.setLocation(location)
console.log("Task has been running "+ count +" time(s). With data: "+data);
console.log(locationGlobal);
console.log(count++);
console.log(date)
}
});
I also have a global variable that holds the taskName
const taskName = 'geofencing'
The stop and start background location functions are hooked up to a button. I can start the background location fine, but when I try and stop it I get the error
Task 'geofencing' not found for app ID '#anonymous/track-it-fecc322d-0ade-4239-8bd1-fdcb47b0397e'.
- node_modules\react-native\Libraries\BatchedBridge\NativeModules.js:104:55 in <unknown>
- node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:414:4 in __invokeCallback
- ... 4 more stack frames from framework internals
I am new to this and I think I am missing a piece of the puzzle. I can see the taskName and create the task from inside my App function but at the same level I can't reference it to stop it, any ideas?