DeviceMotion, DeviceOrientation, and Vibration are first-class on the mobile web — until they run inside a WebView. Android System WebView left the Device Orientation API disabled until v55 and still returns all-zero acceleration on many builds unless the right flags and permissions are set; Vibration needs an explicit VIBRATE permission. On iOS, WKWebView does not even expose requestPermission(), so the gesture-gated iOS 13+ flow never starts. A host-owned runtime bridges the sensor layer — one API that reads the real hardware on every engine.

Android: disabled by default, silent when "on"

The Chromium documentation is plain: among hardware-sensor APIs, the Device Orientation API was disabled in WebView v33 and only enabled from v55. Geolocation, media capture, and Vibration are partly gated too. And "enabled" is not "working" — many WebView builds return acceleration as all zeros or never fire the event unless the page is served over https and the app grants the runtime permission. A common failure is a "shake to action" feature that simply never triggers because the container did not forward the sensor. Vibration (navigator.vibrate) needs android.permission.VIBRATE; without it the call is a silent no-op.

iOS: the permission API is missing entirely

From iOS 13, Safari requires DeviceMotionEvent.requestPermission() / DeviceOrientationEvent.requestPermission() — a dialog triggered by a user gesture — before any motion or orientation event fires. But that API is not exposed in WKWebView. WebKit's own bug tracker (bug 203287) records it: "The requestPermission() API is only exposed in MobileSafari, not WKWebView." So inside an app's WebView the gesture-gated flow cannot even begin; the page must instead rely on the WebView having direct access, which depends entirely on how the host configured it. Add the secure-context requirement (no http://) and the iframe allow="gyroscope; accelerometer" policy, and most embedded pages get nothing.

What breaks when sensors go quiet

  • Shake, tilt, and step features die. No devicemotion events means no gesture-based UX.
  • 360° / AR / level tools return nothing. deviceorientation is absent or all-zero.
  • Haptics are silent. navigator.vibrate is a no-op without the VIBRATE permission.
  • iOS 13+ double trap. No requestPermission() in WKWebView, so the Safari path cannot run; the host must grant natively.
  • Embedded browsers diverge. WeChat/Weibo containers often expose neither the API nor a way to prompt, so QA in Safari hides the break.

The runtime fix

A host-owned runtime bridges the sensor layer. The host reads the real hardware — SensorManager on Android, Core Motion on iOS — and exposes one uniform API to the page: motion, orientation, and haptic feedback that work on every engine and every embedded browser. Permission is requested once, natively, and the values flow to the page without the per-engine gating. One sensor surface, real hardware, everywhere.

DimensionWebViewHost-owned runtime
Android Device OrientationDisabled < v55, often zeroReal hardware
iOS requestPermissionNot exposed in WKWebViewNative grant
VibrationNeeds VIBRATE permissionNative haptics
Secure context gateEasy to missHandled natively
Embedded browsersNo API, no promptUniform API
ConsistencyPer-engineUniform

A native app reads the gyroscope on every phone. A stock WebView reads it on almost none. A runtime gives the page one sensor layer — and the real hardware behind it.

Sources