@rn-bridge-tools/expo 0.0.1
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/dist/index.cjs +741 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +113 -0
- package/dist/index.d.ts +113 -0
- package/dist/index.js +696 -0
- package/dist/index.js.map +1 -0
- package/package.json +108 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,696 @@
|
|
|
1
|
+
// src/WebViewBridge.tsx
|
|
2
|
+
import { forwardRef, useImperativeHandle, useMemo, useRef } from "react";
|
|
3
|
+
import { bridge, createWebView } from "@webview-bridge/react-native";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
var WebViewBridge = forwardRef(
|
|
6
|
+
function WebViewBridge2({ handlers, customHandlers, ...webViewProps }, ref) {
|
|
7
|
+
const handlersRef = useRef(handlers);
|
|
8
|
+
const customRef = useRef(customHandlers);
|
|
9
|
+
const { InternalWebView, postMessage } = useMemo(() => {
|
|
10
|
+
const allHandlers = {};
|
|
11
|
+
const mergedHandlers = { ...handlersRef.current, ...customRef.current };
|
|
12
|
+
for (const [key, handler] of Object.entries(mergedHandlers)) {
|
|
13
|
+
if (handler) {
|
|
14
|
+
allHandlers[key] = async (...args) => {
|
|
15
|
+
const payload = args[0] ?? {};
|
|
16
|
+
return handler(payload);
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const appBridge = bridge(allHandlers);
|
|
21
|
+
const result = createWebView({
|
|
22
|
+
bridge: appBridge,
|
|
23
|
+
debug: __DEV__ ?? false
|
|
24
|
+
});
|
|
25
|
+
return { InternalWebView: result.WebView, postMessage: result.postMessage };
|
|
26
|
+
}, []);
|
|
27
|
+
useImperativeHandle(
|
|
28
|
+
ref,
|
|
29
|
+
() => ({
|
|
30
|
+
emit: (event, data) => {
|
|
31
|
+
postMessage(event, data);
|
|
32
|
+
}
|
|
33
|
+
}),
|
|
34
|
+
[postMessage]
|
|
35
|
+
);
|
|
36
|
+
return /* @__PURE__ */ jsx(InternalWebView, { ...webViewProps });
|
|
37
|
+
}
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
// src/handlers/camera.ts
|
|
41
|
+
import { moduleNotInstalledError, tryImport } from "@rn-bridge-tools/core";
|
|
42
|
+
var cameraHandlers = {
|
|
43
|
+
"camera.take": async (payload) => {
|
|
44
|
+
const ImagePicker = await tryImport("expo-image-picker");
|
|
45
|
+
if (!ImagePicker) return moduleNotInstalledError("expo-image-picker");
|
|
46
|
+
const result = await ImagePicker.launchCameraAsync({
|
|
47
|
+
quality: payload.quality ?? 0.8,
|
|
48
|
+
cameraType: payload.facing === "front" ? ImagePicker.CameraType.front : ImagePicker.CameraType.back,
|
|
49
|
+
allowsEditing: payload.allowsEditing ?? false
|
|
50
|
+
});
|
|
51
|
+
if (result.canceled) {
|
|
52
|
+
return { success: false, assets: [] };
|
|
53
|
+
}
|
|
54
|
+
const asset = result.assets[0];
|
|
55
|
+
return {
|
|
56
|
+
success: true,
|
|
57
|
+
uri: asset.uri,
|
|
58
|
+
width: asset.width,
|
|
59
|
+
height: asset.height,
|
|
60
|
+
fileSize: asset.fileSize,
|
|
61
|
+
mimeType: asset.mimeType ?? void 0
|
|
62
|
+
};
|
|
63
|
+
},
|
|
64
|
+
"camera.pickImage": async (payload) => {
|
|
65
|
+
const ImagePicker = await tryImport("expo-image-picker");
|
|
66
|
+
if (!ImagePicker) return moduleNotInstalledError("expo-image-picker");
|
|
67
|
+
const result = await ImagePicker.launchImageLibraryAsync({
|
|
68
|
+
allowsMultipleSelection: payload.allowsMultipleSelection ?? false,
|
|
69
|
+
quality: payload.quality ?? 0.8,
|
|
70
|
+
selectionLimit: payload.maxCount ?? 0
|
|
71
|
+
});
|
|
72
|
+
if (result.canceled) {
|
|
73
|
+
return { success: false, assets: [] };
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
success: true,
|
|
77
|
+
assets: result.assets.map((a) => ({
|
|
78
|
+
uri: a.uri,
|
|
79
|
+
width: a.width,
|
|
80
|
+
height: a.height,
|
|
81
|
+
fileSize: a.fileSize,
|
|
82
|
+
mimeType: a.mimeType ?? void 0
|
|
83
|
+
}))
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// src/handlers/location.ts
|
|
89
|
+
import { moduleNotInstalledError as moduleNotInstalledError2, tryImport as tryImport2 } from "@rn-bridge-tools/core";
|
|
90
|
+
var watchSubscriptions = /* @__PURE__ */ new Map();
|
|
91
|
+
var watchCounter = 0;
|
|
92
|
+
var locationHandlers = {
|
|
93
|
+
"location.getCurrent": async (payload) => {
|
|
94
|
+
const Location = await tryImport2("expo-location");
|
|
95
|
+
if (!Location) return moduleNotInstalledError2("expo-location");
|
|
96
|
+
const accuracyMap = {
|
|
97
|
+
lowest: Location.Accuracy.Lowest,
|
|
98
|
+
low: Location.Accuracy.Low,
|
|
99
|
+
balanced: Location.Accuracy.Balanced,
|
|
100
|
+
high: Location.Accuracy.High,
|
|
101
|
+
highest: Location.Accuracy.Highest
|
|
102
|
+
};
|
|
103
|
+
const result = await Location.getCurrentPositionAsync({
|
|
104
|
+
accuracy: accuracyMap[payload.accuracy ?? "balanced"] ?? Location.Accuracy.Balanced
|
|
105
|
+
});
|
|
106
|
+
return {
|
|
107
|
+
lat: result.coords.latitude,
|
|
108
|
+
lng: result.coords.longitude,
|
|
109
|
+
altitude: result.coords.altitude ?? void 0,
|
|
110
|
+
accuracy: result.coords.accuracy ?? void 0,
|
|
111
|
+
timestamp: result.timestamp
|
|
112
|
+
};
|
|
113
|
+
},
|
|
114
|
+
"location.watchStart": async (payload) => {
|
|
115
|
+
const Location = await tryImport2("expo-location");
|
|
116
|
+
if (!Location) return moduleNotInstalledError2("expo-location");
|
|
117
|
+
watchCounter += 1;
|
|
118
|
+
const watchId = `watch_${watchCounter}`;
|
|
119
|
+
const accuracyMap = {
|
|
120
|
+
low: Location.Accuracy.Low,
|
|
121
|
+
balanced: Location.Accuracy.Balanced,
|
|
122
|
+
high: Location.Accuracy.High
|
|
123
|
+
};
|
|
124
|
+
const subscription = await Location.watchPositionAsync(
|
|
125
|
+
{
|
|
126
|
+
accuracy: accuracyMap[payload.accuracy ?? "balanced"] ?? Location.Accuracy.Balanced,
|
|
127
|
+
distanceInterval: payload.distanceInterval,
|
|
128
|
+
timeInterval: payload.timeInterval
|
|
129
|
+
},
|
|
130
|
+
(_location) => {
|
|
131
|
+
}
|
|
132
|
+
);
|
|
133
|
+
watchSubscriptions.set(watchId, subscription);
|
|
134
|
+
return { watchId };
|
|
135
|
+
},
|
|
136
|
+
"location.watchStop": async (payload) => {
|
|
137
|
+
const subscription = watchSubscriptions.get(payload.watchId);
|
|
138
|
+
if (subscription) {
|
|
139
|
+
subscription.remove();
|
|
140
|
+
watchSubscriptions.delete(payload.watchId);
|
|
141
|
+
return { success: true };
|
|
142
|
+
}
|
|
143
|
+
return { success: false };
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
// src/handlers/file.ts
|
|
148
|
+
import { moduleNotInstalledError as moduleNotInstalledError3, tryImport as tryImport3 } from "@rn-bridge-tools/core";
|
|
149
|
+
var fileHandlers = {
|
|
150
|
+
"file.download": async (payload) => {
|
|
151
|
+
const FS = await tryImport3("expo-file-system");
|
|
152
|
+
if (!FS) return moduleNotInstalledError3("expo-file-system");
|
|
153
|
+
try {
|
|
154
|
+
const response = await fetch(payload.url);
|
|
155
|
+
const text = await response.text();
|
|
156
|
+
const file = new FS.File(FS.Paths.document, payload.filename);
|
|
157
|
+
file.write(text);
|
|
158
|
+
return { success: true, localUri: file.uri };
|
|
159
|
+
} catch (err) {
|
|
160
|
+
return { success: false, error: String(err) };
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
"file.read": async (payload) => {
|
|
164
|
+
const FS = await tryImport3("expo-file-system");
|
|
165
|
+
if (!FS) return moduleNotInstalledError3("expo-file-system");
|
|
166
|
+
try {
|
|
167
|
+
const file = new FS.File(payload.uri);
|
|
168
|
+
const content = await file.text();
|
|
169
|
+
return { success: true, content };
|
|
170
|
+
} catch (err) {
|
|
171
|
+
return { success: false, error: String(err) };
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
"file.write": async (payload) => {
|
|
175
|
+
const FS = await tryImport3("expo-file-system");
|
|
176
|
+
if (!FS) return moduleNotInstalledError3("expo-file-system");
|
|
177
|
+
try {
|
|
178
|
+
const dirMap = {
|
|
179
|
+
document: FS.Paths.document,
|
|
180
|
+
cache: FS.Paths.cache,
|
|
181
|
+
temp: FS.Paths.cache
|
|
182
|
+
};
|
|
183
|
+
const baseDir = dirMap[payload.directory ?? "document"];
|
|
184
|
+
const file = new FS.File(baseDir, payload.filename);
|
|
185
|
+
file.write(payload.content);
|
|
186
|
+
return { success: true, uri: file.uri };
|
|
187
|
+
} catch (err) {
|
|
188
|
+
return { success: false, error: String(err) };
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
"file.pick": async (payload) => {
|
|
192
|
+
const DocumentPicker = await tryImport3("expo-document-picker");
|
|
193
|
+
if (!DocumentPicker) return moduleNotInstalledError3("expo-document-picker");
|
|
194
|
+
try {
|
|
195
|
+
const result = await DocumentPicker.getDocumentAsync({
|
|
196
|
+
type: payload.type ?? ["*/*"],
|
|
197
|
+
multiple: payload.multiple ?? false
|
|
198
|
+
});
|
|
199
|
+
if (result.canceled) {
|
|
200
|
+
return { success: false, files: [] };
|
|
201
|
+
}
|
|
202
|
+
return {
|
|
203
|
+
success: true,
|
|
204
|
+
files: result.assets.map((a) => ({
|
|
205
|
+
uri: a.uri,
|
|
206
|
+
name: a.name,
|
|
207
|
+
size: a.size ?? 0,
|
|
208
|
+
mimeType: a.mimeType ?? "application/octet-stream"
|
|
209
|
+
}))
|
|
210
|
+
};
|
|
211
|
+
} catch {
|
|
212
|
+
return { success: false, files: [] };
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
// src/handlers/share.ts
|
|
218
|
+
import { moduleNotInstalledError as moduleNotInstalledError4, tryImport as tryImport4 } from "@rn-bridge-tools/core";
|
|
219
|
+
var shareHandlers = {
|
|
220
|
+
"share.open": async (payload) => {
|
|
221
|
+
const Sharing = await tryImport4("expo-sharing");
|
|
222
|
+
if (!Sharing) return moduleNotInstalledError4("expo-sharing");
|
|
223
|
+
try {
|
|
224
|
+
const isAvailable = await Sharing.isAvailableAsync();
|
|
225
|
+
if (!isAvailable) {
|
|
226
|
+
return { success: false };
|
|
227
|
+
}
|
|
228
|
+
await Sharing.shareAsync(payload.url ?? "", {
|
|
229
|
+
dialogTitle: payload.title
|
|
230
|
+
});
|
|
231
|
+
return { success: true };
|
|
232
|
+
} catch {
|
|
233
|
+
return { success: false };
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
// src/handlers/device.ts
|
|
239
|
+
import { moduleNotInstalledError as moduleNotInstalledError5, tryImport as tryImport5 } from "@rn-bridge-tools/core";
|
|
240
|
+
import { Platform } from "react-native";
|
|
241
|
+
var deviceHandlers = {
|
|
242
|
+
"device.getInfo": async (_payload) => {
|
|
243
|
+
const Device = await tryImport5("expo-device");
|
|
244
|
+
if (!Device) return moduleNotInstalledError5("expo-device");
|
|
245
|
+
return {
|
|
246
|
+
os: Platform.OS,
|
|
247
|
+
osVersion: Platform.Version?.toString() ?? "",
|
|
248
|
+
model: Device.modelName ?? "",
|
|
249
|
+
brand: Device.brand ?? "",
|
|
250
|
+
isTablet: Device.deviceType === Device.DeviceType.TABLET,
|
|
251
|
+
appVersion: "1.0.0",
|
|
252
|
+
buildNumber: "1",
|
|
253
|
+
bundleId: ""
|
|
254
|
+
};
|
|
255
|
+
},
|
|
256
|
+
"device.getBattery": async (_payload) => {
|
|
257
|
+
try {
|
|
258
|
+
const Battery = await tryImport5("expo-battery");
|
|
259
|
+
if (!Battery) {
|
|
260
|
+
return { level: -1, isCharging: false };
|
|
261
|
+
}
|
|
262
|
+
const level = await Battery.getBatteryLevelAsync();
|
|
263
|
+
const state = await Battery.getBatteryStateAsync();
|
|
264
|
+
return {
|
|
265
|
+
level,
|
|
266
|
+
isCharging: state === Battery.BatteryState.CHARGING
|
|
267
|
+
};
|
|
268
|
+
} catch {
|
|
269
|
+
return { level: -1, isCharging: false };
|
|
270
|
+
}
|
|
271
|
+
},
|
|
272
|
+
"device.getNetwork": async (_payload) => {
|
|
273
|
+
try {
|
|
274
|
+
const NetInfo = await tryImport5("@react-native-community/netinfo");
|
|
275
|
+
if (!NetInfo) {
|
|
276
|
+
return { type: "unknown", isConnected: true };
|
|
277
|
+
}
|
|
278
|
+
const state = await NetInfo.fetch();
|
|
279
|
+
return {
|
|
280
|
+
type: state.type ?? "unknown",
|
|
281
|
+
isConnected: state.isConnected ?? false
|
|
282
|
+
};
|
|
283
|
+
} catch {
|
|
284
|
+
return { type: "unknown", isConnected: true };
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
// src/handlers/statusbar.ts
|
|
290
|
+
import { StatusBar } from "react-native";
|
|
291
|
+
var statusbarHandlers = {
|
|
292
|
+
"statusbar.setStyle": async (payload) => {
|
|
293
|
+
const styleMap = {
|
|
294
|
+
light: "light-content",
|
|
295
|
+
dark: "dark-content",
|
|
296
|
+
auto: "default"
|
|
297
|
+
};
|
|
298
|
+
StatusBar.setBarStyle(styleMap[payload.style] ?? "default");
|
|
299
|
+
return { success: true };
|
|
300
|
+
},
|
|
301
|
+
"statusbar.setBackgroundColor": async (payload) => {
|
|
302
|
+
StatusBar.setBackgroundColor(payload.color, payload.animated ?? false);
|
|
303
|
+
return { success: true };
|
|
304
|
+
},
|
|
305
|
+
"statusbar.setHidden": async (payload) => {
|
|
306
|
+
const animationMap = {
|
|
307
|
+
fade: "fade",
|
|
308
|
+
slide: "slide",
|
|
309
|
+
none: "none"
|
|
310
|
+
};
|
|
311
|
+
StatusBar.setHidden(payload.hidden, animationMap[payload.animation ?? "none"]);
|
|
312
|
+
return { success: true };
|
|
313
|
+
}
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
// src/handlers/keyboard.ts
|
|
317
|
+
import { Keyboard } from "react-native";
|
|
318
|
+
var keyboardHandlers = {
|
|
319
|
+
"keyboard.dismiss": async (_payload) => {
|
|
320
|
+
Keyboard.dismiss();
|
|
321
|
+
return { success: true };
|
|
322
|
+
},
|
|
323
|
+
"keyboard.getState": async (_payload) => {
|
|
324
|
+
return {
|
|
325
|
+
visible: false,
|
|
326
|
+
height: 0
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
// src/handlers/haptic.ts
|
|
332
|
+
import { moduleNotInstalledError as moduleNotInstalledError6, tryImport as tryImport6 } from "@rn-bridge-tools/core";
|
|
333
|
+
var hapticHandlers = {
|
|
334
|
+
"haptic.impact": async (payload) => {
|
|
335
|
+
const Haptics = await tryImport6("expo-haptics");
|
|
336
|
+
if (!Haptics) {
|
|
337
|
+
moduleNotInstalledError6("expo-haptics");
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
const styleMap = {
|
|
341
|
+
light: Haptics.ImpactFeedbackStyle.Light,
|
|
342
|
+
medium: Haptics.ImpactFeedbackStyle.Medium,
|
|
343
|
+
heavy: Haptics.ImpactFeedbackStyle.Heavy
|
|
344
|
+
};
|
|
345
|
+
await Haptics.impactAsync(styleMap[payload.style]);
|
|
346
|
+
},
|
|
347
|
+
"haptic.notification": async (payload) => {
|
|
348
|
+
const Haptics = await tryImport6("expo-haptics");
|
|
349
|
+
if (!Haptics) {
|
|
350
|
+
moduleNotInstalledError6("expo-haptics");
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
const typeMap = {
|
|
354
|
+
success: Haptics.NotificationFeedbackType.Success,
|
|
355
|
+
warning: Haptics.NotificationFeedbackType.Warning,
|
|
356
|
+
error: Haptics.NotificationFeedbackType.Error
|
|
357
|
+
};
|
|
358
|
+
await Haptics.notificationAsync(typeMap[payload.type]);
|
|
359
|
+
},
|
|
360
|
+
"haptic.selection": async () => {
|
|
361
|
+
const Haptics = await tryImport6("expo-haptics");
|
|
362
|
+
if (!Haptics) {
|
|
363
|
+
moduleNotInstalledError6("expo-haptics");
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
await Haptics.selectionAsync();
|
|
367
|
+
}
|
|
368
|
+
};
|
|
369
|
+
|
|
370
|
+
// src/handlers/clipboard.ts
|
|
371
|
+
import { moduleNotInstalledError as moduleNotInstalledError7, tryImport as tryImport7 } from "@rn-bridge-tools/core";
|
|
372
|
+
var clipboardHandlers = {
|
|
373
|
+
"clipboard.copy": async (payload) => {
|
|
374
|
+
const Clipboard = await tryImport7("expo-clipboard");
|
|
375
|
+
if (!Clipboard) return moduleNotInstalledError7("expo-clipboard");
|
|
376
|
+
await Clipboard.setStringAsync(payload.text);
|
|
377
|
+
return { success: true };
|
|
378
|
+
},
|
|
379
|
+
"clipboard.paste": async (_payload) => {
|
|
380
|
+
const Clipboard = await tryImport7("expo-clipboard");
|
|
381
|
+
if (!Clipboard) return moduleNotInstalledError7("expo-clipboard");
|
|
382
|
+
const text = await Clipboard.getStringAsync();
|
|
383
|
+
return { text, hasContent: text.length > 0 };
|
|
384
|
+
}
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
// src/handlers/scanner.ts
|
|
388
|
+
import { moduleNotInstalledError as moduleNotInstalledError8, tryImport as tryImport8 } from "@rn-bridge-tools/core";
|
|
389
|
+
var scannerHandlers = {
|
|
390
|
+
"scanner.scanQR": async (_payload) => {
|
|
391
|
+
const Camera = await tryImport8("expo-camera");
|
|
392
|
+
if (!Camera) return moduleNotInstalledError8("expo-camera");
|
|
393
|
+
try {
|
|
394
|
+
const { status } = await Camera.Camera.requestCameraPermissionsAsync();
|
|
395
|
+
if (status !== "granted") {
|
|
396
|
+
return { success: false, cancelled: true };
|
|
397
|
+
}
|
|
398
|
+
return { success: false, error: "Use Camera component for QR scanning" };
|
|
399
|
+
} catch {
|
|
400
|
+
return { success: false };
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
// src/handlers/auth.ts
|
|
406
|
+
import { moduleNotInstalledError as moduleNotInstalledError9, tryImport as tryImport9 } from "@rn-bridge-tools/core";
|
|
407
|
+
var authHandlers = {
|
|
408
|
+
"auth.biometric": async (payload) => {
|
|
409
|
+
const LocalAuth = await tryImport9("expo-local-authentication");
|
|
410
|
+
if (!LocalAuth) return moduleNotInstalledError9("expo-local-authentication");
|
|
411
|
+
try {
|
|
412
|
+
const result = await LocalAuth.authenticateAsync({
|
|
413
|
+
promptMessage: payload.promptMessage ?? "Authenticate",
|
|
414
|
+
cancelLabel: payload.cancelLabel,
|
|
415
|
+
fallbackLabel: payload.fallbackLabel
|
|
416
|
+
});
|
|
417
|
+
if (result.success) {
|
|
418
|
+
return { success: true };
|
|
419
|
+
}
|
|
420
|
+
return { success: false, error: result.error };
|
|
421
|
+
} catch (err) {
|
|
422
|
+
return { success: false, error: String(err) };
|
|
423
|
+
}
|
|
424
|
+
},
|
|
425
|
+
"auth.isBiometricAvailable": async (_payload) => {
|
|
426
|
+
const LocalAuth = await tryImport9("expo-local-authentication");
|
|
427
|
+
if (!LocalAuth) return moduleNotInstalledError9("expo-local-authentication");
|
|
428
|
+
try {
|
|
429
|
+
const available = await LocalAuth.hasHardwareAsync();
|
|
430
|
+
const types = await LocalAuth.supportedAuthenticationTypesAsync();
|
|
431
|
+
let biometryType;
|
|
432
|
+
if (types.includes(LocalAuth.AuthenticationType.FACIAL_RECOGNITION)) {
|
|
433
|
+
biometryType = "facial";
|
|
434
|
+
} else if (types.includes(LocalAuth.AuthenticationType.FINGERPRINT)) {
|
|
435
|
+
biometryType = "fingerprint";
|
|
436
|
+
} else if (types.includes(LocalAuth.AuthenticationType.IRIS)) {
|
|
437
|
+
biometryType = "iris";
|
|
438
|
+
}
|
|
439
|
+
return { available, biometryType };
|
|
440
|
+
} catch {
|
|
441
|
+
return { available: false };
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
};
|
|
445
|
+
|
|
446
|
+
// src/handlers/iap.ts
|
|
447
|
+
var iapHandlers = {
|
|
448
|
+
"iap.getProducts": async (_payload) => {
|
|
449
|
+
return { products: [] };
|
|
450
|
+
},
|
|
451
|
+
"iap.purchase": async (_payload) => {
|
|
452
|
+
return { success: false, error: "IAP not configured" };
|
|
453
|
+
},
|
|
454
|
+
"iap.restore": async (_payload) => {
|
|
455
|
+
return { purchases: [] };
|
|
456
|
+
}
|
|
457
|
+
};
|
|
458
|
+
|
|
459
|
+
// src/handlers/push.ts
|
|
460
|
+
import { moduleNotInstalledError as moduleNotInstalledError10, tryImport as tryImport10 } from "@rn-bridge-tools/core";
|
|
461
|
+
import { Platform as Platform2 } from "react-native";
|
|
462
|
+
var pushHandlers = {
|
|
463
|
+
"push.getToken": async (_payload) => {
|
|
464
|
+
const Notifications = await tryImport10("expo-notifications");
|
|
465
|
+
if (!Notifications) return moduleNotInstalledError10("expo-notifications");
|
|
466
|
+
try {
|
|
467
|
+
const token = await Notifications.getExpoPushTokenAsync();
|
|
468
|
+
return {
|
|
469
|
+
token: token.data,
|
|
470
|
+
platform: Platform2.OS === "ios" ? "apns" : "fcm"
|
|
471
|
+
};
|
|
472
|
+
} catch {
|
|
473
|
+
return { token: "", platform: Platform2.OS === "ios" ? "apns" : "fcm" };
|
|
474
|
+
}
|
|
475
|
+
},
|
|
476
|
+
"push.requestPermission": async (_payload) => {
|
|
477
|
+
const Notifications = await tryImport10("expo-notifications");
|
|
478
|
+
if (!Notifications) return moduleNotInstalledError10("expo-notifications");
|
|
479
|
+
try {
|
|
480
|
+
const { status } = await Notifications.requestPermissionsAsync();
|
|
481
|
+
return {
|
|
482
|
+
granted: status === "granted",
|
|
483
|
+
status
|
|
484
|
+
};
|
|
485
|
+
} catch {
|
|
486
|
+
return { granted: false, status: "denied" };
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
};
|
|
490
|
+
|
|
491
|
+
// src/handlers/permission.ts
|
|
492
|
+
import { Linking } from "react-native";
|
|
493
|
+
import { tryImport as tryImport11 } from "@rn-bridge-tools/core";
|
|
494
|
+
async function getPermissionModule(permission) {
|
|
495
|
+
switch (permission) {
|
|
496
|
+
case "camera": {
|
|
497
|
+
const mod = await tryImport11("expo-camera");
|
|
498
|
+
return mod ? {
|
|
499
|
+
check: () => mod.Camera.getCameraPermissionsAsync(),
|
|
500
|
+
request: () => mod.Camera.requestCameraPermissionsAsync()
|
|
501
|
+
} : null;
|
|
502
|
+
}
|
|
503
|
+
case "location": {
|
|
504
|
+
const mod = await tryImport11("expo-location");
|
|
505
|
+
return mod ? {
|
|
506
|
+
check: () => mod.getForegroundPermissionsAsync(),
|
|
507
|
+
request: () => mod.requestForegroundPermissionsAsync()
|
|
508
|
+
} : null;
|
|
509
|
+
}
|
|
510
|
+
case "notifications": {
|
|
511
|
+
const mod = await tryImport11("expo-notifications");
|
|
512
|
+
return mod ? {
|
|
513
|
+
check: () => mod.getPermissionsAsync(),
|
|
514
|
+
request: () => mod.requestPermissionsAsync()
|
|
515
|
+
} : null;
|
|
516
|
+
}
|
|
517
|
+
default:
|
|
518
|
+
return null;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
var permissionHandlers = {
|
|
522
|
+
"permission.check": async (payload) => {
|
|
523
|
+
const mod = await getPermissionModule(payload.permission);
|
|
524
|
+
if (!mod) {
|
|
525
|
+
return { status: "undetermined", canAskAgain: true };
|
|
526
|
+
}
|
|
527
|
+
try {
|
|
528
|
+
const result = await mod.check();
|
|
529
|
+
return {
|
|
530
|
+
status: result.status,
|
|
531
|
+
canAskAgain: result.canAskAgain ?? true
|
|
532
|
+
};
|
|
533
|
+
} catch {
|
|
534
|
+
return { status: "undetermined", canAskAgain: true };
|
|
535
|
+
}
|
|
536
|
+
},
|
|
537
|
+
"permission.request": async (payload) => {
|
|
538
|
+
const mod = await getPermissionModule(payload.permission);
|
|
539
|
+
if (!mod) {
|
|
540
|
+
return { status: "undetermined", canAskAgain: true };
|
|
541
|
+
}
|
|
542
|
+
try {
|
|
543
|
+
const result = await mod.request();
|
|
544
|
+
return {
|
|
545
|
+
status: result.status,
|
|
546
|
+
canAskAgain: result.canAskAgain ?? true
|
|
547
|
+
};
|
|
548
|
+
} catch {
|
|
549
|
+
return { status: "undetermined", canAskAgain: true };
|
|
550
|
+
}
|
|
551
|
+
},
|
|
552
|
+
"permission.openSettings": async (_payload) => {
|
|
553
|
+
try {
|
|
554
|
+
await Linking.openSettings();
|
|
555
|
+
return { success: true };
|
|
556
|
+
} catch {
|
|
557
|
+
return { success: false };
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
};
|
|
561
|
+
|
|
562
|
+
// src/handlers/preference.ts
|
|
563
|
+
import { tryImport as tryImport12 } from "@rn-bridge-tools/core";
|
|
564
|
+
var preferenceHandlers = {
|
|
565
|
+
"preference.get": async (payload) => {
|
|
566
|
+
const mod = await tryImport12("@react-native-async-storage/async-storage");
|
|
567
|
+
if (!mod) return { value: null };
|
|
568
|
+
const value = await mod.default.getItem(payload.key);
|
|
569
|
+
return { value };
|
|
570
|
+
},
|
|
571
|
+
"preference.set": async (payload) => {
|
|
572
|
+
const mod = await tryImport12("@react-native-async-storage/async-storage");
|
|
573
|
+
if (!mod) return { success: false };
|
|
574
|
+
await mod.default.setItem(payload.key, payload.value);
|
|
575
|
+
return { success: true };
|
|
576
|
+
},
|
|
577
|
+
"preference.remove": async (payload) => {
|
|
578
|
+
const mod = await tryImport12("@react-native-async-storage/async-storage");
|
|
579
|
+
if (!mod) return { success: false };
|
|
580
|
+
await mod.default.removeItem(payload.key);
|
|
581
|
+
return { success: true };
|
|
582
|
+
},
|
|
583
|
+
"preference.clear": async (_payload) => {
|
|
584
|
+
const mod = await tryImport12("@react-native-async-storage/async-storage");
|
|
585
|
+
if (!mod) return { success: false };
|
|
586
|
+
await mod.default.clear();
|
|
587
|
+
return { success: true };
|
|
588
|
+
}
|
|
589
|
+
};
|
|
590
|
+
|
|
591
|
+
// src/handlers/navigation.ts
|
|
592
|
+
var navigationHandlers = {
|
|
593
|
+
"navigation.goBack": async (_payload) => {
|
|
594
|
+
return { success: true };
|
|
595
|
+
},
|
|
596
|
+
"navigation.push": async (_payload) => {
|
|
597
|
+
return { success: true };
|
|
598
|
+
},
|
|
599
|
+
"navigation.close": async (_payload) => {
|
|
600
|
+
return { success: true };
|
|
601
|
+
},
|
|
602
|
+
"navigation.setSwipeBack": async (_payload) => {
|
|
603
|
+
return { success: true };
|
|
604
|
+
}
|
|
605
|
+
};
|
|
606
|
+
|
|
607
|
+
// src/handlers/browser.ts
|
|
608
|
+
import { moduleNotInstalledError as moduleNotInstalledError11, tryImport as tryImport13 } from "@rn-bridge-tools/core";
|
|
609
|
+
import { Linking as Linking2 } from "react-native";
|
|
610
|
+
var browserHandlers = {
|
|
611
|
+
"browser.openExternal": async (payload) => {
|
|
612
|
+
try {
|
|
613
|
+
await Linking2.openURL(payload.url);
|
|
614
|
+
return { success: true };
|
|
615
|
+
} catch {
|
|
616
|
+
return { success: false };
|
|
617
|
+
}
|
|
618
|
+
},
|
|
619
|
+
"browser.openInternal": async (payload) => {
|
|
620
|
+
const WebBrowser = await tryImport13("expo-web-browser");
|
|
621
|
+
if (!WebBrowser) return moduleNotInstalledError11("expo-web-browser");
|
|
622
|
+
try {
|
|
623
|
+
await WebBrowser.openBrowserAsync(payload.url, {
|
|
624
|
+
showTitle: payload.showTitle,
|
|
625
|
+
toolbarColor: payload.toolbarColor
|
|
626
|
+
});
|
|
627
|
+
return { success: true };
|
|
628
|
+
} catch {
|
|
629
|
+
return { success: false };
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
};
|
|
633
|
+
|
|
634
|
+
// src/createHandlers.ts
|
|
635
|
+
var handlerRegistry = {
|
|
636
|
+
camera: cameraHandlers,
|
|
637
|
+
location: locationHandlers,
|
|
638
|
+
file: fileHandlers,
|
|
639
|
+
share: shareHandlers,
|
|
640
|
+
device: deviceHandlers,
|
|
641
|
+
statusbar: statusbarHandlers,
|
|
642
|
+
keyboard: keyboardHandlers,
|
|
643
|
+
haptic: hapticHandlers,
|
|
644
|
+
clipboard: clipboardHandlers,
|
|
645
|
+
scanner: scannerHandlers,
|
|
646
|
+
auth: authHandlers,
|
|
647
|
+
iap: iapHandlers,
|
|
648
|
+
push: pushHandlers,
|
|
649
|
+
permission: permissionHandlers,
|
|
650
|
+
preference: preferenceHandlers,
|
|
651
|
+
navigation: navigationHandlers,
|
|
652
|
+
browser: browserHandlers
|
|
653
|
+
};
|
|
654
|
+
function createDisabledHandler(_namespace, _action) {
|
|
655
|
+
return async () => ({
|
|
656
|
+
success: false,
|
|
657
|
+
error: `not_enabled: ${_namespace}.${_action}`
|
|
658
|
+
});
|
|
659
|
+
}
|
|
660
|
+
function createDefaultHandlers(options = {}) {
|
|
661
|
+
const result = {};
|
|
662
|
+
for (const [namespace, handlers] of Object.entries(handlerRegistry)) {
|
|
663
|
+
const enabled = options[namespace] ?? false;
|
|
664
|
+
for (const [action, handler] of Object.entries(handlers)) {
|
|
665
|
+
if (enabled) {
|
|
666
|
+
result[action] = handler;
|
|
667
|
+
} else {
|
|
668
|
+
const actionName = action.split(".")[1] ?? action;
|
|
669
|
+
result[action] = createDisabledHandler(namespace, actionName);
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
return result;
|
|
674
|
+
}
|
|
675
|
+
export {
|
|
676
|
+
WebViewBridge,
|
|
677
|
+
authHandlers,
|
|
678
|
+
browserHandlers,
|
|
679
|
+
cameraHandlers,
|
|
680
|
+
clipboardHandlers,
|
|
681
|
+
createDefaultHandlers,
|
|
682
|
+
deviceHandlers,
|
|
683
|
+
fileHandlers,
|
|
684
|
+
hapticHandlers,
|
|
685
|
+
iapHandlers,
|
|
686
|
+
keyboardHandlers,
|
|
687
|
+
locationHandlers,
|
|
688
|
+
navigationHandlers,
|
|
689
|
+
permissionHandlers,
|
|
690
|
+
preferenceHandlers,
|
|
691
|
+
pushHandlers,
|
|
692
|
+
scannerHandlers,
|
|
693
|
+
shareHandlers,
|
|
694
|
+
statusbarHandlers
|
|
695
|
+
};
|
|
696
|
+
//# sourceMappingURL=index.js.map
|