expo-foreground-actions
Version:
140 lines • 5.28 kB
JavaScript
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