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.7.0
Version published
Weekly downloads
1
-98.18%
Maintainers
1
Weekly downloads
 
Created
Source

RNWW Plugin Background

React Native WebView 백그라운드 실행 플러그인 (Expo Native Module)

앱 라이프사이클 이벤트 발생 시 메인 WebView에서 JavaScript 콜백을 실행합니다. appBridge 등 앱의 전역 객체에 접근할 수 있습니다.

설치

npm install rnww-plugin-background

빠른 시작

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

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

// 외부 변수 사용 가능
const API_URL = 'https://api.example.com';

// 태스크 등록
await bridge.call('registerTask', {
  taskId: 'my-task',
  triggers: ['app_foreground', 'app_background'],
  callback: (trigger, data) => {
    // 메인 WebView 컨텍스트에서 실행됨
    // appBridge, 전역 변수 등 모두 접근 가능!
    fetch(API_URL + '/sync', {
      method: 'POST',
      body: JSON.stringify({ event: trigger })
    });

    appBridge.call('api:sync', { event: trigger });
  },
  notification: {
    title: '백그라운드 실행 중',
    body: '서비스가 실행 중입니다'
  }
});

// 태스크 시작
await bridge.call('startTask', { taskId: 'my-task' });

핵심 개념

이 플러그인은 Headless WebView를 사용하여 앱 종료 후에도 JavaScript 콜백을 실행합니다.

  • 앱 실행 중: Headless WebView가 Foreground Service 내에서 동작
  • 앱 종료 후: Activity가 종료되어도 Headless WebView가 독립적으로 유지
  • 앱 재시작 시: 기존 Headless WebView와 자동 재연결

트리거 종류

  • 기본 트리거 (init, terminate): 항상 자동 호출됨
  • 라이프사이클 트리거 (app_foreground, app_background): triggers 배열에 포함 시에만 호출
bridge.call('registerTask', {
  taskId: 'my-task',
  triggers: ['app_foreground', 'app_background'],
  callback: (trigger, data) => {
    switch (trigger) {
      case 'init':
        console.log('Task initialized');
        break;
      case 'terminate':
        console.log('Task terminating');
        break;
      case 'app_background':
        saveCurrentState();
        break;
      case 'app_foreground':
        syncData();
        break;
    }
  },
  notification: {
    title: '백그라운드 실행 중',
    body: '서비스가 실행 중입니다'
  }
});

Bridge Handlers

registerTask

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

const result = await bridge.call('registerTask', {
  taskId: string;           // 필수: 작업 고유 ID
  triggers?: TriggerType[]; // 라이프사이클 트리거 ['app_foreground', 'app_background']
  callback?: BackgroundCallback;  // WebView에서 실행될 콜백
  notification?: NotificationConfig; // Android 필수
});

// 결과
// { success: true, taskId: 'my-task' }
// { success: false, error: 'TASK_ALREADY_EXISTS' }

unregisterTask

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

const result = await bridge.call('unregisterTask', { taskId: 'my-task' });

startTask

작업을 시작합니다. WebView가 자동으로 감지되어 연결됩니다.

const result = await bridge.call('startTask', { taskId: 'my-task' });
// { success: true, taskId: 'my-task' }
// { success: false, error: 'NOTIFICATION_PERMISSION_DENIED' }
// { success: false, error: 'WEBVIEW_NOT_FOUND' }

stopTask

작업을 중지합니다.

const result = await bridge.call('stopTask', { taskId: 'my-task' });

stopAllTasks

모든 작업을 중지합니다.

const result = await bridge.call('stopAllTasks');

updateNotification

실행 중인 알림 내용을 업데이트합니다. (Android only)

const result = await bridge.call('updateNotification', {
  taskId: 'my-task',
  title: '동기화 중',
  body: '작업 진행 중...',
  silent: true
});

getTaskStatus / getAllTasksStatus

작업 상태를 조회합니다.

const result = await bridge.call('getTaskStatus', { taskId: 'my-task' });
const allResult = await bridge.call('getAllTasksStatus');

권한 관련

// 백그라운드 권한 확인/요청
await bridge.call('checkBackgroundPermission');
await bridge.call('requestBackgroundPermission');

// 알림 권한 확인/요청 (Android 13+)
await bridge.call('checkNotificationPermission');
await bridge.call('requestNotificationPermission');

태스크 데이터

// 저장
await bridge.call('setTaskData', {
  taskId: 'my-task',
  data: { lastSync: Date.now() }
});

// 조회
const result = await bridge.call('getTaskData', { taskId: 'my-task' });

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

evaluateInMainWebView

메인 WebView에서 JavaScript를 직접 실행합니다.

