UNPKG

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
"use strict"; 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