nativine 1.0.2
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 +410 -0
- package/dist/core/bridge.d.ts +52 -0
- package/dist/core/platform.d.ts +15 -0
- package/dist/index.d.ts +182 -0
- package/dist/modules/ads.d.ts +40 -0
- package/dist/modules/auth.d.ts +45 -0
- package/dist/modules/biometrics.d.ts +60 -0
- package/dist/modules/cache.d.ts +25 -0
- package/dist/modules/camera.d.ts +35 -0
- package/dist/modules/clipboard.d.ts +28 -0
- package/dist/modules/contacts.d.ts +28 -0
- package/dist/modules/device.d.ts +84 -0
- package/dist/modules/downloads.d.ts +31 -0
- package/dist/modules/events.d.ts +55 -0
- package/dist/modules/haptics.d.ts +44 -0
- package/dist/modules/location.d.ts +31 -0
- package/dist/modules/navigation.d.ts +60 -0
- package/dist/modules/network.d.ts +54 -0
- package/dist/modules/onesignal.d.ts +70 -0
- package/dist/modules/pedometer.d.ts +66 -0
- package/dist/modules/print.d.ts +14 -0
- package/dist/modules/reviews.d.ts +19 -0
- package/dist/modules/screenshot.d.ts +21 -0
- package/dist/modules/share.d.ts +46 -0
- package/dist/modules/storage.d.ts +56 -0
- package/dist/modules/toast.d.ts +19 -0
- package/dist/modules/ui.d.ts +109 -0
- package/dist/modules/updates.d.ts +15 -0
- package/dist/nativine.cjs.js +1984 -0
- package/dist/nativine.cjs.js.map +1 -0
- package/dist/nativine.esm.js +1954 -0
- package/dist/nativine.esm.js.map +1 -0
- package/dist/nativine.umd.js +2 -0
- package/dist/nativine.umd.js.map +1 -0
- package/package.json +58 -0
|
@@ -0,0 +1,1984 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Nativine Platform Detection
|
|
7
|
+
*
|
|
8
|
+
* Detects whether the web page is running inside a Nativine-powered native app
|
|
9
|
+
* and identifies the platform (Android, iOS, or Web).
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Detects the current platform by checking for native bridge objects
|
|
13
|
+
* injected by the Nativine native shell.
|
|
14
|
+
*/
|
|
15
|
+
function detectPlatform() {
|
|
16
|
+
if (typeof window === 'undefined')
|
|
17
|
+
return 'web';
|
|
18
|
+
// Android: The Kotlin WebView injects `window.nativine` via addJavascriptInterface
|
|
19
|
+
if (window.nativine && typeof window.nativine.vibrate === 'function') {
|
|
20
|
+
return 'android';
|
|
21
|
+
}
|
|
22
|
+
// Android fallback: check for NativineAndroid bridge
|
|
23
|
+
if (window.NativineAndroid && typeof window.NativineAndroid.postMessage === 'function') {
|
|
24
|
+
return 'android';
|
|
25
|
+
}
|
|
26
|
+
// iOS: WebKit message handlers are injected via WKScriptMessageHandler
|
|
27
|
+
if (window.webkit &&
|
|
28
|
+
window.webkit.messageHandlers &&
|
|
29
|
+
window.webkit.messageHandlers.nativine) {
|
|
30
|
+
return 'ios';
|
|
31
|
+
}
|
|
32
|
+
return 'web';
|
|
33
|
+
}
|
|
34
|
+
/** The detected platform: `'android'`, `'ios'`, or `'web'` */
|
|
35
|
+
const platform = detectPlatform();
|
|
36
|
+
/** `true` if the page is running inside a Nativine native app (Android or iOS) */
|
|
37
|
+
const isNativeApp = platform !== 'web';
|
|
38
|
+
/** `true` if the page is running inside a Nativine Android app */
|
|
39
|
+
const isAndroid = platform === 'android';
|
|
40
|
+
/** `true` if the page is running inside a Nativine iOS app */
|
|
41
|
+
const isIos = platform === 'ios';
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Nativine Bridge Dispatcher
|
|
45
|
+
*
|
|
46
|
+
* Low-level bridge call mechanism that provides a unified, Promise-based interface
|
|
47
|
+
* for communicating with the native Android/iOS app shell.
|
|
48
|
+
*
|
|
49
|
+
* Architecture:
|
|
50
|
+
* - Android: Calls `window.nativine.<method>(args, callbackId)` via @JavascriptInterface
|
|
51
|
+
* - iOS: Calls `window.webkit.messageHandlers.nativine.postMessage({ method, args, callbackId })`
|
|
52
|
+
* - Web: Returns rejected promises or no-ops gracefully
|
|
53
|
+
*
|
|
54
|
+
* The native side resolves the Promise by calling: `window[callbackId](jsonResult)`
|
|
55
|
+
*/
|
|
56
|
+
/** Counter for generating unique callback IDs */
|
|
57
|
+
let _callbackCounter = 0;
|
|
58
|
+
/** Default timeout for bridge calls (10 seconds) */
|
|
59
|
+
const DEFAULT_TIMEOUT_MS = 10000;
|
|
60
|
+
/**
|
|
61
|
+
* Error thrown when a bridge method is called outside a native app context.
|
|
62
|
+
*/
|
|
63
|
+
class NativineNotAvailableError extends Error {
|
|
64
|
+
constructor(method) {
|
|
65
|
+
super(`nativine.${method}() is not available — page is not running inside a Nativine app.`);
|
|
66
|
+
this.name = 'NativineNotAvailableError';
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Error thrown when a bridge call times out waiting for native response.
|
|
71
|
+
*/
|
|
72
|
+
class NativineTimeoutError extends Error {
|
|
73
|
+
constructor(method, timeoutMs) {
|
|
74
|
+
super(`nativine.${method}() timed out after ${timeoutMs}ms waiting for native response.`);
|
|
75
|
+
this.name = 'NativineTimeoutError';
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Makes an async call to the native bridge and returns a Promise that resolves
|
|
80
|
+
* when the native side responds via the callback.
|
|
81
|
+
*
|
|
82
|
+
* @param method - The native method name to call (e.g., 'getDeviceInfo')
|
|
83
|
+
* @param args - Optional arguments to pass to the native method (serialized as JSON string)
|
|
84
|
+
* @param timeoutMs - Timeout in milliseconds (default: 10s)
|
|
85
|
+
* @returns Promise that resolves with the parsed native response
|
|
86
|
+
*/
|
|
87
|
+
function callNativeAsync(method, args, timeoutMs = DEFAULT_TIMEOUT_MS) {
|
|
88
|
+
return new Promise((resolve, reject) => {
|
|
89
|
+
if (!isNativeApp) {
|
|
90
|
+
reject(new NativineNotAvailableError(method));
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const callbackId = `__nativine_cb_${++_callbackCounter}_${Date.now()}`;
|
|
94
|
+
let settled = false;
|
|
95
|
+
// Timeout guard
|
|
96
|
+
const timer = setTimeout(() => {
|
|
97
|
+
if (!settled) {
|
|
98
|
+
settled = true;
|
|
99
|
+
cleanup();
|
|
100
|
+
reject(new NativineTimeoutError(method, timeoutMs));
|
|
101
|
+
}
|
|
102
|
+
}, timeoutMs);
|
|
103
|
+
const cleanup = () => {
|
|
104
|
+
delete window[callbackId];
|
|
105
|
+
delete window[`${callbackId}_error`];
|
|
106
|
+
clearTimeout(timer);
|
|
107
|
+
};
|
|
108
|
+
// Register success callback
|
|
109
|
+
window[callbackId] = (result) => {
|
|
110
|
+
if (settled)
|
|
111
|
+
return;
|
|
112
|
+
settled = true;
|
|
113
|
+
cleanup();
|
|
114
|
+
try {
|
|
115
|
+
const parsed = typeof result === 'string' ? JSON.parse(result) : result;
|
|
116
|
+
resolve(parsed);
|
|
117
|
+
}
|
|
118
|
+
catch (_a) {
|
|
119
|
+
// If it's not JSON, return raw string
|
|
120
|
+
resolve(result);
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
// Register error callback
|
|
124
|
+
window[`${callbackId}_error`] = (error) => {
|
|
125
|
+
if (settled)
|
|
126
|
+
return;
|
|
127
|
+
settled = true;
|
|
128
|
+
cleanup();
|
|
129
|
+
reject(new Error(error || `Native method '${method}' failed`));
|
|
130
|
+
};
|
|
131
|
+
// Dispatch the call to the appropriate native bridge
|
|
132
|
+
try {
|
|
133
|
+
const argsString = args ? JSON.stringify(args) : '';
|
|
134
|
+
if (isAndroid) {
|
|
135
|
+
const bridge = window.nativine;
|
|
136
|
+
if (bridge && typeof bridge[method] === 'function') {
|
|
137
|
+
bridge[method](argsString, callbackId);
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
// Fallback: use NativineAndroid.postMessage for methods handled there
|
|
141
|
+
const androidBridge = window.NativineAndroid;
|
|
142
|
+
if (androidBridge && typeof androidBridge.postMessage === 'function') {
|
|
143
|
+
androidBridge.postMessage(JSON.stringify({
|
|
144
|
+
action: method,
|
|
145
|
+
payload: args || {},
|
|
146
|
+
callbackId,
|
|
147
|
+
}));
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
settled = true;
|
|
151
|
+
cleanup();
|
|
152
|
+
reject(new Error(`Native method '${method}' not found on bridge`));
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
else if (isIos) {
|
|
157
|
+
window.webkit.messageHandlers.nativine.postMessage({
|
|
158
|
+
method,
|
|
159
|
+
args: args || {},
|
|
160
|
+
callbackId,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
catch (e) {
|
|
165
|
+
if (!settled) {
|
|
166
|
+
settled = true;
|
|
167
|
+
cleanup();
|
|
168
|
+
reject(e);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Makes a synchronous (fire-and-forget) call to the native bridge.
|
|
175
|
+
* Used for methods that don't need a return value (e.g., vibrate, statusBar).
|
|
176
|
+
*
|
|
177
|
+
* @param method - The native method name to call
|
|
178
|
+
* @param args - Optional arguments
|
|
179
|
+
*/
|
|
180
|
+
function callNativeSync(method, args) {
|
|
181
|
+
if (!isNativeApp)
|
|
182
|
+
return; // Silent no-op on web
|
|
183
|
+
try {
|
|
184
|
+
const argsString = args ? JSON.stringify(args) : '';
|
|
185
|
+
if (isAndroid) {
|
|
186
|
+
const bridge = window.nativine;
|
|
187
|
+
if (bridge && typeof bridge[method] === 'function') {
|
|
188
|
+
bridge[method](argsString);
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
// Fallback: postMessage for actions handled in the message handler
|
|
192
|
+
const androidBridge = window.NativineAndroid;
|
|
193
|
+
if (androidBridge && typeof androidBridge.postMessage === 'function') {
|
|
194
|
+
androidBridge.postMessage(JSON.stringify({
|
|
195
|
+
action: method,
|
|
196
|
+
payload: args || {},
|
|
197
|
+
}));
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
else if (isIos) {
|
|
202
|
+
window.webkit.messageHandlers.nativine.postMessage({
|
|
203
|
+
method,
|
|
204
|
+
args: args || {},
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
catch (e) {
|
|
209
|
+
// Silent fail on web or if bridge is unavailable
|
|
210
|
+
if (typeof console !== 'undefined') {
|
|
211
|
+
console.warn(`[nativine] Failed to call native method '${method}':`, e);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Device Module
|
|
218
|
+
*
|
|
219
|
+
* Access device hardware/software information, safe area insets,
|
|
220
|
+
* app version, and anonymous device identifiers.
|
|
221
|
+
*/
|
|
222
|
+
/**
|
|
223
|
+
* Get comprehensive device information.
|
|
224
|
+
*
|
|
225
|
+
* @example
|
|
226
|
+
* ```js
|
|
227
|
+
* const info = await nativine.device.getInfo();
|
|
228
|
+
* console.log(info.model); // "Pixel 8"
|
|
229
|
+
* console.log(info.appVersion); // "1.2.0"
|
|
230
|
+
* ```
|
|
231
|
+
*/
|
|
232
|
+
async function getInfo() {
|
|
233
|
+
if (!isNativeApp) {
|
|
234
|
+
return {
|
|
235
|
+
model: navigator.userAgent,
|
|
236
|
+
manufacturer: 'unknown',
|
|
237
|
+
osVersion: 'unknown',
|
|
238
|
+
appVersion: '0.0.0',
|
|
239
|
+
appVersionCode: 0,
|
|
240
|
+
packageName: 'web',
|
|
241
|
+
locale: navigator.language || 'en',
|
|
242
|
+
screenWidth: window.innerWidth,
|
|
243
|
+
screenHeight: window.innerHeight,
|
|
244
|
+
density: window.devicePixelRatio || 1,
|
|
245
|
+
platform,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
return callNativeAsync('getDeviceInfo');
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Get the current safe area insets.
|
|
252
|
+
* Useful for positioning UI elements to avoid notches and system bars.
|
|
253
|
+
*
|
|
254
|
+
* @example
|
|
255
|
+
* ```js
|
|
256
|
+
* const insets = await nativine.device.getSafeAreaInsets();
|
|
257
|
+
* element.style.paddingTop = `${insets.top}px`;
|
|
258
|
+
* ```
|
|
259
|
+
*/
|
|
260
|
+
async function getSafeAreaInsets() {
|
|
261
|
+
if (!isNativeApp) {
|
|
262
|
+
return { top: 0, bottom: 0, left: 0, right: 0 };
|
|
263
|
+
}
|
|
264
|
+
return callNativeAsync('getSafeAreaInsets');
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Get the app's version name string (e.g., "1.2.0").
|
|
268
|
+
*
|
|
269
|
+
* @example
|
|
270
|
+
* ```js
|
|
271
|
+
* const version = await nativine.device.getAppVersion();
|
|
272
|
+
* // "1.2.0"
|
|
273
|
+
* ```
|
|
274
|
+
*/
|
|
275
|
+
async function getAppVersion() {
|
|
276
|
+
if (!isNativeApp)
|
|
277
|
+
return '0.0.0';
|
|
278
|
+
const info = await callNativeAsync('getDeviceInfo');
|
|
279
|
+
return info.appVersion;
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Get an anonymous, persistent device identifier.
|
|
283
|
+
* This ID is unique per app installation (not a hardware ID).
|
|
284
|
+
* Resets when the app is reinstalled.
|
|
285
|
+
*
|
|
286
|
+
* @example
|
|
287
|
+
* ```js
|
|
288
|
+
* const id = await nativine.device.getDeviceId();
|
|
289
|
+
* // "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
|
|
290
|
+
* ```
|
|
291
|
+
*/
|
|
292
|
+
async function getDeviceId() {
|
|
293
|
+
if (!isNativeApp)
|
|
294
|
+
return 'web-' + Math.random().toString(36).slice(2);
|
|
295
|
+
return callNativeAsync('getDeviceId');
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
var device = /*#__PURE__*/Object.freeze({
|
|
299
|
+
__proto__: null,
|
|
300
|
+
getAppVersion: getAppVersion,
|
|
301
|
+
getDeviceId: getDeviceId,
|
|
302
|
+
getInfo: getInfo,
|
|
303
|
+
getSafeAreaInsets: getSafeAreaInsets
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* UI Module
|
|
308
|
+
*
|
|
309
|
+
* Control native UI elements: status bar, navigation bar, splash screen,
|
|
310
|
+
* screen orientation, and native component visibility.
|
|
311
|
+
*/
|
|
312
|
+
/**
|
|
313
|
+
* Configure the native status bar appearance.
|
|
314
|
+
*
|
|
315
|
+
* @example
|
|
316
|
+
* ```js
|
|
317
|
+
* nativine.ui.statusBar({ color: '#1a1a2e', style: 'light' });
|
|
318
|
+
* ```
|
|
319
|
+
*/
|
|
320
|
+
function statusBar(options) {
|
|
321
|
+
callNativeSync('setStatusBar', options);
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Configure the native navigation bar appearance (Android only).
|
|
325
|
+
*
|
|
326
|
+
* @example
|
|
327
|
+
* ```js
|
|
328
|
+
* nativine.ui.navigationBar({ color: '#16213e' });
|
|
329
|
+
* ```
|
|
330
|
+
*/
|
|
331
|
+
function navigationBar(options) {
|
|
332
|
+
callNativeSync('setNavigationBar', options);
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Programmatically hide the splash screen.
|
|
336
|
+
* Useful when your web app needs time to load data before revealing the UI.
|
|
337
|
+
*
|
|
338
|
+
* @example
|
|
339
|
+
* ```js
|
|
340
|
+
* await fetchInitialData();
|
|
341
|
+
* nativine.ui.hideSplashScreen();
|
|
342
|
+
* ```
|
|
343
|
+
*/
|
|
344
|
+
function hideSplashScreen() {
|
|
345
|
+
callNativeSync('hideSplashScreen');
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* Lock the screen to a specific orientation.
|
|
349
|
+
*
|
|
350
|
+
* @param mode - 'portrait' | 'landscape' | 'auto'
|
|
351
|
+
*
|
|
352
|
+
* @example
|
|
353
|
+
* ```js
|
|
354
|
+
* // Lock to landscape for a video player
|
|
355
|
+
* nativine.ui.setOrientation('landscape');
|
|
356
|
+
*
|
|
357
|
+
* // Unlock when done
|
|
358
|
+
* nativine.ui.setOrientation('auto');
|
|
359
|
+
* ```
|
|
360
|
+
*/
|
|
361
|
+
function setOrientation(mode) {
|
|
362
|
+
callNativeSync('setOrientation', { mode });
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Show native UI components (header, bottom nav, floating button).
|
|
366
|
+
* Reverses the effect of `hideNativeComponents()`.
|
|
367
|
+
*
|
|
368
|
+
* @example
|
|
369
|
+
* ```js
|
|
370
|
+
* nativine.ui.showNativeComponents();
|
|
371
|
+
* ```
|
|
372
|
+
*/
|
|
373
|
+
function showNativeComponents() {
|
|
374
|
+
callNativeSync('showNativeComponents');
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Hide all native UI components (header, bottom nav, floating button).
|
|
378
|
+
* Useful for fullscreen content like videos or immersive experiences.
|
|
379
|
+
*
|
|
380
|
+
* @example
|
|
381
|
+
* ```js
|
|
382
|
+
* // Enter fullscreen mode
|
|
383
|
+
* nativine.ui.hideNativeComponents();
|
|
384
|
+
* ```
|
|
385
|
+
*/
|
|
386
|
+
function hideNativeComponents() {
|
|
387
|
+
callNativeSync('hideNativeComponents');
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Toggle pull-to-refresh behavior.
|
|
391
|
+
*
|
|
392
|
+
* @param enabled - Whether pull-to-refresh should be enabled
|
|
393
|
+
*
|
|
394
|
+
* @example
|
|
395
|
+
* ```js
|
|
396
|
+
* // Disable on a page with custom scroll behavior
|
|
397
|
+
* nativine.ui.setPullToRefresh(false);
|
|
398
|
+
* ```
|
|
399
|
+
*/
|
|
400
|
+
function setPullToRefresh(enabled) {
|
|
401
|
+
callNativeSync('setPullToRefresh', { enabled });
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Toggle pinch-to-zoom behavior.
|
|
405
|
+
*
|
|
406
|
+
* @param enabled - Whether pinch-to-zoom should be enabled
|
|
407
|
+
*
|
|
408
|
+
* @example
|
|
409
|
+
* ```js
|
|
410
|
+
* // Enable for an image gallery
|
|
411
|
+
* nativine.ui.setPinchToZoom(true);
|
|
412
|
+
* ```
|
|
413
|
+
*/
|
|
414
|
+
function setPinchToZoom(enabled) {
|
|
415
|
+
callNativeSync('setPinchToZoom', { enabled });
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
var ui = /*#__PURE__*/Object.freeze({
|
|
419
|
+
__proto__: null,
|
|
420
|
+
hideNativeComponents: hideNativeComponents,
|
|
421
|
+
hideSplashScreen: hideSplashScreen,
|
|
422
|
+
navigationBar: navigationBar,
|
|
423
|
+
setOrientation: setOrientation,
|
|
424
|
+
setPinchToZoom: setPinchToZoom,
|
|
425
|
+
setPullToRefresh: setPullToRefresh,
|
|
426
|
+
showNativeComponents: showNativeComponents,
|
|
427
|
+
statusBar: statusBar
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* Navigation Module
|
|
432
|
+
*
|
|
433
|
+
* Control in-app navigation: go back, go forward, navigate to URLs,
|
|
434
|
+
* open external browser, and close the app.
|
|
435
|
+
*/
|
|
436
|
+
/**
|
|
437
|
+
* Navigate the WebView back one page in history.
|
|
438
|
+
* No-op if there's no back history.
|
|
439
|
+
*
|
|
440
|
+
* @example
|
|
441
|
+
* ```js
|
|
442
|
+
* nativine.navigation.goBack();
|
|
443
|
+
* ```
|
|
444
|
+
*/
|
|
445
|
+
function goBack() {
|
|
446
|
+
if (!isNativeApp) {
|
|
447
|
+
window.history.back();
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
callNativeSync('goBack');
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* Navigate the WebView forward one page in history.
|
|
454
|
+
* No-op if there's no forward history.
|
|
455
|
+
*
|
|
456
|
+
* @example
|
|
457
|
+
* ```js
|
|
458
|
+
* nativine.navigation.goForward();
|
|
459
|
+
* ```
|
|
460
|
+
*/
|
|
461
|
+
function goForward() {
|
|
462
|
+
if (!isNativeApp) {
|
|
463
|
+
window.history.forward();
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
callNativeSync('goForward');
|
|
467
|
+
}
|
|
468
|
+
/**
|
|
469
|
+
* Navigate the WebView to a specific URL.
|
|
470
|
+
* Supports both absolute URLs and relative paths.
|
|
471
|
+
*
|
|
472
|
+
* @param url - The URL or path to navigate to
|
|
473
|
+
*
|
|
474
|
+
* @example
|
|
475
|
+
* ```js
|
|
476
|
+
* nativine.navigation.navigate('/products');
|
|
477
|
+
* nativine.navigation.navigate('https://example.com/page');
|
|
478
|
+
* ```
|
|
479
|
+
*/
|
|
480
|
+
function navigate(url) {
|
|
481
|
+
if (!isNativeApp) {
|
|
482
|
+
window.location.href = url;
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
callNativeSync('navigate', { url });
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
488
|
+
* Open a URL in the device's default external browser.
|
|
489
|
+
* The user leaves the app temporarily.
|
|
490
|
+
*
|
|
491
|
+
* @param url - The URL to open externally
|
|
492
|
+
*
|
|
493
|
+
* @example
|
|
494
|
+
* ```js
|
|
495
|
+
* nativine.navigation.openInBrowser('https://docs.nativine.com');
|
|
496
|
+
* ```
|
|
497
|
+
*/
|
|
498
|
+
function openInBrowser(url) {
|
|
499
|
+
if (!isNativeApp) {
|
|
500
|
+
window.open(url, '_blank');
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
callNativeSync('openInBrowser', { url });
|
|
504
|
+
}
|
|
505
|
+
/**
|
|
506
|
+
* Close the app. On Android, this finishes the Activity.
|
|
507
|
+
*
|
|
508
|
+
* @example
|
|
509
|
+
* ```js
|
|
510
|
+
* nativine.navigation.closeApp();
|
|
511
|
+
* ```
|
|
512
|
+
*/
|
|
513
|
+
function closeApp() {
|
|
514
|
+
callNativeSync('closeApp');
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
var navigation = /*#__PURE__*/Object.freeze({
|
|
518
|
+
__proto__: null,
|
|
519
|
+
closeApp: closeApp,
|
|
520
|
+
goBack: goBack,
|
|
521
|
+
goForward: goForward,
|
|
522
|
+
navigate: navigate,
|
|
523
|
+
openInBrowser: openInBrowser
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
/**
|
|
527
|
+
* Haptics Module
|
|
528
|
+
*
|
|
529
|
+
* Trigger device vibrations and haptic feedback patterns.
|
|
530
|
+
*/
|
|
531
|
+
/**
|
|
532
|
+
* Vibrate the device for a specified duration.
|
|
533
|
+
*
|
|
534
|
+
* @param durationMs - Duration in milliseconds (default: 100ms)
|
|
535
|
+
*
|
|
536
|
+
* @example
|
|
537
|
+
* ```js
|
|
538
|
+
* nativine.haptics.vibrate(200);
|
|
539
|
+
* ```
|
|
540
|
+
*/
|
|
541
|
+
function vibrate(durationMs = 100) {
|
|
542
|
+
if (!isNativeApp) {
|
|
543
|
+
// Web Vibration API fallback
|
|
544
|
+
if (typeof navigator !== 'undefined' && navigator.vibrate) {
|
|
545
|
+
navigator.vibrate(durationMs);
|
|
546
|
+
}
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
callNativeSync('vibrate', { duration: durationMs });
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* Trigger a predefined haptic feedback pattern.
|
|
553
|
+
*
|
|
554
|
+
* @param type - The type of haptic feedback
|
|
555
|
+
*
|
|
556
|
+
* Feedback types:
|
|
557
|
+
* - `'light'` — Subtle tap (e.g., toggle switch)
|
|
558
|
+
* - `'medium'` — Standard tap (e.g., button press)
|
|
559
|
+
* - `'heavy'` — Strong tap (e.g., action confirmation)
|
|
560
|
+
* - `'success'` — Success pattern (double tap)
|
|
561
|
+
* - `'error'` — Error pattern (triple tap)
|
|
562
|
+
* - `'warning'` — Warning pattern
|
|
563
|
+
* - `'selection'` — Selection change (lightest)
|
|
564
|
+
*
|
|
565
|
+
* @example
|
|
566
|
+
* ```js
|
|
567
|
+
* // On button click
|
|
568
|
+
* nativine.haptics.feedback('medium');
|
|
569
|
+
*
|
|
570
|
+
* // On form validation error
|
|
571
|
+
* nativine.haptics.feedback('error');
|
|
572
|
+
*
|
|
573
|
+
* // On successful payment
|
|
574
|
+
* nativine.haptics.feedback('success');
|
|
575
|
+
* ```
|
|
576
|
+
*/
|
|
577
|
+
function feedback(type = 'medium') {
|
|
578
|
+
if (!isNativeApp) {
|
|
579
|
+
// Web fallback: simple vibration pattern
|
|
580
|
+
if (typeof navigator !== 'undefined' && navigator.vibrate) {
|
|
581
|
+
const patterns = {
|
|
582
|
+
light: 10,
|
|
583
|
+
medium: 30,
|
|
584
|
+
heavy: 50,
|
|
585
|
+
success: [30, 50, 30],
|
|
586
|
+
error: [30, 30, 30, 30, 30],
|
|
587
|
+
warning: [30, 50, 50],
|
|
588
|
+
selection: 5,
|
|
589
|
+
};
|
|
590
|
+
navigator.vibrate(patterns[type] || 30);
|
|
591
|
+
}
|
|
592
|
+
return;
|
|
593
|
+
}
|
|
594
|
+
callNativeSync('hapticFeedback', { type });
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
var haptics = /*#__PURE__*/Object.freeze({
|
|
598
|
+
__proto__: null,
|
|
599
|
+
feedback: feedback,
|
|
600
|
+
vibrate: vibrate
|
|
601
|
+
});
|
|
602
|
+
|
|
603
|
+
/**
|
|
604
|
+
* Storage Module
|
|
605
|
+
*
|
|
606
|
+
* Persistent key-value storage that survives WebView cache clears.
|
|
607
|
+
* Data is stored in Android SharedPreferences / iOS UserDefaults,
|
|
608
|
+
* not in the WebView's localStorage.
|
|
609
|
+
*/
|
|
610
|
+
/**
|
|
611
|
+
* Store a value persistently in native storage.
|
|
612
|
+
* This data persists even when the WebView cache is cleared.
|
|
613
|
+
*
|
|
614
|
+
* @param key - The storage key
|
|
615
|
+
* @param value - The value to store (will be serialized to string)
|
|
616
|
+
*
|
|
617
|
+
* @example
|
|
618
|
+
* ```js
|
|
619
|
+
* await nativine.storage.set('auth_token', 'abc123');
|
|
620
|
+
* await nativine.storage.set('user', JSON.stringify({ name: 'John' }));
|
|
621
|
+
* ```
|
|
622
|
+
*/
|
|
623
|
+
function set(key, value) {
|
|
624
|
+
if (!isNativeApp) {
|
|
625
|
+
try {
|
|
626
|
+
localStorage.setItem(`nativine_${key}`, value);
|
|
627
|
+
}
|
|
628
|
+
catch (e) { /* quota exceeded */ }
|
|
629
|
+
return;
|
|
630
|
+
}
|
|
631
|
+
if (isAndroid) {
|
|
632
|
+
// Direct call — AppJsBridge.setLocalData() is synchronous
|
|
633
|
+
const bridge = window.nativine;
|
|
634
|
+
if (bridge && typeof bridge.setLocalData === 'function') {
|
|
635
|
+
bridge.setLocalData(key, value);
|
|
636
|
+
return;
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
callNativeSync('setLocalData', { key, value });
|
|
640
|
+
}
|
|
641
|
+
/**
|
|
642
|
+
* Retrieve a value from native persistent storage.
|
|
643
|
+
*
|
|
644
|
+
* @param key - The storage key
|
|
645
|
+
* @param defaultValue - Value to return if key doesn't exist (default: '')
|
|
646
|
+
* @returns The stored value, or defaultValue if not found
|
|
647
|
+
*
|
|
648
|
+
* @example
|
|
649
|
+
* ```js
|
|
650
|
+
* const token = nativine.storage.get('auth_token');
|
|
651
|
+
* const user = JSON.parse(nativine.storage.get('user', '{}'));
|
|
652
|
+
* ```
|
|
653
|
+
*/
|
|
654
|
+
function get(key, defaultValue = '') {
|
|
655
|
+
if (!isNativeApp) {
|
|
656
|
+
try {
|
|
657
|
+
return localStorage.getItem(`nativine_${key}`) || defaultValue;
|
|
658
|
+
}
|
|
659
|
+
catch (_a) {
|
|
660
|
+
return defaultValue;
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
if (isAndroid) {
|
|
664
|
+
// Direct synchronous return via @JavascriptInterface
|
|
665
|
+
const bridge = window.nativine;
|
|
666
|
+
if (bridge && typeof bridge.getLocalData === 'function') {
|
|
667
|
+
return bridge.getLocalData(key, defaultValue);
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
return defaultValue;
|
|
671
|
+
}
|
|
672
|
+
/**
|
|
673
|
+
* Remove a specific key from native persistent storage.
|
|
674
|
+
*
|
|
675
|
+
* @param key - The storage key to remove
|
|
676
|
+
*
|
|
677
|
+
* @example
|
|
678
|
+
* ```js
|
|
679
|
+
* nativine.storage.remove('auth_token');
|
|
680
|
+
* ```
|
|
681
|
+
*/
|
|
682
|
+
function remove(key) {
|
|
683
|
+
if (!isNativeApp) {
|
|
684
|
+
try {
|
|
685
|
+
localStorage.removeItem(`nativine_${key}`);
|
|
686
|
+
}
|
|
687
|
+
catch ( /* ignore */_a) { /* ignore */ }
|
|
688
|
+
return;
|
|
689
|
+
}
|
|
690
|
+
if (isAndroid) {
|
|
691
|
+
const bridge = window.nativine;
|
|
692
|
+
if (bridge && typeof bridge.removeLocalData === 'function') {
|
|
693
|
+
bridge.removeLocalData(key);
|
|
694
|
+
return;
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
callNativeSync('removeLocalData', { key });
|
|
698
|
+
}
|
|
699
|
+
/**
|
|
700
|
+
* Clear all data from native persistent storage.
|
|
701
|
+
*
|
|
702
|
+
* @example
|
|
703
|
+
* ```js
|
|
704
|
+
* // On logout
|
|
705
|
+
* nativine.storage.clear();
|
|
706
|
+
* ```
|
|
707
|
+
*/
|
|
708
|
+
function clear$1() {
|
|
709
|
+
if (!isNativeApp) {
|
|
710
|
+
try {
|
|
711
|
+
const keys = Object.keys(localStorage).filter(k => k.startsWith('nativine_'));
|
|
712
|
+
keys.forEach(k => localStorage.removeItem(k));
|
|
713
|
+
}
|
|
714
|
+
catch ( /* ignore */_a) { /* ignore */ }
|
|
715
|
+
return;
|
|
716
|
+
}
|
|
717
|
+
if (isAndroid) {
|
|
718
|
+
const bridge = window.nativine;
|
|
719
|
+
if (bridge && typeof bridge.clearLocalData === 'function') {
|
|
720
|
+
bridge.clearLocalData();
|
|
721
|
+
return;
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
callNativeSync('clearLocalData');
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
var storage = /*#__PURE__*/Object.freeze({
|
|
728
|
+
__proto__: null,
|
|
729
|
+
clear: clear$1,
|
|
730
|
+
get: get,
|
|
731
|
+
remove: remove,
|
|
732
|
+
set: set
|
|
733
|
+
});
|
|
734
|
+
|
|
735
|
+
/**
|
|
736
|
+
* Share Module
|
|
737
|
+
*
|
|
738
|
+
* Trigger the native share sheet to share text, URLs, and files.
|
|
739
|
+
*/
|
|
740
|
+
/**
|
|
741
|
+
* Open the native share sheet with the specified content.
|
|
742
|
+
*
|
|
743
|
+
* @example
|
|
744
|
+
* ```js
|
|
745
|
+
* nativine.share.share({
|
|
746
|
+
* title: 'Check this out',
|
|
747
|
+
* text: 'Amazing app!',
|
|
748
|
+
* url: 'https://example.com'
|
|
749
|
+
* });
|
|
750
|
+
* ```
|
|
751
|
+
*/
|
|
752
|
+
function share(options) {
|
|
753
|
+
if (!isNativeApp) {
|
|
754
|
+
// Web Share API fallback
|
|
755
|
+
if (typeof navigator !== 'undefined' && navigator.share) {
|
|
756
|
+
navigator.share(options).catch(() => { });
|
|
757
|
+
}
|
|
758
|
+
return;
|
|
759
|
+
}
|
|
760
|
+
callNativeSync('share', options);
|
|
761
|
+
}
|
|
762
|
+
/**
|
|
763
|
+
* Share a file using the native share sheet.
|
|
764
|
+
*
|
|
765
|
+
* @example
|
|
766
|
+
* ```js
|
|
767
|
+
* nativine.share.shareFile({
|
|
768
|
+
* filePath: '/storage/emulated/0/Download/report.pdf',
|
|
769
|
+
* mimeType: 'application/pdf'
|
|
770
|
+
* });
|
|
771
|
+
* ```
|
|
772
|
+
*/
|
|
773
|
+
function shareFile(options) {
|
|
774
|
+
callNativeSync('shareFile', options);
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
/**
|
|
778
|
+
* Auth Module
|
|
779
|
+
*
|
|
780
|
+
* Native Google Sign-In integration. Triggers the native Google Sign-In flow
|
|
781
|
+
* and returns user credentials to your web app.
|
|
782
|
+
*/
|
|
783
|
+
/**
|
|
784
|
+
* Trigger the native Google Sign-In flow.
|
|
785
|
+
* Returns user credentials when the user completes sign-in.
|
|
786
|
+
*
|
|
787
|
+
* @returns Promise resolving with Google user credentials
|
|
788
|
+
*
|
|
789
|
+
* @example
|
|
790
|
+
* ```js
|
|
791
|
+
* try {
|
|
792
|
+
* const user = await nativine.auth.googleSignIn();
|
|
793
|
+
* console.log(user.email); // "john@gmail.com"
|
|
794
|
+
* console.log(user.idToken); // Send to your backend for verification
|
|
795
|
+
* } catch (err) {
|
|
796
|
+
* console.log('Sign-in cancelled or failed');
|
|
797
|
+
* }
|
|
798
|
+
* ```
|
|
799
|
+
*/
|
|
800
|
+
async function googleSignIn() {
|
|
801
|
+
if (!isNativeApp) {
|
|
802
|
+
throw new Error('nativine.auth.googleSignIn() is only available inside a Nativine app.');
|
|
803
|
+
}
|
|
804
|
+
return callNativeAsync('googleSignIn');
|
|
805
|
+
}
|
|
806
|
+
/**
|
|
807
|
+
* Sign out of the current Google account.
|
|
808
|
+
*
|
|
809
|
+
* @example
|
|
810
|
+
* ```js
|
|
811
|
+
* await nativine.auth.googleSignOut();
|
|
812
|
+
* ```
|
|
813
|
+
*/
|
|
814
|
+
function googleSignOut() {
|
|
815
|
+
if (!isNativeApp)
|
|
816
|
+
return;
|
|
817
|
+
if (isAndroid) {
|
|
818
|
+
const bridge = window.NativineAndroid;
|
|
819
|
+
if (bridge && typeof bridge.postMessage === 'function') {
|
|
820
|
+
bridge.postMessage(JSON.stringify({ action: 'google_signout' }));
|
|
821
|
+
return;
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
callNativeSync('googleSignOut');
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
var auth = /*#__PURE__*/Object.freeze({
|
|
828
|
+
__proto__: null,
|
|
829
|
+
googleSignIn: googleSignIn,
|
|
830
|
+
googleSignOut: googleSignOut
|
|
831
|
+
});
|
|
832
|
+
|
|
833
|
+
/**
|
|
834
|
+
* Biometrics Module
|
|
835
|
+
*
|
|
836
|
+
* Trigger native biometric authentication (fingerprint, face recognition, iris scan).
|
|
837
|
+
*/
|
|
838
|
+
/**
|
|
839
|
+
* Check if biometric authentication is available on this device.
|
|
840
|
+
*
|
|
841
|
+
* @returns Promise resolving with availability info
|
|
842
|
+
*
|
|
843
|
+
* @example
|
|
844
|
+
* ```js
|
|
845
|
+
* const { available, biometryType } = await nativine.biometrics.isAvailable();
|
|
846
|
+
* if (available) {
|
|
847
|
+
* console.log(`Biometric type: ${biometryType}`); // "fingerprint"
|
|
848
|
+
* }
|
|
849
|
+
* ```
|
|
850
|
+
*/
|
|
851
|
+
async function isAvailable$1() {
|
|
852
|
+
if (!isNativeApp) {
|
|
853
|
+
return { available: false, biometryType: 'none' };
|
|
854
|
+
}
|
|
855
|
+
return callNativeAsync('isBiometricAvailable');
|
|
856
|
+
}
|
|
857
|
+
/**
|
|
858
|
+
* Trigger biometric authentication.
|
|
859
|
+
*
|
|
860
|
+
* @param options - Configuration for the authentication prompt
|
|
861
|
+
* @returns Promise resolving with the authentication result
|
|
862
|
+
*
|
|
863
|
+
* @example
|
|
864
|
+
* ```js
|
|
865
|
+
* const result = await nativine.biometrics.authenticate({
|
|
866
|
+
* reason: 'Verify your identity to access settings',
|
|
867
|
+
* allowFallback: true
|
|
868
|
+
* });
|
|
869
|
+
*
|
|
870
|
+
* if (result.success) {
|
|
871
|
+
* // User authenticated
|
|
872
|
+
* showSensitiveContent();
|
|
873
|
+
* }
|
|
874
|
+
* ```
|
|
875
|
+
*/
|
|
876
|
+
async function authenticate(options = {}) {
|
|
877
|
+
if (!isNativeApp) {
|
|
878
|
+
throw new Error('nativine.biometrics.authenticate() is only available inside a Nativine app.');
|
|
879
|
+
}
|
|
880
|
+
return callNativeAsync('authenticateBiometric', options);
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
var biometrics = /*#__PURE__*/Object.freeze({
|
|
884
|
+
__proto__: null,
|
|
885
|
+
authenticate: authenticate,
|
|
886
|
+
isAvailable: isAvailable$1
|
|
887
|
+
});
|
|
888
|
+
|
|
889
|
+
/**
|
|
890
|
+
* Contacts Module
|
|
891
|
+
*
|
|
892
|
+
* Access the device's native contact list (requires user permission).
|
|
893
|
+
*/
|
|
894
|
+
/**
|
|
895
|
+
* Retrieve the user's contacts from the native contact book.
|
|
896
|
+
* Prompts for permission if not already granted.
|
|
897
|
+
*
|
|
898
|
+
* @returns Promise resolving with an array of contacts
|
|
899
|
+
*
|
|
900
|
+
* @example
|
|
901
|
+
* ```js
|
|
902
|
+
* const contacts = await nativine.contacts.getAll();
|
|
903
|
+
* contacts.forEach(c => {
|
|
904
|
+
* console.log(`${c.name}: ${c.phone}`);
|
|
905
|
+
* });
|
|
906
|
+
* ```
|
|
907
|
+
*/
|
|
908
|
+
async function getAll() {
|
|
909
|
+
if (!isNativeApp) {
|
|
910
|
+
// Web Contacts API fallback (if available)
|
|
911
|
+
if ('contacts' in navigator && 'ContactsManager' in window) {
|
|
912
|
+
try {
|
|
913
|
+
const props = ['name', 'tel', 'email'];
|
|
914
|
+
const contacts = await navigator.contacts.select(props, { multiple: true });
|
|
915
|
+
return contacts.map((c) => {
|
|
916
|
+
var _a, _b, _c;
|
|
917
|
+
return ({
|
|
918
|
+
name: ((_a = c.name) === null || _a === void 0 ? void 0 : _a[0]) || '',
|
|
919
|
+
phone: ((_b = c.tel) === null || _b === void 0 ? void 0 : _b[0]) || '',
|
|
920
|
+
email: ((_c = c.email) === null || _c === void 0 ? void 0 : _c[0]) || '',
|
|
921
|
+
});
|
|
922
|
+
});
|
|
923
|
+
}
|
|
924
|
+
catch (_a) {
|
|
925
|
+
return [];
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
return [];
|
|
929
|
+
}
|
|
930
|
+
return callNativeAsync('getContacts');
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
var contacts = /*#__PURE__*/Object.freeze({
|
|
934
|
+
__proto__: null,
|
|
935
|
+
getAll: getAll
|
|
936
|
+
});
|
|
937
|
+
|
|
938
|
+
/**
|
|
939
|
+
* Clipboard Module
|
|
940
|
+
*
|
|
941
|
+
* Read from and write to the device clipboard.
|
|
942
|
+
*/
|
|
943
|
+
/**
|
|
944
|
+
* Copy text to the device clipboard.
|
|
945
|
+
*
|
|
946
|
+
* @param text - The text to copy
|
|
947
|
+
*
|
|
948
|
+
* @example
|
|
949
|
+
* ```js
|
|
950
|
+
* await nativine.clipboard.copy('https://example.com/share/abc123');
|
|
951
|
+
* ```
|
|
952
|
+
*/
|
|
953
|
+
async function copy(text) {
|
|
954
|
+
if (!isNativeApp) {
|
|
955
|
+
// Web Clipboard API fallback
|
|
956
|
+
if (navigator.clipboard && navigator.clipboard.writeText) {
|
|
957
|
+
await navigator.clipboard.writeText(text);
|
|
958
|
+
}
|
|
959
|
+
else {
|
|
960
|
+
// Legacy fallback
|
|
961
|
+
const textarea = document.createElement('textarea');
|
|
962
|
+
textarea.value = text;
|
|
963
|
+
textarea.style.position = 'fixed';
|
|
964
|
+
textarea.style.opacity = '0';
|
|
965
|
+
document.body.appendChild(textarea);
|
|
966
|
+
textarea.select();
|
|
967
|
+
document.execCommand('copy');
|
|
968
|
+
document.body.removeChild(textarea);
|
|
969
|
+
}
|
|
970
|
+
return;
|
|
971
|
+
}
|
|
972
|
+
callNativeSync('copyToClipboard', { text });
|
|
973
|
+
}
|
|
974
|
+
/**
|
|
975
|
+
* Read text from the device clipboard.
|
|
976
|
+
*
|
|
977
|
+
* @returns Promise resolving with the clipboard text content
|
|
978
|
+
*
|
|
979
|
+
* @example
|
|
980
|
+
* ```js
|
|
981
|
+
* const text = await nativine.clipboard.read();
|
|
982
|
+
* console.log('Clipboard:', text);
|
|
983
|
+
* ```
|
|
984
|
+
*/
|
|
985
|
+
async function read() {
|
|
986
|
+
if (!isNativeApp) {
|
|
987
|
+
// Web Clipboard API fallback
|
|
988
|
+
if (navigator.clipboard && navigator.clipboard.readText) {
|
|
989
|
+
return navigator.clipboard.readText();
|
|
990
|
+
}
|
|
991
|
+
return '';
|
|
992
|
+
}
|
|
993
|
+
return callNativeAsync('readClipboard');
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
var clipboard = /*#__PURE__*/Object.freeze({
|
|
997
|
+
__proto__: null,
|
|
998
|
+
copy: copy,
|
|
999
|
+
read: read
|
|
1000
|
+
});
|
|
1001
|
+
|
|
1002
|
+
/**
|
|
1003
|
+
* Downloads Module
|
|
1004
|
+
*
|
|
1005
|
+
* Trigger native file downloads using the device's download manager.
|
|
1006
|
+
*/
|
|
1007
|
+
/**
|
|
1008
|
+
* Download a file using the native download manager.
|
|
1009
|
+
* Shows a notification with download progress on Android.
|
|
1010
|
+
*
|
|
1011
|
+
* @param options - Download configuration
|
|
1012
|
+
*
|
|
1013
|
+
* @example
|
|
1014
|
+
* ```js
|
|
1015
|
+
* nativine.downloads.downloadFile({
|
|
1016
|
+
* url: 'https://example.com/report.pdf',
|
|
1017
|
+
* filename: 'monthly-report.pdf',
|
|
1018
|
+
* openAfterDownload: true
|
|
1019
|
+
* });
|
|
1020
|
+
* ```
|
|
1021
|
+
*/
|
|
1022
|
+
function downloadFile(options) {
|
|
1023
|
+
if (!isNativeApp) {
|
|
1024
|
+
// Web fallback: trigger download via anchor tag
|
|
1025
|
+
const a = document.createElement('a');
|
|
1026
|
+
a.href = options.url;
|
|
1027
|
+
a.download = options.filename || '';
|
|
1028
|
+
a.target = '_blank';
|
|
1029
|
+
document.body.appendChild(a);
|
|
1030
|
+
a.click();
|
|
1031
|
+
document.body.removeChild(a);
|
|
1032
|
+
return;
|
|
1033
|
+
}
|
|
1034
|
+
callNativeSync('downloadFile', options);
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
var downloads = /*#__PURE__*/Object.freeze({
|
|
1038
|
+
__proto__: null,
|
|
1039
|
+
downloadFile: downloadFile
|
|
1040
|
+
});
|
|
1041
|
+
|
|
1042
|
+
/**
|
|
1043
|
+
* Camera / Scanner Module
|
|
1044
|
+
*
|
|
1045
|
+
* Access the device camera for barcode and QR code scanning.
|
|
1046
|
+
*/
|
|
1047
|
+
/**
|
|
1048
|
+
* Open the native barcode/QR code scanner.
|
|
1049
|
+
*
|
|
1050
|
+
* @param options - Scanner configuration
|
|
1051
|
+
* @returns Promise resolving with the scanned code data
|
|
1052
|
+
*
|
|
1053
|
+
* @example
|
|
1054
|
+
* ```js
|
|
1055
|
+
* try {
|
|
1056
|
+
* const result = await nativine.scanner.scan();
|
|
1057
|
+
* console.log(result.value); // "https://example.com"
|
|
1058
|
+
* console.log(result.format); // "QR_CODE"
|
|
1059
|
+
* } catch (err) {
|
|
1060
|
+
* console.log('Scan cancelled');
|
|
1061
|
+
* }
|
|
1062
|
+
* ```
|
|
1063
|
+
*/
|
|
1064
|
+
async function scan(options = {}) {
|
|
1065
|
+
if (!isNativeApp) {
|
|
1066
|
+
throw new Error('nativine.scanner.scan() is only available inside a Nativine app.');
|
|
1067
|
+
}
|
|
1068
|
+
return callNativeAsync('scanBarcode', options);
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
var camera = /*#__PURE__*/Object.freeze({
|
|
1072
|
+
__proto__: null,
|
|
1073
|
+
scan: scan
|
|
1074
|
+
});
|
|
1075
|
+
|
|
1076
|
+
/**
|
|
1077
|
+
* Location Module
|
|
1078
|
+
*
|
|
1079
|
+
* Access the device's GPS location.
|
|
1080
|
+
*/
|
|
1081
|
+
/**
|
|
1082
|
+
* Get the device's current GPS location.
|
|
1083
|
+
* Prompts for location permission if not already granted.
|
|
1084
|
+
*
|
|
1085
|
+
* @returns Promise resolving with location coordinates
|
|
1086
|
+
*
|
|
1087
|
+
* @example
|
|
1088
|
+
* ```js
|
|
1089
|
+
* const loc = await nativine.location.getCurrent();
|
|
1090
|
+
* console.log(`Lat: ${loc.latitude}, Lng: ${loc.longitude}`);
|
|
1091
|
+
* console.log(`Accuracy: ${loc.accuracy}m`);
|
|
1092
|
+
* ```
|
|
1093
|
+
*/
|
|
1094
|
+
async function getCurrent() {
|
|
1095
|
+
if (!isNativeApp) {
|
|
1096
|
+
// Web Geolocation API fallback
|
|
1097
|
+
return new Promise((resolve, reject) => {
|
|
1098
|
+
if (!navigator.geolocation) {
|
|
1099
|
+
reject(new Error('Geolocation not supported in this browser'));
|
|
1100
|
+
return;
|
|
1101
|
+
}
|
|
1102
|
+
navigator.geolocation.getCurrentPosition((pos) => resolve({
|
|
1103
|
+
latitude: pos.coords.latitude,
|
|
1104
|
+
longitude: pos.coords.longitude,
|
|
1105
|
+
accuracy: pos.coords.accuracy,
|
|
1106
|
+
altitude: pos.coords.altitude || undefined,
|
|
1107
|
+
speed: pos.coords.speed || undefined,
|
|
1108
|
+
}), (err) => reject(new Error(err.message)), { enableHighAccuracy: true, timeout: 15000, maximumAge: 0 });
|
|
1109
|
+
});
|
|
1110
|
+
}
|
|
1111
|
+
return callNativeAsync('getCurrentLocation');
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
var location = /*#__PURE__*/Object.freeze({
|
|
1115
|
+
__proto__: null,
|
|
1116
|
+
getCurrent: getCurrent
|
|
1117
|
+
});
|
|
1118
|
+
|
|
1119
|
+
/**
|
|
1120
|
+
* Network Module
|
|
1121
|
+
*
|
|
1122
|
+
* Check connectivity status and listen for network changes.
|
|
1123
|
+
*/
|
|
1124
|
+
const _listeners = [];
|
|
1125
|
+
/**
|
|
1126
|
+
* Check if the device currently has network connectivity.
|
|
1127
|
+
*
|
|
1128
|
+
* @returns Promise resolving with connectivity status
|
|
1129
|
+
*
|
|
1130
|
+
* @example
|
|
1131
|
+
* ```js
|
|
1132
|
+
* const status = await nativine.network.isOnline();
|
|
1133
|
+
* if (!status.online) {
|
|
1134
|
+
* showOfflineBanner();
|
|
1135
|
+
* }
|
|
1136
|
+
* ```
|
|
1137
|
+
*/
|
|
1138
|
+
async function isOnline() {
|
|
1139
|
+
if (!isNativeApp) {
|
|
1140
|
+
return {
|
|
1141
|
+
online: typeof navigator !== 'undefined' ? navigator.onLine : true,
|
|
1142
|
+
type: 'unknown',
|
|
1143
|
+
};
|
|
1144
|
+
}
|
|
1145
|
+
return callNativeAsync('getConnectivityStatus');
|
|
1146
|
+
}
|
|
1147
|
+
/**
|
|
1148
|
+
* Listen for network connectivity changes.
|
|
1149
|
+
*
|
|
1150
|
+
* @param callback - Function called when connectivity changes
|
|
1151
|
+
* @returns Unsubscribe function to stop listening
|
|
1152
|
+
*
|
|
1153
|
+
* @example
|
|
1154
|
+
* ```js
|
|
1155
|
+
* const unsubscribe = nativine.network.onConnectivityChange((status) => {
|
|
1156
|
+
* if (!status.online) {
|
|
1157
|
+
* showOfflineBanner();
|
|
1158
|
+
* } else {
|
|
1159
|
+
* hideOfflineBanner();
|
|
1160
|
+
* }
|
|
1161
|
+
* });
|
|
1162
|
+
*
|
|
1163
|
+
* // Later: stop listening
|
|
1164
|
+
* unsubscribe();
|
|
1165
|
+
* ```
|
|
1166
|
+
*/
|
|
1167
|
+
function onConnectivityChange(callback) {
|
|
1168
|
+
_listeners.push(callback);
|
|
1169
|
+
// Set up web fallback listener
|
|
1170
|
+
if (!isNativeApp) {
|
|
1171
|
+
const onlineHandler = () => callback({ online: true, type: 'unknown' });
|
|
1172
|
+
const offlineHandler = () => callback({ online: false, type: 'none' });
|
|
1173
|
+
window.addEventListener('online', onlineHandler);
|
|
1174
|
+
window.addEventListener('offline', offlineHandler);
|
|
1175
|
+
return () => {
|
|
1176
|
+
const idx = _listeners.indexOf(callback);
|
|
1177
|
+
if (idx !== -1)
|
|
1178
|
+
_listeners.splice(idx, 1);
|
|
1179
|
+
window.removeEventListener('online', onlineHandler);
|
|
1180
|
+
window.removeEventListener('offline', offlineHandler);
|
|
1181
|
+
};
|
|
1182
|
+
}
|
|
1183
|
+
// Register native listener
|
|
1184
|
+
callNativeSync('registerConnectivityListener');
|
|
1185
|
+
return () => {
|
|
1186
|
+
const idx = _listeners.indexOf(callback);
|
|
1187
|
+
if (idx !== -1)
|
|
1188
|
+
_listeners.splice(idx, 1);
|
|
1189
|
+
if (_listeners.length === 0) {
|
|
1190
|
+
callNativeSync('unregisterConnectivityListener');
|
|
1191
|
+
}
|
|
1192
|
+
};
|
|
1193
|
+
}
|
|
1194
|
+
/**
|
|
1195
|
+
* Internal: Called by the native side when connectivity changes.
|
|
1196
|
+
* Dispatches to all registered listeners.
|
|
1197
|
+
* @internal
|
|
1198
|
+
*/
|
|
1199
|
+
function _onConnectivityChanged(status) {
|
|
1200
|
+
_listeners.forEach(cb => {
|
|
1201
|
+
try {
|
|
1202
|
+
cb(status);
|
|
1203
|
+
}
|
|
1204
|
+
catch (e) {
|
|
1205
|
+
console.error('[nativine] Connectivity listener error:', e);
|
|
1206
|
+
}
|
|
1207
|
+
});
|
|
1208
|
+
}
|
|
1209
|
+
// Register global handler for native callbacks
|
|
1210
|
+
if (typeof window !== 'undefined') {
|
|
1211
|
+
window.__nativine_onConnectivityChanged = (json) => {
|
|
1212
|
+
try {
|
|
1213
|
+
const status = typeof json === 'string' ? JSON.parse(json) : json;
|
|
1214
|
+
_onConnectivityChanged(status);
|
|
1215
|
+
}
|
|
1216
|
+
catch (e) { /* ignore */ }
|
|
1217
|
+
};
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
var network = /*#__PURE__*/Object.freeze({
|
|
1221
|
+
__proto__: null,
|
|
1222
|
+
_onConnectivityChanged: _onConnectivityChanged,
|
|
1223
|
+
isOnline: isOnline,
|
|
1224
|
+
onConnectivityChange: onConnectivityChange
|
|
1225
|
+
});
|
|
1226
|
+
|
|
1227
|
+
/**
|
|
1228
|
+
* Cache Module
|
|
1229
|
+
*
|
|
1230
|
+
* Clear WebView cache and cookies.
|
|
1231
|
+
*/
|
|
1232
|
+
/**
|
|
1233
|
+
* Clear the WebView cache (CSS, JS, images, etc.).
|
|
1234
|
+
* Shows a confirmation dialog to the user.
|
|
1235
|
+
*
|
|
1236
|
+
* @example
|
|
1237
|
+
* ```js
|
|
1238
|
+
* nativine.cache.clear();
|
|
1239
|
+
* ```
|
|
1240
|
+
*/
|
|
1241
|
+
function clear() {
|
|
1242
|
+
if (!isNativeApp)
|
|
1243
|
+
return;
|
|
1244
|
+
callNativeSync('clear_cache');
|
|
1245
|
+
}
|
|
1246
|
+
/**
|
|
1247
|
+
* Clear all WebView cookies.
|
|
1248
|
+
* Useful for logout flows to ensure session data is wiped.
|
|
1249
|
+
*
|
|
1250
|
+
* @example
|
|
1251
|
+
* ```js
|
|
1252
|
+
* nativine.cache.clearCookies();
|
|
1253
|
+
* ```
|
|
1254
|
+
*/
|
|
1255
|
+
function clearCookies() {
|
|
1256
|
+
if (!isNativeApp) {
|
|
1257
|
+
// Web fallback: clear cookies via document.cookie
|
|
1258
|
+
document.cookie.split(';').forEach(cookie => {
|
|
1259
|
+
const name = cookie.split('=')[0].trim();
|
|
1260
|
+
document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/`;
|
|
1261
|
+
});
|
|
1262
|
+
return;
|
|
1263
|
+
}
|
|
1264
|
+
callNativeSync('clearCookies');
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
var cache = /*#__PURE__*/Object.freeze({
|
|
1268
|
+
__proto__: null,
|
|
1269
|
+
clear: clear,
|
|
1270
|
+
clearCookies: clearCookies
|
|
1271
|
+
});
|
|
1272
|
+
|
|
1273
|
+
/**
|
|
1274
|
+
* Print Module
|
|
1275
|
+
*
|
|
1276
|
+
* Trigger native print dialog for the current page.
|
|
1277
|
+
*/
|
|
1278
|
+
/**
|
|
1279
|
+
* Open the native print dialog for the current WebView content.
|
|
1280
|
+
*
|
|
1281
|
+
* @example
|
|
1282
|
+
* ```js
|
|
1283
|
+
* nativine.print();
|
|
1284
|
+
* ```
|
|
1285
|
+
*/
|
|
1286
|
+
function printPage() {
|
|
1287
|
+
if (!isNativeApp) {
|
|
1288
|
+
window.print();
|
|
1289
|
+
return;
|
|
1290
|
+
}
|
|
1291
|
+
callNativeSync('printPage');
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
/**
|
|
1295
|
+
* Screenshot Module
|
|
1296
|
+
*
|
|
1297
|
+
* Control screenshot protection (prevent screenshots of sensitive screens).
|
|
1298
|
+
*/
|
|
1299
|
+
/**
|
|
1300
|
+
* Enable or disable screenshot/screen recording protection.
|
|
1301
|
+
* When enabled, the app content appears black in screenshots and screen recordings.
|
|
1302
|
+
*
|
|
1303
|
+
* @param enabled - Whether to enable screenshot protection
|
|
1304
|
+
*
|
|
1305
|
+
* @example
|
|
1306
|
+
* ```js
|
|
1307
|
+
* // Protect a banking page
|
|
1308
|
+
* nativine.screenshot.setProtection(true);
|
|
1309
|
+
*
|
|
1310
|
+
* // Remove protection when leaving
|
|
1311
|
+
* nativine.screenshot.setProtection(false);
|
|
1312
|
+
* ```
|
|
1313
|
+
*/
|
|
1314
|
+
function setProtection(enabled) {
|
|
1315
|
+
if (!isNativeApp)
|
|
1316
|
+
return;
|
|
1317
|
+
callNativeSync('setScreenshotProtection', { enabled });
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
var screenshot = /*#__PURE__*/Object.freeze({
|
|
1321
|
+
__proto__: null,
|
|
1322
|
+
setProtection: setProtection
|
|
1323
|
+
});
|
|
1324
|
+
|
|
1325
|
+
/**
|
|
1326
|
+
* Reviews Module
|
|
1327
|
+
*
|
|
1328
|
+
* Trigger the native in-app review dialog (Google Play / App Store).
|
|
1329
|
+
*/
|
|
1330
|
+
/**
|
|
1331
|
+
* Request an in-app review from the user.
|
|
1332
|
+
* Uses Google Play In-App Review API (Android) or StoreKit (iOS).
|
|
1333
|
+
*
|
|
1334
|
+
* Note: The system may not show the dialog if the user has already reviewed
|
|
1335
|
+
* or if the request is too frequent. This is controlled by the platform.
|
|
1336
|
+
*
|
|
1337
|
+
* @example
|
|
1338
|
+
* ```js
|
|
1339
|
+
* // After a positive user interaction
|
|
1340
|
+
* nativine.reviews.request();
|
|
1341
|
+
* ```
|
|
1342
|
+
*/
|
|
1343
|
+
function request() {
|
|
1344
|
+
if (!isNativeApp)
|
|
1345
|
+
return;
|
|
1346
|
+
callNativeSync('requestAppReview');
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
var reviews = /*#__PURE__*/Object.freeze({
|
|
1350
|
+
__proto__: null,
|
|
1351
|
+
request: request
|
|
1352
|
+
});
|
|
1353
|
+
|
|
1354
|
+
/**
|
|
1355
|
+
* Updates Module
|
|
1356
|
+
*
|
|
1357
|
+
* Check for and trigger in-app updates (Android only).
|
|
1358
|
+
*/
|
|
1359
|
+
/**
|
|
1360
|
+
* Check for available app updates using the Android In-App Update API.
|
|
1361
|
+
* If an update is available, a native update UI will be shown.
|
|
1362
|
+
*
|
|
1363
|
+
* @example
|
|
1364
|
+
* ```js
|
|
1365
|
+
* nativine.updates.check();
|
|
1366
|
+
* ```
|
|
1367
|
+
*/
|
|
1368
|
+
function check() {
|
|
1369
|
+
if (!isNativeApp)
|
|
1370
|
+
return;
|
|
1371
|
+
callNativeSync('checkForUpdates');
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
var updates = /*#__PURE__*/Object.freeze({
|
|
1375
|
+
__proto__: null,
|
|
1376
|
+
check: check
|
|
1377
|
+
});
|
|
1378
|
+
|
|
1379
|
+
/**
|
|
1380
|
+
* Ads Module
|
|
1381
|
+
*
|
|
1382
|
+
* Control AdMob interstitial and rewarded ad display from your web app.
|
|
1383
|
+
*/
|
|
1384
|
+
/**
|
|
1385
|
+
* Show a fullscreen interstitial ad.
|
|
1386
|
+
* The ad must be pre-loaded by the native app.
|
|
1387
|
+
*
|
|
1388
|
+
* @example
|
|
1389
|
+
* ```js
|
|
1390
|
+
* // Show an ad between content transitions
|
|
1391
|
+
* nativine.ads.showInterstitial();
|
|
1392
|
+
* ```
|
|
1393
|
+
*/
|
|
1394
|
+
function showInterstitial() {
|
|
1395
|
+
if (!isNativeApp)
|
|
1396
|
+
return;
|
|
1397
|
+
callNativeSync('showInterstitialAd');
|
|
1398
|
+
}
|
|
1399
|
+
/**
|
|
1400
|
+
* Show a rewarded video ad.
|
|
1401
|
+
* Returns a Promise that resolves when the user finishes watching.
|
|
1402
|
+
*
|
|
1403
|
+
* @returns Promise resolving with the reward result
|
|
1404
|
+
*
|
|
1405
|
+
* @example
|
|
1406
|
+
* ```js
|
|
1407
|
+
* const result = await nativine.ads.showRewarded();
|
|
1408
|
+
* if (result.rewarded) {
|
|
1409
|
+
* // Grant premium access for 24 hours
|
|
1410
|
+
* unlockPremiumContent();
|
|
1411
|
+
* }
|
|
1412
|
+
* ```
|
|
1413
|
+
*/
|
|
1414
|
+
async function showRewarded() {
|
|
1415
|
+
if (!isNativeApp) {
|
|
1416
|
+
return { rewarded: false };
|
|
1417
|
+
}
|
|
1418
|
+
return callNativeAsync('showRewardedAd');
|
|
1419
|
+
}
|
|
1420
|
+
|
|
1421
|
+
var ads = /*#__PURE__*/Object.freeze({
|
|
1422
|
+
__proto__: null,
|
|
1423
|
+
showInterstitial: showInterstitial,
|
|
1424
|
+
showRewarded: showRewarded
|
|
1425
|
+
});
|
|
1426
|
+
|
|
1427
|
+
/**
|
|
1428
|
+
* OneSignal Module
|
|
1429
|
+
*
|
|
1430
|
+
* Interact with OneSignal push notification service from your web app.
|
|
1431
|
+
* Requires the OneSignal addon to be enabled in your Nativine app.
|
|
1432
|
+
*/
|
|
1433
|
+
/**
|
|
1434
|
+
* Set the OneSignal external user ID.
|
|
1435
|
+
* Links the device's push subscription to your backend user ID.
|
|
1436
|
+
*
|
|
1437
|
+
* @param userId - Your app's user identifier
|
|
1438
|
+
*
|
|
1439
|
+
* @example
|
|
1440
|
+
* ```js
|
|
1441
|
+
* // After user logs in
|
|
1442
|
+
* nativine.onesignal.setExternalUserId('user_12345');
|
|
1443
|
+
* ```
|
|
1444
|
+
*/
|
|
1445
|
+
function setExternalUserId(userId) {
|
|
1446
|
+
if (!isNativeApp)
|
|
1447
|
+
return;
|
|
1448
|
+
callNativeSync('onesignalSetExternalUserId', { userId });
|
|
1449
|
+
}
|
|
1450
|
+
/**
|
|
1451
|
+
* Send a tag (key-value pair) to OneSignal for audience segmentation.
|
|
1452
|
+
*
|
|
1453
|
+
* @param key - Tag key
|
|
1454
|
+
* @param value - Tag value
|
|
1455
|
+
*
|
|
1456
|
+
* @example
|
|
1457
|
+
* ```js
|
|
1458
|
+
* nativine.onesignal.sendTag('plan', 'premium');
|
|
1459
|
+
* nativine.onesignal.sendTag('language', 'en');
|
|
1460
|
+
* ```
|
|
1461
|
+
*/
|
|
1462
|
+
function sendTag(key, value) {
|
|
1463
|
+
if (!isNativeApp)
|
|
1464
|
+
return;
|
|
1465
|
+
callNativeSync('onesignalSendTag', { key, value });
|
|
1466
|
+
}
|
|
1467
|
+
/**
|
|
1468
|
+
* Send multiple tags at once to OneSignal.
|
|
1469
|
+
*
|
|
1470
|
+
* @param tags - Object with tag key-value pairs
|
|
1471
|
+
*
|
|
1472
|
+
* @example
|
|
1473
|
+
* ```js
|
|
1474
|
+
* nativine.onesignal.sendTags({
|
|
1475
|
+
* plan: 'premium',
|
|
1476
|
+
* language: 'en',
|
|
1477
|
+
* onboarded: 'true'
|
|
1478
|
+
* });
|
|
1479
|
+
* ```
|
|
1480
|
+
*/
|
|
1481
|
+
function sendTags(tags) {
|
|
1482
|
+
if (!isNativeApp)
|
|
1483
|
+
return;
|
|
1484
|
+
callNativeSync('onesignalSendTags', { tags });
|
|
1485
|
+
}
|
|
1486
|
+
/**
|
|
1487
|
+
* Get the OneSignal Player ID (push subscription ID) for this device.
|
|
1488
|
+
*
|
|
1489
|
+
* @returns Promise resolving with the player ID string
|
|
1490
|
+
*
|
|
1491
|
+
* @example
|
|
1492
|
+
* ```js
|
|
1493
|
+
* const playerId = await nativine.onesignal.getPlayerId();
|
|
1494
|
+
* // Send to your backend for targeted push notifications
|
|
1495
|
+
* ```
|
|
1496
|
+
*/
|
|
1497
|
+
async function getPlayerId() {
|
|
1498
|
+
if (!isNativeApp)
|
|
1499
|
+
return '';
|
|
1500
|
+
return callNativeAsync('onesignalGetPlayerId');
|
|
1501
|
+
}
|
|
1502
|
+
/**
|
|
1503
|
+
* Remove the external user ID association.
|
|
1504
|
+
* Call this when the user logs out.
|
|
1505
|
+
*
|
|
1506
|
+
* @example
|
|
1507
|
+
* ```js
|
|
1508
|
+
* // On logout
|
|
1509
|
+
* nativine.onesignal.removeExternalUserId();
|
|
1510
|
+
* ```
|
|
1511
|
+
*/
|
|
1512
|
+
function removeExternalUserId() {
|
|
1513
|
+
if (!isNativeApp)
|
|
1514
|
+
return;
|
|
1515
|
+
callNativeSync('onesignalRemoveExternalUserId');
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1518
|
+
var onesignal = /*#__PURE__*/Object.freeze({
|
|
1519
|
+
__proto__: null,
|
|
1520
|
+
getPlayerId: getPlayerId,
|
|
1521
|
+
removeExternalUserId: removeExternalUserId,
|
|
1522
|
+
sendTag: sendTag,
|
|
1523
|
+
sendTags: sendTags,
|
|
1524
|
+
setExternalUserId: setExternalUserId
|
|
1525
|
+
});
|
|
1526
|
+
|
|
1527
|
+
/**
|
|
1528
|
+
* Toast Module
|
|
1529
|
+
*
|
|
1530
|
+
* Show native Android toast messages.
|
|
1531
|
+
*/
|
|
1532
|
+
/**
|
|
1533
|
+
* Show a native toast message.
|
|
1534
|
+
*
|
|
1535
|
+
* @param message - The text to display
|
|
1536
|
+
* @param duration - 'short' (~2s) or 'long' (~3.5s)
|
|
1537
|
+
*
|
|
1538
|
+
* @example
|
|
1539
|
+
* ```js
|
|
1540
|
+
* nativine.toast('Item added to cart!');
|
|
1541
|
+
* nativine.toast('Processing payment...', 'long');
|
|
1542
|
+
* ```
|
|
1543
|
+
*/
|
|
1544
|
+
function showToast(message, duration = 'short') {
|
|
1545
|
+
if (!isNativeApp) {
|
|
1546
|
+
// Web fallback: show a temporary notification-style element
|
|
1547
|
+
const el = document.createElement('div');
|
|
1548
|
+
el.textContent = message;
|
|
1549
|
+
Object.assign(el.style, {
|
|
1550
|
+
position: 'fixed',
|
|
1551
|
+
bottom: '80px',
|
|
1552
|
+
left: '50%',
|
|
1553
|
+
transform: 'translateX(-50%)',
|
|
1554
|
+
background: 'rgba(0,0,0,0.8)',
|
|
1555
|
+
color: '#fff',
|
|
1556
|
+
padding: '10px 24px',
|
|
1557
|
+
borderRadius: '24px',
|
|
1558
|
+
fontSize: '14px',
|
|
1559
|
+
zIndex: '999999',
|
|
1560
|
+
pointerEvents: 'none',
|
|
1561
|
+
transition: 'opacity 0.3s ease',
|
|
1562
|
+
opacity: '0',
|
|
1563
|
+
fontFamily: '-apple-system, BlinkMacSystemFont, sans-serif',
|
|
1564
|
+
});
|
|
1565
|
+
document.body.appendChild(el);
|
|
1566
|
+
// Fade in
|
|
1567
|
+
requestAnimationFrame(() => { el.style.opacity = '1'; });
|
|
1568
|
+
// Remove after duration
|
|
1569
|
+
const ms = duration === 'long' ? 3500 : 2000;
|
|
1570
|
+
setTimeout(() => {
|
|
1571
|
+
el.style.opacity = '0';
|
|
1572
|
+
setTimeout(() => {
|
|
1573
|
+
if (el.parentNode)
|
|
1574
|
+
el.parentNode.removeChild(el);
|
|
1575
|
+
}, 300);
|
|
1576
|
+
}, ms);
|
|
1577
|
+
return;
|
|
1578
|
+
}
|
|
1579
|
+
callNativeSync('showToast', { message, duration });
|
|
1580
|
+
}
|
|
1581
|
+
|
|
1582
|
+
/**
|
|
1583
|
+
* Pedometer / Step Counter Module
|
|
1584
|
+
*
|
|
1585
|
+
* Access the device's built-in step counter sensor to track steps.
|
|
1586
|
+
* Uses Android's TYPE_STEP_COUNTER hardware sensor.
|
|
1587
|
+
* Requires ACTIVITY_RECOGNITION permission on Android 10+.
|
|
1588
|
+
*/
|
|
1589
|
+
/**
|
|
1590
|
+
* Check if the device has a step counter sensor.
|
|
1591
|
+
*
|
|
1592
|
+
* @returns Promise resolving with availability info
|
|
1593
|
+
*
|
|
1594
|
+
* @example
|
|
1595
|
+
* ```js
|
|
1596
|
+
* const { available } = await nativine.pedometer.isAvailable();
|
|
1597
|
+
* if (available) {
|
|
1598
|
+
* nativine.pedometer.startTracking();
|
|
1599
|
+
* }
|
|
1600
|
+
* ```
|
|
1601
|
+
*/
|
|
1602
|
+
async function isAvailable() {
|
|
1603
|
+
if (!isNativeApp) {
|
|
1604
|
+
return { available: false };
|
|
1605
|
+
}
|
|
1606
|
+
return callNativeAsync('isPedometerAvailable');
|
|
1607
|
+
}
|
|
1608
|
+
/**
|
|
1609
|
+
* Get the current step count since tracking started.
|
|
1610
|
+
* Returns 0 if tracking hasn't been started yet.
|
|
1611
|
+
*
|
|
1612
|
+
* @returns Promise resolving with the step count
|
|
1613
|
+
*
|
|
1614
|
+
* @example
|
|
1615
|
+
* ```js
|
|
1616
|
+
* const { steps } = await nativine.pedometer.getStepCount();
|
|
1617
|
+
* console.log(`You've taken ${steps} steps`);
|
|
1618
|
+
* ```
|
|
1619
|
+
*/
|
|
1620
|
+
async function getStepCount() {
|
|
1621
|
+
if (!isNativeApp) {
|
|
1622
|
+
return { steps: 0 };
|
|
1623
|
+
}
|
|
1624
|
+
return callNativeAsync('getStepCount');
|
|
1625
|
+
}
|
|
1626
|
+
/**
|
|
1627
|
+
* Start tracking steps. The step count resets to 0 when tracking begins.
|
|
1628
|
+
* Step updates are dispatched as 'stepUpdate' events via `nativine.on()`.
|
|
1629
|
+
*
|
|
1630
|
+
* @example
|
|
1631
|
+
* ```js
|
|
1632
|
+
* nativine.pedometer.startTracking();
|
|
1633
|
+
*
|
|
1634
|
+
* // Listen for real-time step updates
|
|
1635
|
+
* nativine.on('stepUpdate', ({ steps }) => {
|
|
1636
|
+
* document.getElementById('step-count').textContent = steps;
|
|
1637
|
+
* });
|
|
1638
|
+
* ```
|
|
1639
|
+
*/
|
|
1640
|
+
function startTracking() {
|
|
1641
|
+
if (!isNativeApp)
|
|
1642
|
+
return;
|
|
1643
|
+
callNativeSync('startStepTracking');
|
|
1644
|
+
}
|
|
1645
|
+
/**
|
|
1646
|
+
* Stop tracking steps. The sensor listener is unregistered to save battery.
|
|
1647
|
+
*
|
|
1648
|
+
* @example
|
|
1649
|
+
* ```js
|
|
1650
|
+
* nativine.pedometer.stopTracking();
|
|
1651
|
+
* ```
|
|
1652
|
+
*/
|
|
1653
|
+
function stopTracking() {
|
|
1654
|
+
if (!isNativeApp)
|
|
1655
|
+
return;
|
|
1656
|
+
callNativeSync('stopStepTracking');
|
|
1657
|
+
}
|
|
1658
|
+
|
|
1659
|
+
var pedometer = /*#__PURE__*/Object.freeze({
|
|
1660
|
+
__proto__: null,
|
|
1661
|
+
getStepCount: getStepCount,
|
|
1662
|
+
isAvailable: isAvailable,
|
|
1663
|
+
startTracking: startTracking,
|
|
1664
|
+
stopTracking: stopTracking
|
|
1665
|
+
});
|
|
1666
|
+
|
|
1667
|
+
/**
|
|
1668
|
+
* Events Module
|
|
1669
|
+
*
|
|
1670
|
+
* Subscribe to native app lifecycle events.
|
|
1671
|
+
* The native side dispatches events by calling global handler functions.
|
|
1672
|
+
*/
|
|
1673
|
+
const _eventListeners = new Map();
|
|
1674
|
+
/**
|
|
1675
|
+
* Subscribe to a native app lifecycle event.
|
|
1676
|
+
*
|
|
1677
|
+
* Available events:
|
|
1678
|
+
* - `'appResume'` — App returned to foreground
|
|
1679
|
+
* - `'appPause'` — App went to background
|
|
1680
|
+
* - `'pageReady'` — Bridge is fully initialized and ready
|
|
1681
|
+
* - `'keyboardShow'` — Software keyboard appeared (with height data)
|
|
1682
|
+
* - `'keyboardHide'` — Software keyboard dismissed
|
|
1683
|
+
*
|
|
1684
|
+
* @param event - The event name to listen for
|
|
1685
|
+
* @param callback - Function called when the event fires
|
|
1686
|
+
* @returns Unsubscribe function
|
|
1687
|
+
*
|
|
1688
|
+
* @example
|
|
1689
|
+
* ```js
|
|
1690
|
+
* // Refresh data when user returns to app
|
|
1691
|
+
* const unsubscribe = nativine.on('appResume', () => {
|
|
1692
|
+
* fetchLatestData();
|
|
1693
|
+
* });
|
|
1694
|
+
*
|
|
1695
|
+
* // Listen for keyboard visibility
|
|
1696
|
+
* nativine.on('keyboardShow', ({ height }) => {
|
|
1697
|
+
* adjustLayoutForKeyboard(height);
|
|
1698
|
+
* });
|
|
1699
|
+
*
|
|
1700
|
+
* // Cleanup
|
|
1701
|
+
* unsubscribe();
|
|
1702
|
+
* ```
|
|
1703
|
+
*/
|
|
1704
|
+
function on(event, callback) {
|
|
1705
|
+
if (!_eventListeners.has(event)) {
|
|
1706
|
+
_eventListeners.set(event, []);
|
|
1707
|
+
}
|
|
1708
|
+
_eventListeners.get(event).push(callback);
|
|
1709
|
+
return () => {
|
|
1710
|
+
const listeners = _eventListeners.get(event);
|
|
1711
|
+
if (listeners) {
|
|
1712
|
+
const idx = listeners.indexOf(callback);
|
|
1713
|
+
if (idx !== -1)
|
|
1714
|
+
listeners.splice(idx, 1);
|
|
1715
|
+
}
|
|
1716
|
+
};
|
|
1717
|
+
}
|
|
1718
|
+
/**
|
|
1719
|
+
* Unsubscribe all listeners for a specific event, or all events.
|
|
1720
|
+
*
|
|
1721
|
+
* @param event - The event to clear listeners for (or omit to clear all)
|
|
1722
|
+
*
|
|
1723
|
+
* @example
|
|
1724
|
+
* ```js
|
|
1725
|
+
* // Remove all appResume listeners
|
|
1726
|
+
* nativine.off('appResume');
|
|
1727
|
+
*
|
|
1728
|
+
* // Remove ALL event listeners
|
|
1729
|
+
* nativine.off();
|
|
1730
|
+
* ```
|
|
1731
|
+
*/
|
|
1732
|
+
function off(event) {
|
|
1733
|
+
if (event) {
|
|
1734
|
+
_eventListeners.delete(event);
|
|
1735
|
+
}
|
|
1736
|
+
else {
|
|
1737
|
+
_eventListeners.clear();
|
|
1738
|
+
}
|
|
1739
|
+
}
|
|
1740
|
+
/**
|
|
1741
|
+
* Internal: Dispatch an event to all registered listeners.
|
|
1742
|
+
* Called by the native side via global window functions.
|
|
1743
|
+
* @internal
|
|
1744
|
+
*/
|
|
1745
|
+
function _dispatchEvent(event, data) {
|
|
1746
|
+
const listeners = _eventListeners.get(event);
|
|
1747
|
+
if (listeners) {
|
|
1748
|
+
listeners.forEach(cb => {
|
|
1749
|
+
try {
|
|
1750
|
+
cb(data);
|
|
1751
|
+
}
|
|
1752
|
+
catch (e) {
|
|
1753
|
+
console.error(`[nativine] Event '${event}' listener error:`, e);
|
|
1754
|
+
}
|
|
1755
|
+
});
|
|
1756
|
+
}
|
|
1757
|
+
}
|
|
1758
|
+
// Register global handlers for native-side event dispatching
|
|
1759
|
+
if (typeof window !== 'undefined') {
|
|
1760
|
+
window.__nativine_event = (eventName, jsonData) => {
|
|
1761
|
+
try {
|
|
1762
|
+
const data = jsonData ? (typeof jsonData === 'string' ? JSON.parse(jsonData) : jsonData) : undefined;
|
|
1763
|
+
_dispatchEvent(eventName, data);
|
|
1764
|
+
}
|
|
1765
|
+
catch (e) { /* ignore parse errors */ }
|
|
1766
|
+
};
|
|
1767
|
+
// Convenience aliases for common events
|
|
1768
|
+
window.__nativine_onAppResume = () => _dispatchEvent('appResume');
|
|
1769
|
+
window.__nativine_onAppPause = () => _dispatchEvent('appPause');
|
|
1770
|
+
window.__nativine_onKeyboardShow = (json) => {
|
|
1771
|
+
try {
|
|
1772
|
+
_dispatchEvent('keyboardShow', JSON.parse(json));
|
|
1773
|
+
}
|
|
1774
|
+
catch (_a) {
|
|
1775
|
+
_dispatchEvent('keyboardShow');
|
|
1776
|
+
}
|
|
1777
|
+
};
|
|
1778
|
+
window.__nativine_onKeyboardHide = () => _dispatchEvent('keyboardHide');
|
|
1779
|
+
// Fire 'pageReady' event after bridge initialization
|
|
1780
|
+
if (document.readyState === 'complete') {
|
|
1781
|
+
setTimeout(() => _dispatchEvent('pageReady'), 0);
|
|
1782
|
+
}
|
|
1783
|
+
else {
|
|
1784
|
+
window.addEventListener('load', () => {
|
|
1785
|
+
setTimeout(() => _dispatchEvent('pageReady'), 0);
|
|
1786
|
+
});
|
|
1787
|
+
}
|
|
1788
|
+
}
|
|
1789
|
+
|
|
1790
|
+
/**
|
|
1791
|
+
* Nativine JavaScript Bridge
|
|
1792
|
+
*
|
|
1793
|
+
* Enterprise-grade bridge for communicating between web apps and Nativine native shells.
|
|
1794
|
+
* Provides 50+ APIs across 12 namespaces with full TypeScript support, Promise-based
|
|
1795
|
+
* async methods, and graceful web fallbacks.
|
|
1796
|
+
*
|
|
1797
|
+
* @example ESM (recommended)
|
|
1798
|
+
* ```js
|
|
1799
|
+
* import nativine from 'nativine';
|
|
1800
|
+
*
|
|
1801
|
+
* if (nativine.isNativeApp) {
|
|
1802
|
+
* const info = await nativine.device.getInfo();
|
|
1803
|
+
* nativine.haptics.vibrate(200);
|
|
1804
|
+
* }
|
|
1805
|
+
* ```
|
|
1806
|
+
*
|
|
1807
|
+
* @example CDN / Script tag
|
|
1808
|
+
* ```html
|
|
1809
|
+
* <script src="https://cdn.jsdelivr.net/npm/nativine@latest/dist/nativine.umd.js"></script>
|
|
1810
|
+
* <script>
|
|
1811
|
+
* if (Nativine.isNativeApp) {
|
|
1812
|
+
* Nativine.haptics.vibrate(200);
|
|
1813
|
+
* }
|
|
1814
|
+
* </script>
|
|
1815
|
+
* ```
|
|
1816
|
+
*
|
|
1817
|
+
* @packageDocumentation
|
|
1818
|
+
*/
|
|
1819
|
+
// ─── Core ────────────────────────────────────────────────────
|
|
1820
|
+
// ─── Bridge API ──────────────────────────────────────────────
|
|
1821
|
+
const nativine = {
|
|
1822
|
+
// ── Detection ──────────────────────────────────
|
|
1823
|
+
/** The detected platform: `'android'`, `'ios'`, or `'web'` */
|
|
1824
|
+
platform,
|
|
1825
|
+
/** `true` if running inside a Nativine native app */
|
|
1826
|
+
isNativeApp,
|
|
1827
|
+
/** `true` if running inside a Nativine Android app */
|
|
1828
|
+
isAndroid,
|
|
1829
|
+
/** `true` if running inside a Nativine iOS app */
|
|
1830
|
+
isIos,
|
|
1831
|
+
// ── SDK Version ────────────────────────────────
|
|
1832
|
+
/** The version of this SDK */
|
|
1833
|
+
version: '1.0.0',
|
|
1834
|
+
// ── Device ─────────────────────────────────────
|
|
1835
|
+
device: {
|
|
1836
|
+
getInfo: getInfo,
|
|
1837
|
+
getSafeAreaInsets: getSafeAreaInsets,
|
|
1838
|
+
getAppVersion: getAppVersion,
|
|
1839
|
+
getDeviceId: getDeviceId,
|
|
1840
|
+
},
|
|
1841
|
+
// ── UI ──────────────────────────────────────────
|
|
1842
|
+
ui: {
|
|
1843
|
+
statusBar: statusBar,
|
|
1844
|
+
navigationBar: navigationBar,
|
|
1845
|
+
hideSplashScreen: hideSplashScreen,
|
|
1846
|
+
setOrientation: setOrientation,
|
|
1847
|
+
showNativeComponents: showNativeComponents,
|
|
1848
|
+
hideNativeComponents: hideNativeComponents,
|
|
1849
|
+
setPullToRefresh: setPullToRefresh,
|
|
1850
|
+
setPinchToZoom: setPinchToZoom,
|
|
1851
|
+
},
|
|
1852
|
+
// ── Navigation ──────────────────────────────────
|
|
1853
|
+
navigation: {
|
|
1854
|
+
goBack: goBack,
|
|
1855
|
+
goForward: goForward,
|
|
1856
|
+
navigate: navigate,
|
|
1857
|
+
openInBrowser: openInBrowser,
|
|
1858
|
+
closeApp: closeApp,
|
|
1859
|
+
},
|
|
1860
|
+
// ── Haptics ─────────────────────────────────────
|
|
1861
|
+
haptics: {
|
|
1862
|
+
vibrate: vibrate,
|
|
1863
|
+
feedback: feedback,
|
|
1864
|
+
},
|
|
1865
|
+
// ── Storage ─────────────────────────────────────
|
|
1866
|
+
storage: {
|
|
1867
|
+
set: set,
|
|
1868
|
+
get: get,
|
|
1869
|
+
remove: remove,
|
|
1870
|
+
clear: clear$1,
|
|
1871
|
+
},
|
|
1872
|
+
// ── Share ───────────────────────────────────────
|
|
1873
|
+
share: share,
|
|
1874
|
+
shareFile: shareFile,
|
|
1875
|
+
// ── Auth ────────────────────────────────────────
|
|
1876
|
+
auth: {
|
|
1877
|
+
googleSignIn: googleSignIn,
|
|
1878
|
+
googleSignOut: googleSignOut,
|
|
1879
|
+
},
|
|
1880
|
+
// ── Biometrics ──────────────────────────────────
|
|
1881
|
+
biometrics: {
|
|
1882
|
+
isAvailable: isAvailable$1,
|
|
1883
|
+
authenticate: authenticate,
|
|
1884
|
+
},
|
|
1885
|
+
// ── Contacts ────────────────────────────────────
|
|
1886
|
+
contacts: {
|
|
1887
|
+
getAll: getAll,
|
|
1888
|
+
},
|
|
1889
|
+
// ── Clipboard ───────────────────────────────────
|
|
1890
|
+
clipboard: {
|
|
1891
|
+
copy: copy,
|
|
1892
|
+
read: read,
|
|
1893
|
+
},
|
|
1894
|
+
// ── Downloads ───────────────────────────────────
|
|
1895
|
+
downloads: {
|
|
1896
|
+
downloadFile: downloadFile,
|
|
1897
|
+
},
|
|
1898
|
+
// ── Scanner ─────────────────────────────────────
|
|
1899
|
+
scanner: {
|
|
1900
|
+
scan: scan,
|
|
1901
|
+
},
|
|
1902
|
+
// ── Location ────────────────────────────────────
|
|
1903
|
+
location: {
|
|
1904
|
+
getCurrent: getCurrent,
|
|
1905
|
+
},
|
|
1906
|
+
// ── Network ─────────────────────────────────────
|
|
1907
|
+
network: {
|
|
1908
|
+
isOnline: isOnline,
|
|
1909
|
+
onConnectivityChange: onConnectivityChange,
|
|
1910
|
+
},
|
|
1911
|
+
// ── Cache ───────────────────────────────────────
|
|
1912
|
+
cache: {
|
|
1913
|
+
clear: clear,
|
|
1914
|
+
clearCookies: clearCookies,
|
|
1915
|
+
},
|
|
1916
|
+
// ── Print ───────────────────────────────────────
|
|
1917
|
+
print: printPage,
|
|
1918
|
+
// ── Screenshot ──────────────────────────────────
|
|
1919
|
+
screenshot: {
|
|
1920
|
+
setProtection: setProtection,
|
|
1921
|
+
},
|
|
1922
|
+
// ── Reviews ─────────────────────────────────────
|
|
1923
|
+
reviews: {
|
|
1924
|
+
request: request,
|
|
1925
|
+
},
|
|
1926
|
+
// ── Updates ─────────────────────────────────────
|
|
1927
|
+
updates: {
|
|
1928
|
+
check: check,
|
|
1929
|
+
},
|
|
1930
|
+
// ── Ads ─────────────────────────────────────────
|
|
1931
|
+
ads: {
|
|
1932
|
+
showInterstitial: showInterstitial,
|
|
1933
|
+
showRewarded: showRewarded,
|
|
1934
|
+
},
|
|
1935
|
+
// ── OneSignal ───────────────────────────────────
|
|
1936
|
+
onesignal: {
|
|
1937
|
+
setExternalUserId: setExternalUserId,
|
|
1938
|
+
removeExternalUserId: removeExternalUserId,
|
|
1939
|
+
sendTag: sendTag,
|
|
1940
|
+
sendTags: sendTags,
|
|
1941
|
+
getPlayerId: getPlayerId,
|
|
1942
|
+
},
|
|
1943
|
+
// ── Toast ───────────────────────────────────────
|
|
1944
|
+
toast: showToast,
|
|
1945
|
+
// ── Pedometer / Step Counter ────────────────
|
|
1946
|
+
pedometer: {
|
|
1947
|
+
isAvailable: isAvailable,
|
|
1948
|
+
getStepCount: getStepCount,
|
|
1949
|
+
startTracking: startTracking,
|
|
1950
|
+
stopTracking: stopTracking,
|
|
1951
|
+
},
|
|
1952
|
+
// ── Events ──────────────────────────────────────
|
|
1953
|
+
on,
|
|
1954
|
+
off,
|
|
1955
|
+
};
|
|
1956
|
+
|
|
1957
|
+
exports.ads = ads;
|
|
1958
|
+
exports.auth = auth;
|
|
1959
|
+
exports.biometrics = biometrics;
|
|
1960
|
+
exports.cache = cache;
|
|
1961
|
+
exports.clipboard = clipboard;
|
|
1962
|
+
exports.contacts = contacts;
|
|
1963
|
+
exports.default = nativine;
|
|
1964
|
+
exports.device = device;
|
|
1965
|
+
exports.downloads = downloads;
|
|
1966
|
+
exports.haptics = haptics;
|
|
1967
|
+
exports.isAndroid = isAndroid;
|
|
1968
|
+
exports.isIos = isIos;
|
|
1969
|
+
exports.isNativeApp = isNativeApp;
|
|
1970
|
+
exports.location = location;
|
|
1971
|
+
exports.navigation = navigation;
|
|
1972
|
+
exports.network = network;
|
|
1973
|
+
exports.off = off;
|
|
1974
|
+
exports.on = on;
|
|
1975
|
+
exports.onesignal = onesignal;
|
|
1976
|
+
exports.pedometer = pedometer;
|
|
1977
|
+
exports.platform = platform;
|
|
1978
|
+
exports.reviews = reviews;
|
|
1979
|
+
exports.scanner = camera;
|
|
1980
|
+
exports.screenshot = screenshot;
|
|
1981
|
+
exports.storage = storage;
|
|
1982
|
+
exports.ui = ui;
|
|
1983
|
+
exports.updates = updates;
|
|
1984
|
+
//# sourceMappingURL=nativine.cjs.js.map
|