New:Microsoft Teams Notifications Are Now Available in Socket.Learn more
Get Started

rnww-plugin-background

Package Overview
Dependencies
Maintainers
1
Versions
22
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

rnww-plugin-background

React Native WebView Background Execution Plugin with Expo support

npmnpm
Version
1.2.1
Version published
Weekly downloads
1
-98.18%
Maintainers
1
Weekly downloads
 
Created
Source

RNWW Plugin Background

React Native WebView 백그라운드 실행 제어 플러그인

설치

npm install rnww-plugin-background

빠른 시작

import { registerBackgroundHandlers } from 'rnww-plugin-background';

registerBackgroundHandlers({
  bridge: yourBridgeImplementation,
  platform: { OS: Platform.OS },
});

Bridge Handlers

registerTask

백그라운드 작업을 등록합니다.

bridge.call('registerTask', {
  taskId: 'sync-task',
  mode: 'persistent',
  interval: 60000,
  triggers: ['network_change', 'battery_low'],
  callbackId: 'my-callback',
  callback: (event) => {
    console.log('Task event:', event);
  },
  notification: {
    title: '백그라운드 실행 중',
    body: '동기화 진행 중...',
    color: '#4CAF50',
    priority: 'high',
    ongoing: true,
    progress: { current: 0, max: 100 },
    actions: [
      {
        id: 'pause',
        title: '일시정지',
        onPress: (actionId, taskId) => {
          console.log(`Action ${actionId} clicked for task ${taskId}`);
        }
      }
    ]
  }
});

startTask / stopTask

작업을 시작하거나 중지합니다.

bridge.call('startTask', { taskId: 'sync-task' });
bridge.call('stopTask', { taskId: 'sync-task' });
bridge.call('stopAllTasks');

unregisterTask

등록된 작업을 해제합니다.

bridge.call('unregisterTask', { taskId: 'sync-task' });

updateNotification

알림 내용을 동적으로 업데이트합니다.

bridge.call('updateNotification', {
  taskId: 'sync-task',
  title: '동기화 중',
  body: '50% 완료',
  progress: { current: 50, max: 100 },
  actions: [
    {
      id: 'cancel',
      title: '취소',
      onPress: (actionId, taskId) => {
        bridge.call('stopTask', { taskId });
      }
    }
  ]
});

getTaskStatus / getAllTasksStatus

작업 상태를 조회합니다.

const status = await bridge.call('getTaskStatus', { taskId: 'sync-task' });
const allStatus = await bridge.call('getAllTasksStatus');

checkBackgroundPermission / requestBackgroundPermission

백그라운드 권한을 확인하고 요청합니다.

const permission = await bridge.call('checkBackgroundPermission');
// {
//   success: true,
//   canRunBackground: boolean,
//   batteryOptimizationExempt: boolean,
//   notificationPermission: boolean,  // Android 13+
//   requiredPermissions: string[],
//   deniedPermissions: string[]
// }

if (!permission.canRunBackground) {
  await bridge.call('requestBackgroundPermission');
}

checkNotificationPermission / requestNotificationPermission

알림 권한을 확인하고 요청합니다. (Android 13+ 필수)

// 알림 권한 확인
const notifPerm = await bridge.call('checkNotificationPermission');
// { success: true, granted: boolean, canAskAgain: boolean }

// 알림 권한 요청
if (!notifPerm.granted) {
  const result = await bridge.call('requestNotificationPermission');
  // { success: true, granted: boolean, canAskAgain: boolean, openedSettings?: boolean }
}

참고: Android 12 이하에서는 항상 granted: true를 반환합니다.

disposeBackgroundHandlers

브릿지 핸들러와 리소스를 정리합니다.

bridge.call('disposeBackgroundHandlers');

콜백 시스템

Task Callback

작업 등록 시 callback 함수를 지정하면 해당 작업의 모든 이벤트를 수신합니다.