const result = await bridge.call('evaluateInMainWebView', {
  script: 'window.myApp.getState()'
});

트리거 시스템

기본 트리거 (자동 호출)

트리거호출 시점설명
init태스크 시작 직후초기화 로직 실행
terminate태스크 종료 직전상태 저장, 리소스 정리

라이프사이클 트리거 (선택적)

triggers 배열에 명시적으로 포함해야 호출됩니다.

트리거호출 시점설명
app_foreground앱이 포그라운드로 전환데이터 동기화, UI 갱신
app_background앱이 백그라운드로 전환상태 저장, 네트워크 요청

콜백 시스템

callback (WebView 콜백)

메인 WebView에서 실행됩니다. 백그라운드에서도 동작합니다. 외부 변수와 앱 전역 객체에 접근할 수 있습니다.

const API_URL = 'https://api.example.com';

callback: (trigger, data) => {
  switch (trigger) {
    case 'init':
      // 초기화
      window.__taskStartedAt = Date.now();
      break;

    case 'terminate':
      // 종료 직전 정리
      fetch(API_URL + '/final', {
        method: 'POST',
        body: JSON.stringify({ duration: Date.now() - window.__taskStartedAt })
      });
      break;

    case 'app_background':
      // 앱이 백그라운드로 전환
      appBridge.call('saveState', { timestamp: data.timestamp });
      break;

    case 'app_foreground':
      // 앱이 포그라운드로 복귀
      appBridge.call('syncData');
      break;
  }
}

알림 설정 (Android)

interface NotificationConfig {
  title: string;
  body: string;
  icon?: string;            // drawable 리소스명
  color?: string;           // '#4CAF50'
  priority?: 'min' | 'low' | 'default' | 'high' | 'max';
  ongoing?: boolean;        // 기본값: true
  silent?: boolean;         // 기본값: false
  channelId?: string;
  channelName?: string;
  channelDescription?: string;
}

에러 타입

type BackgroundError =
  | 'TASK_NOT_FOUND'
  | 'TASK_ALREADY_EXISTS'
  | 'TASK_ALREADY_RUNNING'
  | 'NOTIFICATION_PERMISSION_DENIED'
  | 'WEBVIEW_NOT_FOUND'
  | 'INVALID_INPUT'
  | 'UNKNOWN';

플랫폼별 설정

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 런타임 권한 필수

iOS

Info.plist에 추가:

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

<key>BGTaskSchedulerPermittedIdentifiers</key>
<array>
  <string>expo.modules.custombackground.refresh</string>
</array>

고급: Headless WebView

아키텍처

┌─────────────────────────────────────────────────────────────┐
│ 앱 실행 중                                                   │
│                                                             │
│  Main WebView ←→ Bridge ←→ React Native                     │
│                                  ↓                          │
│                         BackgroundService                   │
│                                  ↓                          │
│                       Headless WebView (독립)                │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│ 앱 종료 후                                                   │
│                                                             │
│  BackgroundService (Foreground Service로 유지)               │
│                 ↓                                           │
│       Headless WebView (독립적으로 JavaScript 실행)           │
│                 ↓                                           │
│       backgr:* 핸들러 → Native에서 직접 처리                  │
└─────────────────────────────────────────────────────────────┘

Headless WebView API

import {
  setBridgeScript,
  isHeadlessActive,
  sendToHeadless,
  connectHeadlessToBridge
} from 'rnww-plugin-background';

// 1. Bridge 스크립트 설정 (앱 초기화 시)
await setBridgeScript(bridgeClientScript);

// 2. Headless WebView 상태 확인
const active = await isHeadlessActive();

// 3. Headless WebView로 메시지 전송
await sendToHeadless('customAction', { data: 'value' });

// 4. RN Template BridgeExtension 연동
connectHeadlessToBridge(BridgeExtension);

메시지 라우팅

Headless WebView에서 postMessage로 전송한 메시지는 다음과 같이 처리됩니다:

핸들러 패턴처리 방식설명
backgr:*Native 직접 처리RN 없이도 동작 (앱 종료 후)
기타React Native 전달onHeadlessMessage 이벤트

수동 WebView 연결 (레거시)

여러 WebView가 있는 경우 특정 WebView를 지정할 수 있습니다:

// React Native 컴포넌트
<WebView
  nativeID="123"
  source={{ uri: 'https://...' }}
/>
// 특정 WebView 연결
await bridge.call('attachWebView', { viewTag: 123 });

// 연결 해제
await bridge.call('detachWebView');

라이선스

MIT

Keywords

react-native

FAQs

Package last updated on 05 Feb 2026

Related posts