Tried react-native-background-fetch and react-native-background-job both libraries does not run the code when app is closed, followed the documentation clearly
react-native-background-fetch job runs when custom event created using
when app is in foreground
adb shell cmd jobscheduler run -f com.bg_fetch 999
, also periodic event is not triggered after 15 min(as given in config)
For react-native-background-job job does not run even in background
Tested on android-9
componentDidMount() {
// Configure it.
BackgroundFetch.configure({
minimumFetchInterval: 15, // <-- minutes (15 is minimum allowed)
// Android options
stopOnTerminate: false,
startOnBoot: true,
requiredNetworkType: BackgroundFetch.NETWORK_TYPE_ANY, // Default
requiresCharging: false, // Default
requiresDeviceIdle: false, // Default
requiresBatteryNotLow: false, // Default
requiresStorageNotLow: false, // Default
enableHeadless:true,
}, async() => {
console.log('[BackgroundFetch HeadlessTask] start');
let response = await fetch('http://431c21b5.ngrok.io/');
let responseJson = await response.json();
console.log('[BackgroundFetch HeadlessTask] response: ', responseJson);
BackgroundFetch.finish(BackgroundFetch.FETCH_RESULT_NEW_DATA);
}, (error) => {
console.log("[js] RNBackgroundFetch failed to start");
});
// Optional: Query the authorization status.
BackgroundFetch.status((status) => {
switch(status) {
case BackgroundFetch.STATUS_RESTRICTED:
console.log("BackgroundFetch restricted");
break;
case BackgroundFetch.STATUS_DENIED:
console.log("BackgroundFetch denied");
break;
case BackgroundFetch.STATUS_AVAILABLE:
console.log("BackgroundFetch is enabled");
break;
}
});
}
Job is supposed to run when app is in background or closed,
Headless job is getting killed after i close the app,
you need to put inside your index.js file your headlessTask
https://github.com/transistorsoft/react-native-background-fetch#config-boolean-enableheadless-false
Related
I've finished writing my first Cypress test. Everything is good except I'm struggling to post the result data to a website. Because I want to send the result data and also if any errors occurs the result screenshot to our coworker telegram group.
For the last two days I've tried everything and couldn't find any solution.
I've tried those in my test script (cypress/integration/test.js);
Cypress.on('test:after:run', (test, runnable) => {
console.log('test,runnable', test, runnable)
const details = {
projectKey: Cypress.env('zephyr-project-key'),
testName: test.invocationDetails.relativeFile,
status: test.status,
error: runnable.err.message,
retries: runnable.retries.length,
duration: test.wallClockDuration,
startTime: test.wallClockStartedAt
}
cy.request('POST', 'http://mywebsite.com/notify.php', { body: details })
fetch('http://mywebsite.com/notify.php')
})
Also this didn't work (cypress/plugins/index.js);
module.exports = (on, config) => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
on('after:run', (results) => {
if (results) {
// results will be undefined in interactive mode
console.log(results.totalPassed, 'out of', results.totalTests, 'passed')
fetch('http://mywebsite.com/notify.php');
}
})
}
Edit: This is day 3 and I still couldn't solve this. What I've seen from Cypress help page is that cy.task() calls do not fire in 'test:after:run' event block;
https://github.com/cypress-io/cypress/issues/4823
I've seen some telegram groups who can do what I'm trying to do. All I need is to be able to get the results and post it to my website.
The third parameter to cy.request() is body, you don't have to wrap it.
Cypress.on('test:after:run', (test, runnable) => {
const details = {
projectKey: Cypress.env('zephyr-project-key'),
testName: test.invocationDetails.relativeFile,
status: test.status,
error: runnable.err?.message, // need err?.message if there is no error
retries: runnable.retries.length,
duration: test.wallClockDuration,
startTime: test.wallClockStartedAt
}
cy.request('POST', 'http://mywebsite.com/notify.php', details) // don't wrap details
.then(res => expect(res.status).to.eq(201)) // confirm result
})
My app is requiring that google oauth (via federatedSignIn) be tapped twice in iOS devices, prior to actually signing the user in.
Process:
Upon the first tap, inapp browser opens up and you select which account you're intending to sign in with. Inapp browser closes and seems like all the rest of my logic is not being hit.
Upon the second tap, the inapp browser re-opens up again for a split second (screen is blank), and then closes and THEN the user is actually signed in.
On the iOS simulator/android, however, it seems like it works as expected. Another strange thing is that it works as expected for oauth'ing in with Apple on all devices.
Wondering if anyone else has run into this issue and if y'all have a suggestion?
Where I instantiate the hub listener:
useEffect(() => {
// NOTE: amplify hub listener
const listener = async (data: any) => {
switch (data.payload.event) {
case "signIn":
case "cognitoHostedUI":
await signInUser();
break;
case "signOut":
setUser(null);
break;
default:
break;
}
};
Hub.listen("auth", listener);
}, []);
My google oauth button component:
export function GoogleSignInButton({ title }: GoogleSignInButtonProps) {
return (
<SocialIcon
button
type="google"
title={title}
style={{ padding: 50, marginBottom: 10 }}
onPress={() =>
Auth.federatedSignIn({
provider: "Google" as any,
}).catch(federatedSignInError => {
console.log({ federatedSignInError });
throw new Error(federatedSignInError);
})
}
/>
);
}
I'm also using the react-native-inappbrowser-reborn npm package to have an internal webview when signing in, if that's relevant:
async function urlOpener(url: string, redirectUrl: string) {
await InAppBrowser.isAvailable();
const { type, url: newUrl } = (await InAppBrowser.openAuth(url, redirectUrl, {
showTitle: false,
enableUrlBarHiding: true,
enableDefaultShare: false,
ephemeralWebSession: false,
})) as RedirectResult;
if (type === "success") {
Linking.openURL(newUrl);
}
}
const appsyncAuthenticationTypeOverride = {
...config,
oauth: {
...config.oauth,
urlOpener,
},
aws_appsync_authenticationType: "AWS_IAM",
};
Amplify.configure(appsyncAuthenticationTypeOverride);
i had the same issue.
It seems to be related to Cookies in navigator, you seem to be loading the during the first logging attempt, and using the during the second one.
Also it seems to be sometimes related to redirection errors in Cognito Auth Flow.
I managed to solve it by finding this issue :
https://github.com/aws-amplify/amplify-js/issues/7468
Especially this comment :
https://github.com/aws-amplify/amplify-js/issues/7468#issuecomment-816853703
I am using the following code for checking if my react application has a camera permission:-
checkForCameraPermission = () => {
try {
navigator.permissions.query({ name: 'camera' }).then(permissionStatus => {
// granted, denied, prompt
switch (permissionStatus.state) {
case 'denied':
// eslint-disable-next-line no-alert
// alert(
// 'You need to provide camera permission and reload page to continue futher with KYC journey or else please download the EarlySalary App to continue further.'
// );
this.setState({
cameraDialogStatus: true
});
break;
default:
break;
}
// eslint-disable-next-line no-param-reassign
permissionStatus.onchange = () => {
console.log(`Permission changed to ${this.state}`);
};
});
} catch (error) {
console.log('camera error', error);
// alert('TEST');
this.setState({ isShowTestDialog: true });
}
};
I am using this in component did mount lifecycle method it works fine on most of the browsers but on some browsers it is not supported. So I tried finding out why it wasn't working on some devices and I finally got my answer with the MDN web docs at the following link:-
[https://developer.mozilla.org/en-US/docs/Web/API/Navigator/permissions][1]
Is there a better approach that I can take as my react application is being used on Desktops as well as on mobile phone's and I would like the application to work as expected on all the devices and if not show why it is failing?
Any help or suggestion is much appreciated. Thank you for your time and support.
I'm currently working on a Android mobile App.
It's a kitchen recipes app. The app will send notification to the user during the day.
In the settings of the app, the user can choose how many and at what time he will receive the notifications (11 am to 7 pm for example)
This is where the problem begins;
I use the react-native-push-notification library with the following code:
static LocalNotif(string)
{
PushNotification.localNotification({
vibrate: true, // (optional) default: true
vibration: 300, // vibration length in milliseconds, ignored if vibrate=false, default: 1000
title: "VĂ©rifier vos produit", // (optional)
message: string, // (required)
largeIcon: "ic_launcher",
smallIcon: "ic_notification",
});
}
Next, I use the react-native-background-fetch to send a notification, even if the app is not running
static async backFetch(delay_to_next_notif)
{
BackgroundFetch.configure({
minimumFetchInterval: 3600
}, async (taskId) => {
// This is the fetch-event callback.
console.log("[BackgroundFetch] taskId: ", taskId);
// Use a switch statement to route task-handling.
switch (taskId) {
case 'com.foo.customtask':
this.LocalNotif("test")
break;
default:
console.log("Default fetch task");
}
// Finish, providing received taskId.
BackgroundFetch.finish(taskId);
});
// Step 2: Schedule a custom "oneshot" task "com.foo.customtask" to execute 5000ms from now.
BackgroundFetch.scheduleTask({
taskId: "com.foo.customtask",
forceAlarmManager: true,
delay: delay_to_next_notif// <-- milliseconds
});
}
The use of react-native-background-fetch is very strange. Sometime I never receive the notification.
Is it possible to use a push notification library and create a routine so that the user receives notifications at specific times during the day, even if the app is not running?
You can use Pushnptification.configure method and set your state if your app is in forground or background something like this
async componentDidMount() {
await this.requestUserPermission();
PushNotification.configure({
onNotification: (notification) => {
console.log('NOTIFICATION', notification);
if (notification.foreground === false) {
console.log('app is in background')
}
this.setState({
msg: notification.message.body
? notification.message.body
: notification.message,
forground: notification.foreground,
});
},
});
}
and in your return u can do something like this
{this.state.forground === true
? showMessage({
message: this.state.msg,
backgroundColor: '#1191cf',
type: 'default',
duration: 10000,
icon: 'success',
onPress: () => {
console.log('app is in forground')
},
})
: null}
I need to access the fileHandler object of my logger so I can flush the buffer to the file.
This is my program:
import * as log from "https://deno.land/std#0.75.0/log/mod.ts"
import { Application } from "https://deno.land/x/oak#v6.3.1/mod.ts";
const app = new Application()
const port = 7001
await log.setup({
handlers:{
file: new log.handlers.FileHandler("DEBUG",{
filename: "logger.log",
formatter: lr => {
return `${lr.datetime.toISOString()} [${lr.levelName}] ${lr.msg}`
}
})
},
loggers: {
default: {
level: "DEBUG",
handlers: ["file"]
}
}
})
const logger = log.getLogger()
logger.debug("hi there")
app.use((ctx) => {
ctx.response.body = 'Hi there'
})
console.log(`listening on port ${port}`)
app.listen({ port })
My problem is that the log message is never being written to file.
If I remove the last line ( app.listen() ) it Does write to the file because the process ends.
But if I leave it listening process never ends so the log buffer is never flushed.
If I interrupt the process with Ctrl-C it doesn't write it either
Documentation (https://deno.land/std#0.75.0/log/README.md) says I can force log flush using the flush method from FileHandler. But I don't know how to access the fileHandler object.
So I've tried this:
const logger = log.getLogger()
logger.debug("hi there")
logger.handlers[0].flush()
And it works! but only as javascript, NOT as typescript
As typescript I get this error:
error: TS2339 [ERROR]: Property 'flush' does not exist on type 'BaseHandler'.
logger.handlers[0].flush()
Well, I found a solution.
I just have to import the FileHandler class and cast my handler down from BaseHandler to FileHandler.
So I added this line among the imports:
import { FileHandler } from "https://deno.land/std#0.75.0/log/handlers.ts"
And then after creating the logger:
logger.debug("hi there")
const fileHandler = <FileHandler> logger.handlers[0]
fileHandler.flush()
Looks a little weird, I still guess there must be less quirky / more semantic solution for this. But it works ok.
Let us just recap with the help of Santi's answer.
In my experience logs in file work fine in an ending program. I mean a program which dies by itself or with Deno.exit(0). Problem occurs in a never ending loop. In this case logs don't append in their files. Below is how to overcome this situation :
// dev.js : "I want my logs" example
import {serve} from "https://deno.land/std#0.113.0/http/server_legacy.ts";
import * as log from "https://deno.land/std#0.113.0/log/mod.ts";
// very simple setup, adapted from the official standard lib https://deno.land/std#0.113.0/log
await log.setup({
handlers: {
file: new log.handlers.FileHandler("WARNING", {
filename: "./log.txt",
formatter: "{levelName} {msg}",
}),
},
loggers: {
default: {
level: "DEBUG",
handlers: ["file"],
},
},
});
// here we go
let logger;
logger = log.getLogger();
logger.warning('started');
const fileHandler = logger.handlers[0];
await fileHandler.flush(); // <---- the trick, need to flush ! Thanks Santi
// loop on requests
const srv = serve(`:4321`);
for await (const request of srv) {
request.respond({body: 'bonjour', status: 200});
logger.warning('hit !');
fileHandler.flush(); // <---- flush again
}
Run with
$ deno run -A dev.js
And check the file log.txt with the following trigger
$ curl localhost:4321
This is a very low tech, problably adding important delay to the process. The next level will be to fire a time event to flush every minute or so.