bridge.call('registerTask', {
  taskId: 'my-task',
  mode: 'persistent',
  callback: (event) => {
    switch (event.type) {
      case 'started':
        console.log('작업 시작됨');
        break;
      case 'stopped':
        console.log('작업 중지됨');
        break;
      case 'trigger':
        console.log(`트리거 발생: ${event.trigger}`, event.data);
        break;
      case 'action':
        console.log(`액션 클릭: ${event.actionId}`);
        break;
      case 'error':
        console.error('에러 발생:', event.error);
        break;
    }
  },
  notification: { title: 'Task', body: 'Running...' }
});

Action Callback

각 알림 액션 버튼에 onPress 콜백을 개별 지정할 수 있습니다.

bridge.call('registerTask', {
  taskId: 'download-task',
  mode: 'persistent',
  notification: {
    title: '다운로드 중',
    body: '파일 다운로드...',
    actions: [
      {
        id: 'pause',
        title: '일시정지',
        icon: 'ic_pause',
        dismissOnPress: false,
        onPress: async (actionId, taskId) => {
          await pauseDownload();
          bridge.call('updateNotification', {
            taskId,
            title: '일시정지됨',
            body: '다운로드가 일시정지되었습니다'
          });
        }
      },
      {
        id: 'cancel',
        title: '취소',
        dismissOnPress: true,
        bringToForeground: false,
        onPress: async (actionId, taskId) => {
          await cancelDownload();
          bridge.call('stopTask', { taskId });
        }
      }
    ]
  }
});

Callback ID

callbackId를 지정하면 이벤트 수신 시 해당 ID가 함께 전달되어 여러 작업의 이벤트를 구분할 수 있습니다.

// 작업 등록
bridge.call('registerTask', {
  taskId: 'task-1',
  callbackId: 'sync-callback',
  // ...
});

bridge.call('registerTask', {
  taskId: 'task-2',
  callbackId: 'upload-callback',
  // ...
});

// 이벤트 수신
bridge.on('onTaskEvent', (event) => {
  if (event.callbackId === 'sync-callback') {
    // task-1의 이벤트 처리
  } else if (event.callbackId === 'upload-callback') {
    // task-2의 이벤트 처리
  }
});

트리거 시스템

트리거 종류

트리거설명
interval주기적 실행 (interval 옵션 사용)
network_change네트워크 상태 변경 (연결/해제)
location_change위치 변경 (significant location change)
time_trigger예약된 시간에 실행
battery_low배터리 부족 (기본 15% 이하)
battery_okay배터리 정상 복귀
battery_charging충전 시작
battery_discharging충전 해제
app_foreground앱이 포그라운드로 전환
app_background앱이 백그라운드로 전환
app_terminate앱 종료 시
custom사용자 정의 트리거

간단한 사용법

문자열로 트리거 타입만 지정:

bridge.call('registerTask', {
  taskId: 'my-task',
  mode: 'persistent',
  triggers: ['network_change', 'battery_low', 'app_background'],
  // ...
});

상세 설정

객체로 트리거별 옵션 지정:

bridge.call('registerTask', {
  taskId: 'my-task',
  mode: 'persistent',
  triggers: [
    // 배터리 30% 이하일 때 트리거
    {
      type: 'battery_low',
      options: { threshold: 30 }
    },
    // WiFi 연결 변경만 감지
    {
      type: 'network_change',
      options: { networkTypes: ['wifi'] }
    },
    // 100m 이상 이동 시 트리거
    {
      type: 'location_change',
      options: { minDistance: 100 }
    },
    // 사용자 정의 트리거
    {
      type: 'custom',
      customId: 'my-custom-trigger'
    }
  ],
  callback: (event) => {
    if (event.type === 'trigger') {
      switch (event.trigger) {
        case 'battery_low':
          console.log('배터리 레벨:', event.data?.batteryLevel);
          break;
        case 'network_change':
          console.log('네트워크:', event.data?.networkType, event.data?.isConnected);
          break;
        case 'location_change':
          console.log('위치:', event.data?.location);
          break;
        case 'custom':
          console.log('커스텀 트리거:', event.customTriggerId);
          break;
      }
    }
  },
  // ...
});

트리거 옵션 상세

