@livx.cc/appwrap 0.39.2 → 0.39.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@livx.cc/appwrap",
3
- "version": "0.39.2",
3
+ "version": "0.39.4",
4
4
  "description": "Wrap any PWA into a native app with native capabilities (appwrap runtime + @livx.cc/native-kit).",
5
5
  "license": "MIT",
6
6
  "author": "Elya Livshitz",
@@ -5,9 +5,10 @@ import { SHELL_BUILD, reloadWebView, getReportedWebVersion } from './handlers';
5
5
 
6
6
  /**
7
7
  * Shake-to-open developer menu (enabled in prod too, gated by `SHELL_CONFIG.devMenu`).
8
- * A shake raises a native action sheet → "App Info" shows non-sensitive diagnostics
9
- * (ids, versions, loader, remote host) including the running webapp's version vs. the
10
- * latest deployed — so you can tell at a glance whether the device got the update.
8
+ * A shake raises a native action sheet with: "App Info" — non-sensitive diagnostics (ids, versions,
9
+ * loader, remote host) including the running webapp's version vs. the latest deployed, so you can tell
10
+ * at a glance whether the device got the update; "Reload"; and "Toggle Debug" — a generic hook that
11
+ * dispatches the `appwrap:toggleDebug` DOM event so the web app can flip its OWN debug UI.
11
12
  * The web version status is reported via the always-on `app.reportWebVersion` handler
12
13
  * (in handlers.ts) — independent of this menu — and read here when the menu is shown.
13
14
  */
@@ -120,10 +121,11 @@ async function showDevMenu(): Promise<void> {
120
121
  title: SHELL_CONFIG.name,
121
122
  message: 'Developer menu',
122
123
  cancelButtonText: 'Cancel',
123
- actions: ['App Info', 'Reload'],
124
+ actions: ['App Info', 'Reload', 'Toggle Debug'],
124
125
  });
125
126
  if (action === 'App Info') await showInfo();
126
127
  else if (action === 'Reload') reloadWebView();
128
+ else if (action === 'Toggle Debug') toggleWebDebug();
127
129
  } finally {
128
130
  menuOpen = false;
129
131
  }
@@ -152,6 +154,15 @@ async function showInfo(): Promise<void> {
152
154
  Dialogs.alert({ title: 'App Info', message: lines.join('\n'), okButtonText: 'Close' });
153
155
  }
154
156
 
157
+ /** Generic dev hook: dispatch a DOM event the running web app can listen for to flip its OWN debug UI
158
+ * (`window.addEventListener('appwrap:toggleDebug', …)`). No-op for apps that don't listen — the shell
159
+ * has no app-specific debug state of its own, so it just relays the intent. */
160
+ function toggleWebDebug(): void {
161
+ bridge
162
+ .evalJs("window.dispatchEvent(new CustomEvent('appwrap:toggleDebug'))")
163
+ .catch((e) => console.log('[appwrap] toggleDebug dispatch failed:', e));
164
+ }
165
+
155
166
  /** Read the running page's embedded version directly from the WebView: `window.__APP_VERSION__`,
156
167
  * then a `<meta name="app-version">` fallback. '' if neither is present (or eval fails). */
157
168
  async function readPageVersion(): Promise<string> {
@@ -256,8 +256,12 @@ export function registerAndroidHandlers(): void {
256
256
  let motionListener: android.hardware.SensorEventListener | null = null;
257
257
  const lastMotion = { ax: 0, ay: 0, az: 0, rx: 0, ry: 0, rz: 0 };
258
258
 
259
- bridge.register('motion.start', () => {
259
+ bridge.register('motion.start', (p: { hz?: number } = {}) => {
260
260
  if (motionListener) return; // already streaming
261
+ // Emit rate configurable (default 10 Hz; up to 60 for crisp tilt). SENSOR_DELAY_GAME feeds ~50 Hz;
262
+ // we throttle the EMIT to the requested rate. Higher Hz = more bridge traffic/battery.
263
+ const hz = Math.max(5, Math.min(60, p.hz || 10));
264
+ const minMs = 1000 / hz;
261
265
  const sm = sensorManager();
262
266
  const accel = sm.getDefaultSensor(android.hardware.Sensor.TYPE_ACCELEROMETER);
263
267
  if (!accel) throw err('UNSUPPORTED', 'No accelerometer on this device');
@@ -274,12 +278,13 @@ export function registerAndroidHandlers(): void {
274
278
  lastMotion.rx = v[0]; lastMotion.ry = v[1]; lastMotion.rz = v[2];
275
279
  }
276
280
  const now = java.lang.System.currentTimeMillis();
277
- if (now - last < 100) return; // ~10Hz, matches iOS
281
+ if (now - last < minMs) return; // throttle emit to the requested Hz
278
282
  last = now;
279
283
  bridge.emit('motion.data', { ...lastMotion });
280
284
  },
281
285
  });
282
- const RATE = android.hardware.SensorManager.SENSOR_DELAY_GAME;
286
+ const RATE = hz > 30 ? android.hardware.SensorManager.SENSOR_DELAY_FASTEST
287
+ : android.hardware.SensorManager.SENSOR_DELAY_GAME;
283
288
  sm.registerListener(motionListener, accel, RATE);
284
289
  if (gyro) sm.registerListener(motionListener, gyro, RATE);
285
290
  });
@@ -172,13 +172,18 @@ export function registerParityHandlers(): void {
172
172
  let motionManager: CMMotionManager | null = null;
173
173
  let motionTimer: ReturnType<typeof setInterval> | null = null;
174
174
 
175
- bridge.register('motion.start', () => {
175
+ bridge.register('motion.start', (p: { hz?: number } = {}) => {
176
176
  if (!isIOS) throw iosOnly();
177
177
  if (motionManager) return;
178
+ // Emit rate is configurable (default 10 Hz; games can ask up to 60 for crisp tilt). Both the JS
179
+ // poll cadence AND the CoreMotion sample interval are set — the poll is the actual emit rate, so
180
+ // bumping deviceMotionUpdateInterval alone wouldn't help. Higher Hz = more bridge traffic/battery.
181
+ const hz = Math.max(5, Math.min(60, p.hz || 10));
182
+ const ms = 1000 / hz;
178
183
  const mm = CMMotionManager.new();
179
184
  if (!mm.deviceMotionAvailable) throw err('UNSUPPORTED', 'No motion sensors (simulator?)');
180
185
  motionManager = mm;
181
- mm.deviceMotionUpdateInterval = 0.1;
186
+ mm.deviceMotionUpdateInterval = ms / 1000;
182
187
  mm.startDeviceMotionUpdates();
183
188
  const G = 9.81; // CoreMotion reports in g — kit contract is m/s²
184
189
  motionTimer = setInterval(() => {
@@ -192,7 +197,7 @@ export function registerParityHandlers(): void {
192
197
  ry: m.rotationRate.y,
193
198
  rz: m.rotationRate.z,
194
199
  });
195
- }, 100);
200
+ }, ms);
196
201
  });
197
202
 
198
203
  bridge.register('motion.stop', () => {