Files
native/index.ts
T
Linus Rath c5143975db fix: finish the widget refresh after leaving the app #52
The previous fix started the refresh as the app went to the background,
but it still stopped after its first request: fetch hands every response
over through a JS timer, and React Native pauses timers while the app's
activity is in the background, so the answer was only read once the app
came back. The widgets kept the previous account after a switch and
Home, and changes made in the app reached them late.

The refresh now runs as a headless task of its own,
BulwarkWidgetRefresh, started through BulwarkWidgetRefreshService. A
running headless task keeps the timers going, and the service keeps the
process from being frozen before the widgets are redrawn. Where Android
refuses to start the service the app refreshes in place as before. A
refresh started for a change also no longer joins one that began before
it.
2026-10-02 12:01:31 +02:00

45 lines
2.3 KiB
TypeScript

import { createElement } from 'react';
import { AppRegistry } from 'react-native';
import { registerRootComponent } from 'expo';
import { registerWidgetTaskHandler } from 'react-native-android-widget';
import { pushBackgroundTask } from './src/lib/push-background-task';
import { widgetTaskHandler } from './src/widgets/task-handler';
import { refreshWidgetsInBackground } from './src/widgets/sync';
import { markUiStarted } from './src/widgets/ui-presence';
// Runs in a fresh headless JS runtime when BulwarkPushTaskService is started
// from BulwarkMessagingService on an FCM data message. Must be registered
// before the native service tries to invoke the task. New mail also refreshes
// any home-screen widgets (a no-op when none are placed).
AppRegistry.registerHeadlessTask('BulwarkPushTask', () => async (data: Parameters<typeof pushBackgroundTask>[0]) => {
await Promise.allSettled([pushBackgroundTask(data), refreshWidgetsInBackground()]);
});
// Device sync (Android, #34): the contacts and calendar sync adapters run the
// sync engine through this task, headless or next to the UI. The engine is
// required on first use so an app start does not load it.
AppRegistry.registerHeadlessTask('BulwarkDeviceSync', () => async (data: import('./src/device-sync/types').RunPayload) => {
const { runDeviceSyncTask } = require('./src/device-sync/task') as typeof import('./src/device-sync/task');
await runDeviceSyncTask(data);
});
// Home-screen widgets (Android): every widget event runs this headless task.
registerWidgetTaskHandler(widgetTaskHandler);
// ...and leaving the app refreshes them in one (BulwarkWidgetRefreshService).
AppRegistry.registerHeadlessTask('BulwarkWidgetRefresh', () => refreshWidgetsInBackground);
// A headless push task evaluates this file too, so App is required when the
// UI first renders instead of imported above: importing it here would load
// every screen, store and icon before the task could run.
function Root() {
markUiStarted();
const App = (require('./App') as typeof import('./App')).default;
return createElement(App);
}
// registerRootComponent calls AppRegistry.registerComponent('main', () => Root);
// It also ensures that whether you load the app in Expo Go or in a native build,
// the environment is set up appropriately
registerRootComponent(Root);