battery_low / battery_okay

{
  type: 'battery_low',
  options: {
    threshold: 20  // 배터리 임계값 % (기본: 15)
  }
}

이벤트 데이터:

event.data?.batteryLevel  // 현재 배터리 레벨 (%)

network_change

{
  type: 'network_change',
  options: {
    networkTypes: ['wifi', 'cellular']  // 감지할 네트워크 타입
  }
}

이벤트 데이터:

event.data?.networkType   // 'wifi' | 'cellular' | 'ethernet' | 'none'
event.data?.isConnected   // 연결 상태 (boolean)

location_change

{
  type: 'location_change',
  options: {
    minDistance: 50  // 최소 이동 거리 (미터)
  }
}

이벤트 데이터:

event.data?.location  // { latitude: number, longitude: number }

time_trigger

예약 시간에 트리거. scheduledTime 필드와 함께 사용:

bridge.call('registerTask', {
  taskId: 'scheduled-task',
  mode: 'efficient',
  triggers: ['time_trigger'],
  scheduledTime: Date.now() + 3600000,  // 1시간 후
  // ...
});

custom

사용자 정의 트리거. 네이티브 측에서 직접 발생시킬 수 있음:

{
  type: 'custom',
  customId: 'my-sync-trigger'  // 고유 식별자
}

이벤트에서 event.customTriggerId로 식별 가능.

알림 설정

기본 알림

notification: {
  title: '백그라운드 작업',
  body: '작업이 실행 중입니다',
  icon: 'ic_notification',  // Android drawable 리소스명
}

스타일 옵션

notification: {
  title: '동기화',
  body: '데이터 동기화 중...',

  // 아이콘/강조 색상 (hex)
  color: '#4CAF50',

  // 우선순위
  // 'min': 최소 (무음, 상태바만)
  // 'low': 낮음 (무음)
  // 'default': 기본
  // 'high': 높음 (헤드업 알림)
  // 'max': 최대 (긴급)
  priority: 'high',

  // 지속 알림 (사용자가 스와이프로 닫을 수 없음)
  // persistent 모드에서는 항상 true
  ongoing: true,

  // 무음 알림 (소리/진동 없이 내용만 변경)
  // updateNotification 시 기본 true
  silent: false,
}

진행 상태바

notification: {
  title: '다운로드 중',
  body: '50% 완료',
  progress: {
    current: 50,
    max: 100,
    indeterminate: false  // true면 무한 진행 표시
  }
}

무한 진행 표시 (로딩):

progress: {
  current: 0,
  max: 100,
  indeterminate: true
}

액션 버튼

최대 3개까지 지원:

notification: {
  title: '음악 재생 중',
  body: 'Now Playing...',
  actions: [
    {
      id: 'prev',
      title: '이전',
      icon: 'ic_prev',  // Android drawable (선택)
      dismissOnPress: false,  // 클릭 시 알림 유지
      bringToForeground: false,  // 앱을 포그라운드로 가져오지 않음
      onPress: (actionId, taskId) => {
        playPrevious();
      }
    },
    {
      id: 'pause',
      title: '일시정지',
      icon: 'ic_pause',
      onPress: (actionId, taskId) => {
        togglePlayPause();
      }
    },
    {
      id: 'next',
      title: '다음',
      icon: 'ic_next',
      onPress: (actionId, taskId) => {
        playNext();
      }
    }
  ]
}

채널 설정 (Android 8.0+)

notification: {
  title: '알림',
  body: '내용',
  channelId: 'sync_channel',
  channelName: '동기화 알림',
  channelDescription: '백그라운드 동기화 알림을 표시합니다'
}

실행 모드

persistent 모드

포그라운드 서비스로 항상 실행됩니다. 알림이 필수입니다.

bridge.call('registerTask', {
  taskId: 'always-on',
  mode: 'persistent',
  interval: 10000,  // 최소 1초 (1000ms)
  notification: {   // 필수
    title: '실행 중',
    body: '백그라운드 서비스 동작 중'
  }
});

