rnww-plugin-wifi 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +841 -0
- package/lib/bridge/background-bridge.d.ts +22 -0
- package/lib/bridge/background-bridge.d.ts.map +1 -0
- package/lib/bridge/background-bridge.js +493 -0
- package/lib/bridge/index.d.ts +6 -0
- package/lib/bridge/index.d.ts.map +1 -0
- package/lib/bridge/index.js +23 -0
- package/lib/bridge/wifi-bridge.d.ts +16 -0
- package/lib/bridge/wifi-bridge.d.ts.map +1 -0
- package/lib/bridge/wifi-bridge.js +202 -0
- package/lib/modules/index.d.ts +41 -0
- package/lib/modules/index.d.ts.map +1 -0
- package/lib/modules/index.js +150 -0
- package/lib/types/background-module.d.ts +291 -0
- package/lib/types/background-module.d.ts.map +1 -0
- package/lib/types/background-module.js +5 -0
- package/lib/types/bridge.d.ts +22 -0
- package/lib/types/bridge.d.ts.map +1 -0
- package/lib/types/bridge.js +5 -0
- package/lib/types/index.d.ts +7 -0
- package/lib/types/index.d.ts.map +1 -0
- package/lib/types/index.js +5 -0
- package/lib/types/platform.d.ts +10 -0
- package/lib/types/platform.d.ts.map +1 -0
- package/lib/types/platform.js +2 -0
- package/lib/types/wifi-module.d.ts +146 -0
- package/lib/types/wifi-module.d.ts.map +1 -0
- package/lib/types/wifi-module.js +6 -0
- package/package.json +42 -0
- package/src/modules/android/build.gradle +64 -0
- package/src/modules/android/src/main/AndroidManifest.xml +28 -0
- package/src/modules/android/src/main/java/expo/modules/customwifi/WifiModule.kt +517 -0
- package/src/modules/android/src/main/java/expo/modules/customwifi/WifiStateReceiver.kt +46 -0
- package/src/modules/expo-module.config.json +9 -0
- package/src/modules/index.ts +166 -0
- package/src/modules/ios/WifiModule.swift +399 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Background 브릿지 핸들러
|
|
3
|
+
* 의존성 주입을 통해 동작하는 순수한 브릿지 로직
|
|
4
|
+
*/
|
|
5
|
+
import type { IBridge, IPlatform } from '../types';
|
|
6
|
+
/**
|
|
7
|
+
* Background 브릿지 설정
|
|
8
|
+
*/
|
|
9
|
+
export interface BackgroundBridgeConfig {
|
|
10
|
+
bridge: IBridge;
|
|
11
|
+
platform: IPlatform;
|
|
12
|
+
logger?: {
|
|
13
|
+
log: (...args: unknown[]) => void;
|
|
14
|
+
warn: (...args: unknown[]) => void;
|
|
15
|
+
error: (...args: unknown[]) => void;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Background 브릿지 핸들러를 등록합니다
|
|
20
|
+
*/
|
|
21
|
+
export declare const registerBackgroundHandlers: (config: BackgroundBridgeConfig) => void;
|
|
22
|
+
//# sourceMappingURL=background-bridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"background-bridge.d.ts","sourceRoot":"","sources":["../../src/bridge/background-bridge.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAenD;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,SAAS,CAAC;IACpB,MAAM,CAAC,EAAE;QACP,GAAG,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;QAClC,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;QACnC,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;KACrC,CAAC;CACH;AAkHD;;GAEG;AACH,eAAO,MAAM,0BAA0B,GAAI,QAAQ,sBAAsB,KAAG,IAmZ3E,CAAC"}
|
|
@@ -0,0 +1,493 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Background 브릿지 핸들러
|
|
4
|
+
* 의존성 주입을 통해 동작하는 순수한 브릿지 로직
|
|
5
|
+
*/
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
18
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
19
|
+
}) : function(o, v) {
|
|
20
|
+
o["default"] = v;
|
|
21
|
+
});
|
|
22
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
23
|
+
var ownKeys = function(o) {
|
|
24
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
25
|
+
var ar = [];
|
|
26
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
27
|
+
return ar;
|
|
28
|
+
};
|
|
29
|
+
return ownKeys(o);
|
|
30
|
+
};
|
|
31
|
+
return function (mod) {
|
|
32
|
+
if (mod && mod.__esModule) return mod;
|
|
33
|
+
var result = {};
|
|
34
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
35
|
+
__setModuleDefault(result, mod);
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
})();
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
exports.registerBackgroundHandlers = void 0;
|
|
41
|
+
const Background = __importStar(require("../modules"));
|
|
42
|
+
/**
|
|
43
|
+
* 액션 콜백 키 생성
|
|
44
|
+
*/
|
|
45
|
+
function actionCallbackKey(taskId, actionId) {
|
|
46
|
+
return `${taskId}:${actionId}`;
|
|
47
|
+
}
|
|
48
|
+
// ============================================================================
|
|
49
|
+
// Validation Helpers
|
|
50
|
+
// ============================================================================
|
|
51
|
+
/**
|
|
52
|
+
* taskId 유효성 검사
|
|
53
|
+
*/
|
|
54
|
+
function isValidTaskId(taskId) {
|
|
55
|
+
return typeof taskId === 'string' && taskId.trim().length > 0;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* BackgroundTask 기본 유효성 검사
|
|
59
|
+
*/
|
|
60
|
+
function isValidBackgroundTask(task) {
|
|
61
|
+
if (!task || typeof task !== 'object')
|
|
62
|
+
return false;
|
|
63
|
+
const t = task;
|
|
64
|
+
return (isValidTaskId(t.taskId) &&
|
|
65
|
+
(t.mode === 'persistent' || t.mode === 'efficient'));
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* NotificationConfig 유효성 검사
|
|
69
|
+
*/
|
|
70
|
+
function isValidNotificationConfig(config) {
|
|
71
|
+
if (!config || typeof config !== 'object')
|
|
72
|
+
return false;
|
|
73
|
+
const c = config;
|
|
74
|
+
return (typeof c.title === 'string' &&
|
|
75
|
+
typeof c.body === 'string');
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* hex color 유효성 검사
|
|
79
|
+
*/
|
|
80
|
+
function isValidHexColor(color) {
|
|
81
|
+
if (typeof color !== 'string')
|
|
82
|
+
return false;
|
|
83
|
+
return /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$/.test(color);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* NotificationConfig에서 콜백 함수 추출 및 정규화
|
|
87
|
+
*/
|
|
88
|
+
function extractAndSanitizeNotification(config, taskId, actionCallbackMap) {
|
|
89
|
+
const sanitized = { ...config };
|
|
90
|
+
// color 검증
|
|
91
|
+
if (sanitized.color && !isValidHexColor(sanitized.color)) {
|
|
92
|
+
delete sanitized.color;
|
|
93
|
+
}
|
|
94
|
+
// actions 처리
|
|
95
|
+
if (sanitized.actions && sanitized.actions.length > 0) {
|
|
96
|
+
// 최대 3개 제한
|
|
97
|
+
const limitedActions = sanitized.actions.slice(0, 3);
|
|
98
|
+
// 각 액션에서 onPress 콜백 추출 및 저장
|
|
99
|
+
sanitized.actions = limitedActions.map((action) => {
|
|
100
|
+
if (action.onPress && typeof action.onPress === 'function') {
|
|
101
|
+
// 콜백 저장
|
|
102
|
+
actionCallbackMap.set(actionCallbackKey(taskId, action.id), action.onPress);
|
|
103
|
+
}
|
|
104
|
+
// 네이티브에 전달할 때는 onPress 제외
|
|
105
|
+
const { onPress, ...actionWithoutCallback } = action;
|
|
106
|
+
return actionWithoutCallback;
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
// progress 값 검증
|
|
110
|
+
if (sanitized.progress) {
|
|
111
|
+
sanitized.progress = {
|
|
112
|
+
...sanitized.progress,
|
|
113
|
+
current: Math.max(0, sanitized.progress.current),
|
|
114
|
+
max: Math.max(1, sanitized.progress.max),
|
|
115
|
+
};
|
|
116
|
+
if (sanitized.progress.current > sanitized.progress.max) {
|
|
117
|
+
sanitized.progress.current = sanitized.progress.max;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return sanitized;
|
|
121
|
+
}
|
|
122
|
+
// ============================================================================
|
|
123
|
+
// Main Handler
|
|
124
|
+
// ============================================================================
|
|
125
|
+
/** 중복 등록 방지 플래그 */
|
|
126
|
+
let isRegistered = false;
|
|
127
|
+
/**
|
|
128
|
+
* Background 브릿지 핸들러를 등록합니다
|
|
129
|
+
*/
|
|
130
|
+
const registerBackgroundHandlers = (config) => {
|
|
131
|
+
const { bridge, platform, logger = console } = config;
|
|
132
|
+
// 플랫폼 체크
|
|
133
|
+
if (platform.OS !== 'android' && platform.OS !== 'ios') {
|
|
134
|
+
logger.log('[Bridge] Background handlers skipped (Android/iOS only)');
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
// 중복 등록 방지
|
|
138
|
+
if (isRegistered) {
|
|
139
|
+
logger.warn('[Bridge] Background handlers already registered, skipping');
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
isRegistered = true;
|
|
143
|
+
// 이벤트 리스너 구독 객체
|
|
144
|
+
let eventSubscription = null;
|
|
145
|
+
// 작업별 콜백 ID 매핑 (taskId → callbackId)
|
|
146
|
+
const callbackIdMap = new Map();
|
|
147
|
+
// 작업 콜백 함수 저장소 (taskId → callback)
|
|
148
|
+
const taskCallbackMap = new Map();
|
|
149
|
+
// 액션 콜백 함수 저장소 (taskId:actionId → callback)
|
|
150
|
+
const actionCallbackMap = new Map();
|
|
151
|
+
/**
|
|
152
|
+
* 이벤트 핸들러 - 콜백 실행 및 Web 전달
|
|
153
|
+
*/
|
|
154
|
+
const handleTaskEvent = (event) => {
|
|
155
|
+
// 이벤트 검증
|
|
156
|
+
if (!event || !isValidTaskId(event.taskId)) {
|
|
157
|
+
logger.warn('[Bridge] Invalid task event received:', event);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
// callbackId 추가
|
|
161
|
+
const enrichedEvent = {
|
|
162
|
+
...event,
|
|
163
|
+
callbackId: callbackIdMap.get(event.taskId),
|
|
164
|
+
};
|
|
165
|
+
// 액션 이벤트인 경우 액션 콜백 우선 실행
|
|
166
|
+
if (event.type === 'action' && event.actionId) {
|
|
167
|
+
const actionCallback = actionCallbackMap.get(actionCallbackKey(event.taskId, event.actionId));
|
|
168
|
+
if (actionCallback) {
|
|
169
|
+
Promise.resolve()
|
|
170
|
+
.then(() => actionCallback(event.actionId, event.taskId))
|
|
171
|
+
.catch((error) => {
|
|
172
|
+
logger.error('[Bridge] Action callback error:', error);
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
// Web으로 이벤트 전달 (non-blocking)
|
|
177
|
+
try {
|
|
178
|
+
bridge.sendToWeb('onTaskEvent', enrichedEvent);
|
|
179
|
+
}
|
|
180
|
+
catch (error) {
|
|
181
|
+
logger.error('[Bridge] Failed to send event to web:', error);
|
|
182
|
+
}
|
|
183
|
+
// 작업 콜백 실행 (비동기, non-blocking)
|
|
184
|
+
const taskCallback = taskCallbackMap.get(event.taskId);
|
|
185
|
+
if (taskCallback) {
|
|
186
|
+
Promise.resolve()
|
|
187
|
+
.then(() => taskCallback(enrichedEvent))
|
|
188
|
+
.catch((error) => {
|
|
189
|
+
logger.error('[Bridge] Task callback error:', error);
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
/**
|
|
194
|
+
* 이벤트 리스너 초기화
|
|
195
|
+
*/
|
|
196
|
+
const ensureEventListener = () => {
|
|
197
|
+
if (!eventSubscription) {
|
|
198
|
+
eventSubscription = Background.addTaskEventListener(handleTaskEvent);
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
/**
|
|
202
|
+
* 특정 작업의 액션 콜백 정리
|
|
203
|
+
*/
|
|
204
|
+
const clearActionCallbacks = (taskId) => {
|
|
205
|
+
const keysToDelete = [];
|
|
206
|
+
actionCallbackMap.forEach((_, key) => {
|
|
207
|
+
if (key.startsWith(`${taskId}:`)) {
|
|
208
|
+
keysToDelete.push(key);
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
keysToDelete.forEach((key) => actionCallbackMap.delete(key));
|
|
212
|
+
};
|
|
213
|
+
// ============================================================================
|
|
214
|
+
// Handler Registration
|
|
215
|
+
// ============================================================================
|
|
216
|
+
// 작업 등록
|
|
217
|
+
bridge.registerHandler('registerTask', async (payload, respond) => {
|
|
218
|
+
try {
|
|
219
|
+
// 입력 검증
|
|
220
|
+
if (!isValidBackgroundTask(payload)) {
|
|
221
|
+
respond({
|
|
222
|
+
success: false,
|
|
223
|
+
error: 'INVALID_INPUT',
|
|
224
|
+
message: 'Invalid task configuration: taskId and mode are required',
|
|
225
|
+
});
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
const task = payload;
|
|
229
|
+
const { callback, notification, ...taskConfig } = task;
|
|
230
|
+
// notification 정규화 및 액션 콜백 추출
|
|
231
|
+
const sanitizedNotification = notification
|
|
232
|
+
? extractAndSanitizeNotification(notification, task.taskId, actionCallbackMap)
|
|
233
|
+
: undefined;
|
|
234
|
+
const sanitizedTask = {
|
|
235
|
+
...taskConfig,
|
|
236
|
+
...(sanitizedNotification && { notification: sanitizedNotification }),
|
|
237
|
+
};
|
|
238
|
+
// 네이티브 모듈에 등록
|
|
239
|
+
const result = await Background.registerTask(sanitizedTask);
|
|
240
|
+
// 등록 성공 시에만 콜백 저장
|
|
241
|
+
if (result.success) {
|
|
242
|
+
if (task.callbackId) {
|
|
243
|
+
callbackIdMap.set(task.taskId, task.callbackId);
|
|
244
|
+
}
|
|
245
|
+
if (callback && typeof callback === 'function') {
|
|
246
|
+
taskCallbackMap.set(task.taskId, callback);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
// 실패 시 저장된 액션 콜백 정리
|
|
251
|
+
clearActionCallbacks(task.taskId);
|
|
252
|
+
}
|
|
253
|
+
respond(result);
|
|
254
|
+
}
|
|
255
|
+
catch (error) {
|
|
256
|
+
logger.error('[Bridge] registerTask error:', error);
|
|
257
|
+
respond({
|
|
258
|
+
success: false,
|
|
259
|
+
error: 'UNKNOWN',
|
|
260
|
+
message: error instanceof Error ? error.message : 'Failed to register task',
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
// 작업 해제
|
|
265
|
+
bridge.registerHandler('unregisterTask', async (payload, respond) => {
|
|
266
|
+
try {
|
|
267
|
+
const data = payload;
|
|
268
|
+
const taskId = data?.taskId;
|
|
269
|
+
// 입력 검증
|
|
270
|
+
if (!isValidTaskId(taskId)) {
|
|
271
|
+
respond({
|
|
272
|
+
success: false,
|
|
273
|
+
error: 'INVALID_INPUT',
|
|
274
|
+
message: 'Invalid taskId',
|
|
275
|
+
});
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
// 모든 콜백 정리
|
|
279
|
+
callbackIdMap.delete(taskId);
|
|
280
|
+
taskCallbackMap.delete(taskId);
|
|
281
|
+
clearActionCallbacks(taskId);
|
|
282
|
+
const result = await Background.unregisterTask(taskId);
|
|
283
|
+
respond(result);
|
|
284
|
+
}
|
|
285
|
+
catch (error) {
|
|
286
|
+
logger.error('[Bridge] unregisterTask error:', error);
|
|
287
|
+
respond({
|
|
288
|
+
success: false,
|
|
289
|
+
error: 'UNKNOWN',
|
|
290
|
+
message: error instanceof Error ? error.message : 'Failed to unregister task',
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
// 작업 시작
|
|
295
|
+
bridge.registerHandler('startTask', async (payload, respond) => {
|
|
296
|
+
try {
|
|
297
|
+
const data = payload;
|
|
298
|
+
const taskId = data?.taskId;
|
|
299
|
+
// 입력 검증
|
|
300
|
+
if (!isValidTaskId(taskId)) {
|
|
301
|
+
respond({
|
|
302
|
+
success: false,
|
|
303
|
+
error: 'INVALID_INPUT',
|
|
304
|
+
message: 'Invalid taskId',
|
|
305
|
+
});
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
ensureEventListener();
|
|
309
|
+
const result = await Background.startTask(taskId);
|
|
310
|
+
respond(result);
|
|
311
|
+
}
|
|
312
|
+
catch (error) {
|
|
313
|
+
logger.error('[Bridge] startTask error:', error);
|
|
314
|
+
respond({
|
|
315
|
+
success: false,
|
|
316
|
+
error: 'UNKNOWN',
|
|
317
|
+
message: error instanceof Error ? error.message : 'Failed to start task',
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
// 작업 중지
|
|
322
|
+
bridge.registerHandler('stopTask', async (payload, respond) => {
|
|
323
|
+
try {
|
|
324
|
+
const data = payload;
|
|
325
|
+
const taskId = data?.taskId;
|
|
326
|
+
// 입력 검증
|
|
327
|
+
if (!isValidTaskId(taskId)) {
|
|
328
|
+
respond({
|
|
329
|
+
success: false,
|
|
330
|
+
error: 'INVALID_INPUT',
|
|
331
|
+
message: 'Invalid taskId',
|
|
332
|
+
});
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
const result = await Background.stopTask(taskId);
|
|
336
|
+
respond(result);
|
|
337
|
+
}
|
|
338
|
+
catch (error) {
|
|
339
|
+
logger.error('[Bridge] stopTask error:', error);
|
|
340
|
+
respond({
|
|
341
|
+
success: false,
|
|
342
|
+
error: 'UNKNOWN',
|
|
343
|
+
message: error instanceof Error ? error.message : 'Failed to stop task',
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
// 모든 작업 중지
|
|
348
|
+
bridge.registerHandler('stopAllTasks', async (_payload, respond) => {
|
|
349
|
+
try {
|
|
350
|
+
const result = await Background.stopAllTasks();
|
|
351
|
+
// 이벤트 리스너 해제
|
|
352
|
+
if (eventSubscription) {
|
|
353
|
+
eventSubscription.remove();
|
|
354
|
+
eventSubscription = null;
|
|
355
|
+
}
|
|
356
|
+
// 모든 콜백 정리
|
|
357
|
+
callbackIdMap.clear();
|
|
358
|
+
taskCallbackMap.clear();
|
|
359
|
+
actionCallbackMap.clear();
|
|
360
|
+
respond(result);
|
|
361
|
+
}
|
|
362
|
+
catch (error) {
|
|
363
|
+
logger.error('[Bridge] stopAllTasks error:', error);
|
|
364
|
+
respond({
|
|
365
|
+
success: false,
|
|
366
|
+
error: 'UNKNOWN',
|
|
367
|
+
message: error instanceof Error ? error.message : 'Failed to stop all tasks',
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
});
|
|
371
|
+
// 알림 업데이트 (액션 콜백 지원)
|
|
372
|
+
bridge.registerHandler('updateNotification', async (payload, respond) => {
|
|
373
|
+
try {
|
|
374
|
+
// 입력 검증
|
|
375
|
+
if (!isValidNotificationConfig(payload)) {
|
|
376
|
+
respond({
|
|
377
|
+
success: false,
|
|
378
|
+
error: 'Invalid notification config: title and body are required',
|
|
379
|
+
});
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
const config = payload;
|
|
383
|
+
const taskId = config.taskId || 'default';
|
|
384
|
+
// 기존 액션 콜백 정리 후 새로 등록
|
|
385
|
+
if (config.actions) {
|
|
386
|
+
clearActionCallbacks(taskId);
|
|
387
|
+
}
|
|
388
|
+
const sanitizedConfig = extractAndSanitizeNotification(config, taskId, actionCallbackMap);
|
|
389
|
+
const result = await Background.updateNotification(sanitizedConfig);
|
|
390
|
+
respond(result);
|
|
391
|
+
}
|
|
392
|
+
catch (error) {
|
|
393
|
+
logger.error('[Bridge] updateNotification error:', error);
|
|
394
|
+
respond({
|
|
395
|
+
success: false,
|
|
396
|
+
error: error instanceof Error ? error.message : 'Failed to update notification',
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
});
|
|
400
|
+
// 특정 작업 상태 조회
|
|
401
|
+
bridge.registerHandler('getTaskStatus', async (payload, respond) => {
|
|
402
|
+
try {
|
|
403
|
+
const data = payload;
|
|
404
|
+
const taskId = data?.taskId;
|
|
405
|
+
// 입력 검증
|
|
406
|
+
if (!isValidTaskId(taskId)) {
|
|
407
|
+
respond({
|
|
408
|
+
success: false,
|
|
409
|
+
error: 'Invalid taskId',
|
|
410
|
+
});
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
const status = await Background.getTaskStatus(taskId);
|
|
414
|
+
respond({ success: true, status });
|
|
415
|
+
}
|
|
416
|
+
catch (error) {
|
|
417
|
+
logger.error('[Bridge] getTaskStatus error:', error);
|
|
418
|
+
respond({
|
|
419
|
+
success: false,
|
|
420
|
+
error: error instanceof Error ? error.message : 'Failed to get task status',
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
});
|
|
424
|
+
// 전체 작업 상태 조회
|
|
425
|
+
bridge.registerHandler('getAllTasksStatus', async (_payload, respond) => {
|
|
426
|
+
try {
|
|
427
|
+
const status = await Background.getAllTasksStatus();
|
|
428
|
+
respond({ success: true, ...status });
|
|
429
|
+
}
|
|
430
|
+
catch (error) {
|
|
431
|
+
logger.error('[Bridge] getAllTasksStatus error:', error);
|
|
432
|
+
respond({
|
|
433
|
+
success: false,
|
|
434
|
+
error: error instanceof Error ? error.message : 'Failed to get all tasks status',
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
});
|
|
438
|
+
// 권한 확인
|
|
439
|
+
bridge.registerHandler('checkBackgroundPermission', async (_payload, respond) => {
|
|
440
|
+
try {
|
|
441
|
+
const status = await Background.checkBackgroundPermission();
|
|
442
|
+
respond({ success: true, ...status });
|
|
443
|
+
}
|
|
444
|
+
catch (error) {
|
|
445
|
+
logger.error('[Bridge] checkBackgroundPermission error:', error);
|
|
446
|
+
respond({
|
|
447
|
+
success: false,
|
|
448
|
+
error: error instanceof Error ? error.message : 'Failed to check permission',
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
});
|
|
452
|
+
// 권한 요청
|
|
453
|
+
bridge.registerHandler('requestBackgroundPermission', async (_payload, respond) => {
|
|
454
|
+
try {
|
|
455
|
+
const status = await Background.requestBackgroundPermission();
|
|
456
|
+
respond({ success: true, ...status });
|
|
457
|
+
}
|
|
458
|
+
catch (error) {
|
|
459
|
+
logger.error('[Bridge] requestBackgroundPermission error:', error);
|
|
460
|
+
respond({
|
|
461
|
+
success: false,
|
|
462
|
+
error: error instanceof Error ? error.message : 'Failed to request permission',
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
});
|
|
466
|
+
// 리소스 정리 (dispose)
|
|
467
|
+
bridge.registerHandler('disposeBackgroundHandlers', async (_payload, respond) => {
|
|
468
|
+
try {
|
|
469
|
+
// 이벤트 리스너 해제
|
|
470
|
+
if (eventSubscription) {
|
|
471
|
+
eventSubscription.remove();
|
|
472
|
+
eventSubscription = null;
|
|
473
|
+
}
|
|
474
|
+
// 모든 콜백 정리
|
|
475
|
+
callbackIdMap.clear();
|
|
476
|
+
taskCallbackMap.clear();
|
|
477
|
+
actionCallbackMap.clear();
|
|
478
|
+
// 재등록 가능하도록 플래그 리셋
|
|
479
|
+
isRegistered = false;
|
|
480
|
+
logger.log('[Bridge] Background handlers disposed');
|
|
481
|
+
respond({ success: true });
|
|
482
|
+
}
|
|
483
|
+
catch (error) {
|
|
484
|
+
logger.error('[Bridge] disposeBackgroundHandlers error:', error);
|
|
485
|
+
respond({
|
|
486
|
+
success: false,
|
|
487
|
+
error: error instanceof Error ? error.message : 'Failed to dispose handlers',
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
});
|
|
491
|
+
logger.log('[Bridge] Background handlers registered');
|
|
492
|
+
};
|
|
493
|
+
exports.registerBackgroundHandlers = registerBackgroundHandlers;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/bridge/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAErD,cAAc,UAAU,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* WiFi Bridge Main Entry Point
|
|
4
|
+
*/
|
|
5
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
+
}
|
|
11
|
+
Object.defineProperty(o, k2, desc);
|
|
12
|
+
}) : (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
o[k2] = m[k];
|
|
15
|
+
}));
|
|
16
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
17
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
18
|
+
};
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.registerWifiHandlers = void 0;
|
|
21
|
+
var wifi_bridge_1 = require("./wifi-bridge");
|
|
22
|
+
Object.defineProperty(exports, "registerWifiHandlers", { enumerable: true, get: function () { return wifi_bridge_1.registerWifiHandlers; } });
|
|
23
|
+
__exportStar(require("../types"), exports);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WiFi Bridge Handlers
|
|
3
|
+
* WebView에서 호출 가능한 WiFi 관련 핸들러 등록
|
|
4
|
+
*/
|
|
5
|
+
import type { IBridge, IPlatform } from '../types';
|
|
6
|
+
interface WifiBridgeConfig {
|
|
7
|
+
bridge: IBridge;
|
|
8
|
+
platform: IPlatform;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* WiFi 브릿지 핸들러 등록
|
|
12
|
+
* @param config 브릿지 설정 (bridge 인스턴스, platform 정보)
|
|
13
|
+
*/
|
|
14
|
+
export declare function registerWifiHandlers(config: WifiBridgeConfig): void;
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=wifi-bridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wifi-bridge.d.ts","sourceRoot":"","sources":["../../src/bridge/wifi-bridge.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAoC,MAAM,UAAU,CAAC;AAGrF,UAAU,gBAAgB;IACxB,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAuKnE"}
|