react-native-background-task-manager
Version:
Advanced React Native background task manager with foreground services, scheduling, and geolocation support for Android
365 lines (340 loc) • 10.4 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
var _exportNames = {};
exports.default = void 0;
var _reactNative = require("react-native");
var _index = require("./index");
Object.keys(_index).forEach(function (key) {
if (key === "default" || key === "__esModule") return;
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
if (key in exports && exports[key] === _index[key]) return;
Object.defineProperty(exports, key, {
enumerable: true,
get: function () {
return _index[key];
}
});
});
const LINKING_ERROR = `The package 'react-native-background-task-manager' doesn't seem to be linked. Make sure: \n\n` + _reactNative.Platform.select({
ios: "- You have run 'cd ios && pod install'\n",
default: ''
}) + '- You rebuilt the app after installing the package\n' + '- You are not using Expo managed workflow\n';
const RNForegroundService = _reactNative.NativeModules.RNForegroundService ?? new Proxy({}, {
get() {
throw new Error(LINKING_ERROR);
}
});
class ForegroundServiceClass {
eventEmitter = null;
// Enhanced service tracking
serviceStartTime = null;
serviceCount = 0;
constructor() {
if (_reactNative.Platform.OS === 'android' && RNForegroundService) {
this.eventEmitter = new _reactNative.NativeEventEmitter(RNForegroundService);
}
}
/**
* Start the foreground service with enhanced validation and tracking
*/
async startService(options) {
if (_reactNative.Platform.OS !== 'android') {
console.warn('Foreground service is only supported on Android');
return;
}
// Enhanced validation
if (!options.taskName || !options.taskTitle) {
throw new Error('taskName and taskTitle are required fields');
}
// Validate service type for Android 14+
if (_reactNative.Platform.Version >= 34 && !options.serviceType) {
throw new Error('serviceType is required for Android 14+ (API level 34)');
}
try {
// Check permissions before starting
const hasPermission = await this.checkPermission();
if (!hasPermission) {
const granted = await this.requestPermission();
if (!granted) {
throw new Error('Foreground service permission denied');
}
}
await RNForegroundService.startService(options);
this.serviceStartTime = Date.now();
this.serviceCount++;
} catch (error) {
throw new Error(`Failed to start foreground service: ${error}`);
}
}
/**
* Stop the foreground service with enhanced tracking
*/
async stopService() {
if (_reactNative.Platform.OS !== 'android') {
return;
}
try {
await RNForegroundService.stopService();
this.serviceCount = Math.max(0, this.serviceCount - 1);
if (this.serviceCount === 0) {
this.serviceStartTime = null;
}
} catch (error) {
throw new Error(`Failed to stop foreground service: ${error}`);
}
}
/**
* Stop all service instances (force stop) with enhanced tracking
*/
async stopServiceAll() {
if (_reactNative.Platform.OS !== 'android') {
return;
}
try {
await RNForegroundService.stopServiceAll();
this.serviceCount = 0;
this.serviceStartTime = null;
} catch (error) {
throw new Error(`Failed to stop all foreground services: ${error}`);
}
}
/**
* Update the foreground service notification
*/
async updateService(options) {
if (_reactNative.Platform.OS !== 'android') {
return;
}
return RNForegroundService.updateService(options);
}
/**
* Check if the service is running
*/
async isServiceRunning() {
if (_reactNative.Platform.OS !== 'android') {
return false;
}
return RNForegroundService.isServiceRunning();
}
/**
* Check if app has foreground service permission
*/
async checkPermission() {
if (_reactNative.Platform.OS !== 'android') {
return true; // iOS doesn't need explicit permission
}
return RNForegroundService.checkPermission();
}
/**
* Check notification permission specifically (Android 13+)
*/
async checkNotificationPermission() {
if (_reactNative.Platform.OS !== 'android') {
return true; // iOS doesn't need explicit permission check here
}
return RNForegroundService.checkNotificationPermission();
}
/**
* Check if app is exempted from battery optimization
*/
async checkBatteryOptimization() {
if (_reactNative.Platform.OS !== 'android') {
return true; // iOS doesn't have battery optimization settings
}
return RNForegroundService.checkBatteryOptimization();
}
/**
* Request foreground service permission
*/
async requestPermission() {
if (_reactNative.Platform.OS !== 'android') {
return true; // iOS doesn't need explicit permission
}
return RNForegroundService.requestPermission();
}
/**
* Request notification permission (Android 13+)
* Note: This should be called from React Native side using PermissionsAndroid
*/
async requestNotificationPermission() {
if (_reactNative.Platform.OS !== 'android') {
return true;
}
if (_reactNative.Platform.Version >= 33) {
try {
const granted = await _reactNative.PermissionsAndroid.request('android.permission.POST_NOTIFICATIONS');
return granted === _reactNative.PermissionsAndroid.RESULTS.GRANTED;
} catch (error) {
console.error('Error requesting notification permission:', error);
return false;
}
}
return true; // Permission not needed on older versions
}
/**
* Get service instance count
*/
async getServiceCount() {
if (_reactNative.Platform.OS !== 'android') {
return 0;
}
return RNForegroundService.getServiceCount();
}
/**
* Register event listeners for service events
*/
addEventListener(listener) {
if (!this.eventEmitter || _reactNative.Platform.OS !== 'android') {
return;
}
const eventMap = [{
event: 'onServiceStart',
callback: listener.onServiceStart
}, {
event: 'onServiceStop',
callback: listener.onServiceStop
}, {
event: 'onServiceError',
callback: listener.onServiceError
}, {
event: 'onButtonPress',
callback: listener.onButtonPress
}, {
event: 'onActionPress',
callback: listener.onActionPress
}, {
event: 'onTaskComplete',
callback: listener.onTaskComplete
}];
eventMap.forEach(({
event,
callback
}) => {
if (callback) {
this.eventEmitter.addListener(event, callback);
}
});
// Handle onTaskError separately due to multiple parameters
if (listener.onTaskError) {
this.eventEmitter.addListener('onTaskError', event => {
listener.onTaskError(event.taskId, event.error);
});
}
}
/**
* Remove event listeners
*/
removeEventListener() {
if (this.eventEmitter && _reactNative.Platform.OS === 'android') {
this.eventEmitter.removeAllListeners('onServiceStart');
this.eventEmitter.removeAllListeners('onServiceStop');
this.eventEmitter.removeAllListeners('onServiceError');
this.eventEmitter.removeAllListeners('onButtonPress');
this.eventEmitter.removeAllListeners('onActionPress');
this.eventEmitter.removeAllListeners('onTaskComplete');
this.eventEmitter.removeAllListeners('onTaskError');
}
}
/**
* Get current service status with detailed information and enhanced tracking
*/
async getServiceStatus() {
if (_reactNative.Platform.OS !== 'android') {
return {
isRunning: false
};
}
try {
const isRunning = await this.isServiceRunning();
const taskStats = this.TaskManager.getStats();
const result = {
isRunning,
taskCount: taskStats.totalTasks,
notificationId: 1
};
if (this.serviceStartTime !== null && this.serviceStartTime !== undefined) {
result.startTime = this.serviceStartTime;
result.uptime = Date.now() - this.serviceStartTime;
}
return result;
} catch (error) {
console.error('Error getting service status:', error);
return {
isRunning: false
};
}
}
/**
* Get service performance metrics with enhanced tracking
*/
async getServiceMetrics() {
const taskStats = this.TaskManager.getStats();
return {
uptime: this.serviceStartTime ? Date.now() - this.serviceStartTime : 0,
tasksExecuted: taskStats.totalTasks,
tasksSucceeded: taskStats.completedTasks,
tasksFailed: taskStats.failedTasks,
memoryUsage: 0,
batteryImpact: 'low'
};
}
/**
* Request battery optimization exemption (required for long-running services)
*/
async requestBatteryOptimizationExemption() {
if (_reactNative.Platform.OS !== 'android') {
return true;
}
return RNForegroundService.requestBatteryOptimizationExemption();
}
/**
* Register a foreground task (headless task support) with enhanced integration
*/
registerForegroundTask(taskName, task) {
if (_reactNative.Platform.OS !== 'android') {
return;
}
_reactNative.AppRegistry.registerHeadlessTask(taskName, () => task);
}
/**
* Run a registered task with enhanced error handling
*/
async runTask(taskConfig) {
if (_reactNative.Platform.OS !== 'android') {
return;
}
try {
await RNForegroundService.runTask(taskConfig);
} catch (error) {
throw new Error(`Failed to run task: ${error}`);
}
}
/**
* Cancel a specific notification with enhanced error handling
*/
async cancelNotification(notificationId) {
if (_reactNative.Platform.OS !== 'android') {
return;
}
try {
await RNForegroundService.cancelNotification(notificationId);
} catch (error) {
throw new Error(`Failed to cancel notification: ${error}`);
}
}
/**
* Task Manager - Advanced task management
*/
get TaskManager() {
// Import TaskManager here to avoid circular dependency
const {
TaskManager
} = require('./TaskManager');
return TaskManager;
}
}
const ForegroundService = new ForegroundServiceClass();
var _default = exports.default = ForegroundService;
//# sourceMappingURL=ForegroundService.js.map