특징:

  • 시스템에 의해 종료되지 않음 (높은 우선순위)
  • 항상 알림 표시 (ongoing: true 강제)
  • interval 최소값: 1000ms (1초)
  • 배터리 사용량 높음

efficient 모드

시스템이 관리하는 효율적 실행입니다. (WorkManager/BGTaskScheduler)

bridge.call('registerTask', {
  taskId: 'periodic-sync',
  mode: 'efficient',
  interval: 900000,  // 최소 15분 (900000ms)
  triggers: ['network_change'],
  notification: {  // 선택
    title: '동기화',
    body: '대기 중...'
  }
});

특징:

  • 시스템이 배터리/리소스에 따라 실행 시점 조정
  • interval 최소값: 900000ms (15분, 시스템 제한)
  • 정확한 타이밍 보장 안됨
  • 배터리 효율적

이벤트

onTaskEvent

모든 작업 이벤트를 수신합니다.

bridge.on('onTaskEvent', (event) => {
  console.log('Event:', event);
});

TaskEvent 구조

interface TaskEvent {
  taskId: string;              // 작업 ID
  callbackId?: string;         // 등록 시 지정한 콜백 ID
  type: 'started' | 'stopped' | 'restart' | 'error' | 'trigger' | 'action' | 'terminating' | 'terminated';
  reason?: 'unexpected' | 'system_kill' | 'user_force_stop';  // 종료 사유 (terminated일 때)
  lastStartedAt?: number;      // 마지막 시작 시간 (terminated일 때)
  trigger?: TriggerType;       // 트리거 종류 (type이 'trigger'일 때)
  customTriggerId?: string;    // custom 트리거 식별자
  actionId?: string;           // 액션 버튼 ID (type이 'action'일 때)
  error?: string;              // 에러 메시지 (type이 'error'일 때)
  data?: {                     // 트리거 관련 데이터
    batteryLevel?: number;
    networkType?: 'wifi' | 'cellular' | 'ethernet' | 'none';
    isConnected?: boolean;
    location?: { latitude: number; longitude: number };
    [key: string]: unknown;
  };
  timestamp: number;           // 타임스탬프
}

이벤트 타입:

  • started: 작업 시작됨
  • stopped: 작업 중지됨
  • restart: 작업 재시작됨
  • error: 에러 발생
  • trigger: 트리거 발생
  • action: 알림 액션 클릭
  • terminating: 백그라운드 서비스 종료 직전 (onTerminate 콜백 실행)
  • terminated: 프로세스 강제 종료로 비정상 종료됨 (앱 재시작 시 감지)

타입 정의

BackgroundTask

interface BackgroundTask {
  taskId: string;
  mode: 'persistent' | 'efficient';
  interval?: number;
  triggers?: TriggerConfig[];
  scheduledTime?: number;
  callbackId?: string;
  callback?: (event: TaskEvent) => void | Promise<void>;
  onTerminate?: (event: TaskEvent) => void | Promise<void>;  // 종료 직전 콜백
  notification?: NotificationConfig;
}

TriggerConfig

type TriggerType =
  | 'interval'
  | 'network_change'
  | 'location_change'
  | 'time_trigger'
  | 'battery_low'
  | 'battery_okay'
  | 'battery_charging'
  | 'battery_discharging'
  | 'app_foreground'
  | 'app_background'
  | 'app_terminate'
  | 'custom';

type TriggerConfig = TriggerType | {
  type: TriggerType;
  customId?: string;
  options?: {
    threshold?: number;
    minDistance?: number;
    networkTypes?: Array<'wifi' | 'cellular' | 'ethernet'>;
  };
};

NotificationConfig

interface NotificationConfig {
  taskId?: string;
  title: string;
  body: string;
  icon?: string;
  color?: string;
  priority?: 'min' | 'low' | 'default' | 'high' | 'max';
  ongoing?: boolean;
  silent?: boolean;     // 무음 알림 (기본: registerTask시 false, updateNotification시 true)
  progress?: {
    current: number;
    max: number;
    indeterminate?: boolean;
  };
  actions?: NotificationAction[];
  channelId?: string;
  channelName?: string;
  channelDescription?: string;
}

