Closed happymago closed 2 years ago
API call is suspended
What API call?
So my app is a calendar app. The task sends out a request to the server to see if there is new appointment. From chrome inspection, I can see the request never got sent out.
Why not show all your code?
async initBackgroundFetch() {
const status = await BackgroundFetch.configure({
minimumFetchInterval: process.env.VUE_APP_FETCH_INTERVAL_MIN,
stopOnTerminate: false, // <-- required
enableHeadless: true
}, async (taskId) => { // <---------------- Event handler.
await this.performSync();
BackgroundFetch.finish(taskId);
}, async (taskId) => { // <---------------- Event timeout handler
BackgroundFetch.finish(taskId);
});
// Checking BackgroundFetch status:
if (status !== BackgroundFetch.STATUS_AVAILABLE) {
// Uh-oh: we have a problem:
if (status === BackgroundFetch.STATUS_DENIED) {
alert('The user explicitly disabled background behavior for this app or for the whole system.');
} else if (status === BackgroundFetch.STATUS_RESTRICTED) {
alert('Background updates are unavailable and the user cannot enable them again.')
}
}
}
async performSync() {
return this.getUpcomingEvents(1, 30).then((data) => {
Storage.clear().then(() => {
data.forEach((element,index) => {
Storage.set({
key: index.toString(),
value: JSON.stringify(element)
})
})
})
})
}
getUpcomingEvents(startIndex, endIndex){
const url = `${API_URL}/events/upcoming?userID=${this.getUserID()}&startIndex=${startIndex}&endIndex=${endIndex}`;
return axios.get(url, { headers: this.authHeader() }).then(response => response.data);
}
I suggest you simplify your code for a test. Do a simple http GET request to Google.com using Flutter default http package.
There is nothing complicated in my method. I am not good with javascript.. Learning to use Flutter will take some time too. BTW, is there a way to call javascript method in BackgroundFetchHeadlessTask? I searched online for a while and did not find anything fit. It all mentions using webview. But there is no webview in this case. So far all my logic is in the javascript, I am trying to avoid writing native code to achieve the same thing as the javascript sync method.
oh, woops. I was thinking we were on the Flutter version. That was Flutter code I posted above. I will do the same with Capacitor version.
Here I will implement a simple GET
request to Google's Books API, where I will capture and print the "totalItems"
property from the response data:
{
"kind": "books#volumes",
"totalItems": 3294,
}
.
. <usual imports here>
.
import { Http, HttpResponse } from '@capacitor-community/http';
export class HomePage {
ngAfterContentInit() {
this.initBackgroundFetch();
}
async initBackgroundFetch() {
const status = await BackgroundFetch.configure({
minimumFetchInterval: 15,
stopOnTerminate: false,
enableHeadless: true
}, async (taskId) => {
console.log('[BackgroundFetch] EVENT:', taskId);
// Perform your work in an awaited Promise
const result = await this.performYourWorkHere();
console.log('[Google Books API] total books:', result.totalItems);
// [REQUIRED] Signal to the OS that your work is complete.
BackgroundFetch.finish(taskId);
}, async (taskId) => {
// The OS has signalled that your remaining background-time has expired.
// You must immediately complete your work and signal #finish.
console.log('[BackgroundFetch] TIMEOUT:', taskId);
// [REQUIRED] Signal to the OS that your work is complete.
BackgroundFetch.finish(taskId);
});
}
// A simple HTTP request to Google's books API
async performYourWorkHere() {
const options = {
url: 'https://www.googleapis.com/books/v1/volumes',
params: { q: '{http}' },
};
const response: HttpResponse = await Http.get(options);
console.log('[HttpResponse] status: ', response.status);
return response.data;
}
}
With simulated events on my Samsung Galaxy S20 FE @ 12.0.0 and /example
app from this repo running in the background, I can see the result of successful http requests being returned.
04-30 13:26:02.458 32716 32716 D TSBackgroundFetch: - Background Fetch event received: capacitor-background-fetch
04-30 13:26:02.483 32716 32716 I Capacitor/Console: - Msg: [BackgroundFetch] EVENT: capacitor-background-fetch
04-30 13:26:04.565 32716 32716 I Capacitor/Console: - Msg: [HttpResponse] status: 200
04-30 13:26:04.567 32716 32716 I Capacitor/Console: - Msg: [Google Books API] total books: 3294
04-30 13:26:04.570 32716 661 V Capacitor/Plugin: To native (Capacitor plugin): callbackId: 95804698, pluginId: BackgroundFetch, methodName: finish
04-30 13:26:04.571 32716 520 D TSBackgroundFetch: - finish: capacitor-background-fetch
04-30 13:26:04.572 32716 520 D TSBackgroundFetch: - jobFinished
Thanks for your code. It does work. With this plugin, the API call can fire without issues even if the app is in the background. I wonder what is the difference vs Axios. I notice the API call with this plugin does not show up in the Network tab in chrome. Maybe that is why?
The http package I linked above is implementing native iOS / Android requests. It won't show up in the browser.
It is best to do native http requests instead of relying on the browser.
I see. Thank you for the explanation. It might be difficult for me. I initially built a web app and now use capacitor to convert it into mobile apps. I am good for now. At least figured out what is wrong. You can close this ticket.
2023-06-06 16:42:50.601 18995-18995 TSBackgroundFetch com..............viewdev D - Background Fetch event received: capacitor-background-fetch 2023-06-06 16:42:50.602 18995-18995 MyHeadlessTask com.............viewdev D BackgroundFetchHeadlessTask onFetch -- CUSTOM IMPLEMENTATION: capacitor-background-fetch 2023-06-06 16:42:50.602 18995-18995 TSBackgroundFetch com.............webviewdev D - finish: capacitor-background-fetch 2023-06-06 16:42:50.602 18995-18995 TSBackgroundFetch com.............webviewdev D - jobFinished
Here I will implement a simple
GET
request to Google's Books API, where I will capture and print the"totalItems"
property from the response data:{ "kind": "books#volumes", "totalItems": 3294, }
. . <usual imports here> . import { Http, HttpResponse } from '@capacitor-community/http'; export class HomePage { ngAfterContentInit() { this.initBackgroundFetch(); } async initBackgroundFetch() { const status = await BackgroundFetch.configure({ minimumFetchInterval: 15, stopOnTerminate: false, enableHeadless: true }, async (taskId) => { console.log('[BackgroundFetch] EVENT:', taskId); // Perform your work in an awaited Promise const result = await this.performYourWorkHere(); console.log('[Google Books API] total books:', result.totalItems); // [REQUIRED] Signal to the OS that your work is complete. BackgroundFetch.finish(taskId); }, async (taskId) => { // The OS has signalled that your remaining background-time has expired. // You must immediately complete your work and signal #finish. console.log('[BackgroundFetch] TIMEOUT:', taskId); // [REQUIRED] Signal to the OS that your work is complete. BackgroundFetch.finish(taskId); }); } // A simple HTTP request to Google's books API async performYourWorkHere() { const options = { url: 'https://www.googleapis.com/books/v1/volumes', params: { q: '{http}' }, }; const response: HttpResponse = await Http.get(options); console.log('[HttpResponse] status: ', response.status); return response.data; } }
With simulated events on my Samsung Galaxy S20 FE @ 12.0.0 and
/example
app from this repo running in the background, I can see the result of successful http requests being returned.04-30 13:26:02.458 32716 32716 D TSBackgroundFetch: - Background Fetch event received: capacitor-background-fetch 04-30 13:26:02.483 32716 32716 I Capacitor/Console: - Msg: [BackgroundFetch] EVENT: capacitor-background-fetch 04-30 13:26:04.565 32716 32716 I Capacitor/Console: - Msg: [HttpResponse] status: 200 04-30 13:26:04.567 32716 32716 I Capacitor/Console: - Msg: [Google Books API] total books: 3294 04-30 13:26:04.570 32716 661 V Capacitor/Plugin: To native (Capacitor plugin): callbackId: 95804698, pluginId: BackgroundFetch, methodName: finish 04-30 13:26:04.571 32716 520 D TSBackgroundFetch: - finish: capacitor-background-fetch 04-30 13:26:04.572 32716 520 D TSBackgroundFetch: - jobFinished
Here I am just testing with above example code. But unfortunately I didn't get http status response. My app was in killed State
async performYourWorkHere() { const options = { url: 'https://www.googleapis.com/books/v1/volumes', params: { q: '{http}' }, }; const response: HttpResponse = await Http.get(options); console.log('[HttpResponse] status: ', response.status); return response.data; }
Your Environment
npx cap doctor
) "@capacitor/android": "^3.3.3", "@capacitor/app": "^1.1.0", "@capacitor/cli": "^3.3.3", "@capacitor/core": "^3.0.0-rc.4",BackgroundFetch.configure
: minimumFetchInterval: process.env.VUE_APP_FETCH_INTERVAL_MIN, stopOnTerminate: false, // <-- required enableHeadless: trueExpected Behavior
The background task should work fine while the app is in the background
Actual Behavior
The API call in the task gets in pending status and never sends out. So the task ended up timing out. Is this expected behavior?
Steps to Reproduce
Context
Debug logs