UNPKG

expo-foreground-actions

Version:
140 lines 5.28 kB
import { NativeModulesProxy, EventEmitter, Platform } from "expo-modules-core"; import { platformApiLevel } from "expo-device"; import ExpoForegroundActionsModule from "./ExpoForegroundActionsModule"; import { AppRegistry, AppState } from "react-native"; const emitter = new EventEmitter(ExpoForegroundActionsModule ?? NativeModulesProxy.ExpoForegroundActions); let ranTaskCount = 0; let jsIdentifier = 0; export class NotForegroundedError extends Error { constructor(message) { super(message); // (1) this.name = "NotForegroundedError"; // (2) } } const startForegroundAction = async (options) => { if (Platform.OS === "android" && !options) { throw new Error("Foreground action options cannot be null on android"); } if (Platform.OS === "android") { return ExpoForegroundActionsModule.startForegroundAction(options); } else { return ExpoForegroundActionsModule.startForegroundAction(); } }; // Get the native constant value. export const runForegroundedAction = async (act, androidSettings, settings = { runInJS: false }) => { if (!androidSettings) { throw new Error("Foreground action options cannot be null"); } if (AppState.currentState === "background") { throw new NotForegroundedError("Foreground actions can only be run in the foreground"); } if (Platform.OS === "android" && platformApiLevel && platformApiLevel < 26) { settings.runInJS = true; } const headlessTaskName = `${androidSettings.headlessTaskName}${ranTaskCount}`; const initOptions = { ...androidSettings, headlessTaskName }; const action = async (identifier) => { if (AppState.currentState === "background") { throw new NotForegroundedError("Foreground actions can only be run in the foreground"); } await act({ headlessTaskName, identifier }); }; if (Platform.OS !== "ios" && Platform.OS !== "android") { throw new Error("Unsupported platform, currently only ios and android are supported"); } try { ranTaskCount++; if (settings.runInJS === true) { await runJS(action, settings); return; } if (Platform.OS === "android") { /*On android we wrap the headless task in a promise so we can "await" the starter*/ await runAndroid(action, initOptions, settings); return; } if (Platform.OS === "ios") { await runIos(action, settings); return; } return; } catch (e) { throw e; } }; const runJS = async (action, settings) => { jsIdentifier++; settings?.events?.onIdentifier?.(jsIdentifier); await action(jsIdentifier); jsIdentifier = 0; }; const runIos = async (action, settings) => { const identifier = await startForegroundAction(); settings?.events?.onIdentifier?.(identifier); try { await action(identifier); } catch (e) { throw e; } finally { await stopForegroundAction(identifier); } }; const runAndroid = async (action, options, settings) => new Promise(async (resolve, reject) => { try { /*First we register the headless task so we can run it from the Foreground service*/ AppRegistry.registerHeadlessTask(options.headlessTaskName, () => async (taskdata) => { const { notificationId } = taskdata; /*Then we start the actuall foreground action, we all do this in the headless task, without touching UI, we can still update UI be using something like Realm for example*/ try { settings?.events?.onIdentifier?.(notificationId); await action(notificationId); await stopForegroundAction(notificationId); resolve(); } catch (e) { /*We do this to make sure its ALWAYS stopped*/ await stopForegroundAction(notificationId); throw e; } }); await startForegroundAction(options); } catch (e) { reject(e); throw e; } }); export const updateForegroundedAction = async (id, options) => { if (Platform.OS !== "android") return; return ExpoForegroundActionsModule.updateForegroundedAction(id, options); }; // noinspection JSUnusedGlobalSymbols export const stopForegroundAction = async (id) => { await ExpoForegroundActionsModule.stopForegroundAction(id); }; // noinspection JSUnusedGlobalSymbols export const forceStopAllForegroundActions = async () => { await ExpoForegroundActionsModule.forceStopAllForegroundActions(); }; // noinspection JSUnusedGlobalSymbols export const getForegroundIdentifiers = async () => ExpoForegroundActionsModule.getForegroundIdentifiers(); // noinspection JSUnusedGlobalSymbols export const getRanTaskCount = () => ranTaskCount; export const getBackgroundTimeRemaining = async () => { if (Platform.OS !== "ios") return -1; return await ExpoForegroundActionsModule.getBackgroundTimeRemaining(); }; export function addExpirationListener(listener) { return emitter.addListener("onExpirationEvent", listener); } //# sourceMappingURL=index.js.map