NotificationAction

interface NotificationAction {
  id: string;
  title: string;
  icon?: string;
  onPress?: (actionId: string, taskId: string) => void | Promise<void>;
  dismissOnPress?: boolean;   // 기본: true
  bringToForeground?: boolean; // 기본: false
}

BackgroundError

type BackgroundError =
  | 'TASK_NOT_FOUND'
  | 'TASK_ALREADY_EXISTS'
  | 'TASK_ALREADY_RUNNING'
  | 'TASK_NOT_RUNNING'
  | 'PERMISSION_DENIED'
  | 'NOTIFICATION_PERMISSION_DENIED'  // Android 13+ 알림 권한 없음
  | 'SYSTEM_RESTRICTED'
  | 'WEBVIEW_INIT_FAILED'
  | 'INVALID_INPUT'
  | 'INVALID_INTERVAL'
  | 'INVALID_TRIGGER'
  | 'NOTIFICATION_REQUIRED'
  | 'UNKNOWN';

태스크 데이터 API

작업별로 데이터를 저장/조회/삭제할 수 있습니다.

setTaskData

await bridge.call('setTaskData', {
  taskId: 'my-task',
  data: { lastSync: Date.now(), count: 5 }
});
// { success: true }

getTaskData

const result = await bridge.call('getTaskData', { taskId: 'my-task' });
// { success: true, data: { lastSync: 1234567890, count: 5 } }

removeTaskData

await bridge.call('removeTaskData', { taskId: 'my-task' });
// { success: true }

종료 콜백 (onTerminate)

백그라운드 서비스가 종료되기 직전에 실행되는 콜백입니다.

bridge.call('registerTask', {
  taskId: 'my-task',
  mode: 'persistent',
  onTerminate: async (event) => {
    // 종료 직전 상태 저장
    await bridge.call('setTaskData', {
      taskId: event.taskId,
      data: { terminatedAt: Date.now() }
    });
  },
  notification: { title: 'Task', body: 'Running...' }
});

주의:

  • 콜백 실행 시간은 약 5초로 제한됩니다
  • 프로세스가 즉시 kill되면 호출되지 않을 수 있습니다
  • 비정상 종료는 앱 재시작 시 terminated 이벤트로 감지됩니다

권한 설정

Android

AndroidManifest.xml에 자동 추가:

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />

Android 13 (API 33) 이상:

  • POST_NOTIFICATIONS 런타임 권한이 필요합니다.
  • 백그라운드 작업 시작 전 반드시 권한을 요청해야 합니다.
  • 권한이 없으면 startTask에서 NOTIFICATION_PERMISSION_DENIED 에러가 반환됩니다.
// 권한 체크 후 작업 시작 예시
async function startBackgroundTask() {
  // 1. 알림 권한 확인 (Android 13+)
  const notifPerm = await bridge.call('checkNotificationPermission');
  if (!notifPerm.granted) {
    const result = await bridge.call('requestNotificationPermission');
    if (!result.granted) {
      alert('백그라운드 실행을 위해 알림 권한이 필요합니다.');
      return;
    }
  }

  // 2. 배터리 최적화 예외 확인 (선택)
  const bgPerm = await bridge.call('checkBackgroundPermission');
  if (!bgPerm.batteryOptimizationExempt) {
    await bridge.call('requestBackgroundPermission');
  }

  // 3. 백그라운드 작업 시작
  const result = await bridge.call('startTask', { taskId: 'my-task' });
  if (!result.success) {
    console.error('시작 실패:', result.error);
  }
}

iOS

Info.plist에 추가:

<key>UIBackgroundModes</key>
<array>
  <string>fetch</string>
  <string>processing</string>
</array>

<key>BGTaskSchedulerPermittedIdentifiers</key>
<array>
  <string>$(PRODUCT_BUNDLE_IDENTIFIER).background</string>
</array>

라이선스

MIT

Keywords

react-native

FAQs

Package last updated on 04 Feb 2026

Related posts