Create Free APK

JavaScript bridge API

Vibration and sound

Haptic feedback, the app's own click sound fired on your semantic events rather than every stray tap, and the background music track the creator chose at build time - getMusicVolume returns -1 when the app ships none, so a settings screen can hide the slider instead of showing a dead one.

navigator.vibrate web standard#

navigator.vibrate(pattern)

Example

Vibrates the phone, using the normal web Vibration API. Android WebView's own navigator.vibrate never moves the motor; the app replaces it at document start so it really buzzes.

Returns: true when the request was accepted, false for bad input (a negative or non-number duration). Needs: turn on Vibrate in Step 4 (Access) when you build. AI-built apps get it switched on for you when the code vibrates.

function buzz(pattern) {
  if ('vibrate' in navigator) navigator.vibrate(pattern);
}

document.getElementById('save').addEventListener('click', function () {
  buzz(30);                    // one short buzz, 30 ms
});

document.getElementById('wrong').addEventListener('click', function () {
  buzz([80, 40, 80]);          // buzz 80, pause 40, buzz 80
});

document.getElementById('alarm-off').addEventListener('click', function () {
  buzz(0);                     // 0 or [] stops a running vibration
});

Notes:

  • The pattern is the web one: the first number is a buzz, then pause, buzz, pause ... (the app converts it for Android).
  • If Vibrate was not turned on when you built, the call still returns true but the phone does not vibrate.
  • Decimals are rounded down. In an array, negative numbers count as 0.
  • In a desktop browser navigator.vibrate may be missing, so keep the 'vibrate' in navigator check.

cancelVibrate bridge#

window.WebToApk.cancelVibrate()

Simple haptics for the page (navigator.vibrate and a pattern form). Both are ignored unless the build enabled the Vibrate permission.

Described by its group, Vibration, rather than on its own.

Example

Stops a vibration that is still running. Most pages use the standard navigator.vibrate(0), which calls this for you.

Returns: nothing. Needs: turn on Vibrate in Step 4 (Access) when you build.

The standard way:

if ('vibrate' in navigator) navigator.vibrate(0);   // or navigator.vibrate([])

The raw call, for example to stop a long alarm pattern when the user taps "Dismiss":

if (window.WebToApk && window.WebToApk.vibratePattern) {
  window.WebToApk.vibratePattern(JSON.stringify([1000, 500, 1000, 500, 1000]));
}

document.getElementById('dismiss').addEventListener('click', function () {
  if (window.WebToApk && typeof window.WebToApk.cancelVibrate === 'function') {
    window.WebToApk.cancelVibrate();
  }
});

Notes: Safe to call when nothing is vibrating.

getMusicVolume bridge#

window.WebToApk.getMusicVolume(): Int

Current level 0..100, or -1 when this app ships no background music.

Example

Reads the level of the app's looping background music, 0 to 100.

Returns: a number, synchronously: 0-100, or -1 when this app was built without a music file. Needs: a file chosen under Background Music in Step 3 (Integrate), under Display Options, when you build.

Show a music slider only when there is music:

var slider = document.getElementById('music-slider');
var level = -1;
if (window.WebToApk && typeof window.WebToApk.getMusicVolume === 'function') {
  level = window.WebToApk.getMusicVolume();
}

if (level < 0) {
  slider.parentNode.hidden = true;          // no music in this app: hide the setting
} else {
  slider.value = level;
  slider.addEventListener('input', function () {
    window.WebToApk.setMusicVolume(parseInt(slider.value, 10));
  });
}

Notes: Returns the level set by the build slider or by your last setMusicVolume call. When another app or a call takes the audio, the music ducks or pauses by itself; the number you read does not change.

playClick bridge#

window.WebToApk.playClick()

Plays the app's tap sound on demand, so a page can fire it on its OWN semantic events (a button press) instead of on every stray tap - which is what a native app actually does, and the reason clickSoundMode can be "off" while this still works. A no-op only when the app was built WITHOUT tap sound (enableClickSound off). In clickSoundMode "off" - no automatic every-tap sound - an explicit call still plays: that mode exists for apps that sound on their own events. Otherwise it plays the creator's configured feedback.

Example

Plays the app's tap sound once, so your own buttons can click like a native app.

Returns: nothing. Needs: the Tap Sound switch in Step 3 (Integrate), under Display Options, when you build (on by default). With the switch off, this does nothing.

function clickSound() {
  if (window.WebToApk && typeof window.WebToApk.playClick === 'function') {
    window.WebToApk.playClick();
  }
}

document.querySelectorAll('button, .tab').forEach(function (el) {
  el.addEventListener('click', clickSound);
});

Notes: What you hear depends on the Tap sound choice:

  • Follow phone setting (recommended): the system click. It is silent when the user turned off "Touch sounds" in the phone's settings. That is on purpose.
  • Always play on every tap: the app's own click, always audible. Every tap on the page clicks too, so you usually do not need playClick() in this mode.

Call it from a real button press, not from a timer.

setMusicVolume bridge#

window.WebToApk.setMusicVolume(percent: Int)

Set the background-music level from the page, 0..100. The wizard slider decides how the app STARTS; this is how an app gives its own users a music control, which any game with a settings screen is expected to have. Clamped in [BackgroundMusic.setVolume], so a page passing 500 or -1 cannot hand MediaPlayer a gain outside the range it accepts. The level is REMEMBERED: the next launch starts at it, not at the wizard's level. A no-op when the app was built without a track - there is nothing to set, and the honest answer is [getMusicVolume] returning -1 so the page can hide its slider rather than show one that does nothing.

Example

Changes the level of the app's looping background music, 0 to 100, for example from your game's settings screen.

Returns: nothing. Needs: a file chosen under Background Music in Step 3 (Integrate), under Display Options, when you build. Without music this does nothing (check getMusicVolume() for -1).

A mute button - the app remembers the level for the next launch:

function hasMusic() {
  return !!(window.WebToApk && window.WebToApk.getMusicVolume) && window.WebToApk.getMusicVolume() >= 0;
}

if (!hasMusic()) document.getElementById('mute').hidden = true;

document.getElementById('mute').addEventListener('click', function () {
  if (!hasMusic()) return;
  // clamped to 0..100 by the app, and kept for the next launch
  window.WebToApk.setMusicVolume(window.WebToApk.getMusicVolume() > 0 ? 0 : 40);
});

Notes: The level you set is saved: the next launch starts at it instead of the level from the build slider (until the user clears the app's data). 0 makes the music silent but it keeps playing.

vibrate bridge#

window.WebToApk.vibrate(durationMs: Long)

Simple haptics for the page (navigator.vibrate and a pattern form). Both are ignored unless the build enabled the Vibrate permission.

Described by its group, Vibration, rather than on its own.

Example

Vibrates the phone once for the given number of milliseconds. Most pages use the standard navigator.vibrate(ms), which calls this for you.

Returns: nothing. Needs: turn on Vibrate in Step 4 (Access) when you build. Without it the call does nothing.

The standard way (works the same in a browser):

if ('vibrate' in navigator) navigator.vibrate(50);

The raw call:

document.getElementById('like').addEventListener('click', function () {
  if (window.WebToApk && typeof window.WebToApk.vibrate === 'function') {
    window.WebToApk.vibrate(40);      // 40 ms
  }
});

// 0 (or any value <= 0) stops a running vibration
if (window.WebToApk && window.WebToApk.vibrate) window.WebToApk.vibrate(0);

Notes: Pass a whole number. The strength is the phone's default; for stronger/weaker taps use Capacitor.Plugins.Haptics.impact or Capacitor.Plugins.AppwrightHaptics.play. For a buzz-pause-buzz pattern use vibratePattern.

vibratePattern bridge#

window.WebToApk.vibratePattern(patternJson: String)

Vibrates an on/off pattern, e.g. "[100,50,100]" = buzz 100ms, pause 50, buzz 100. Backs navigator.vibrate(array); prefer the standard API. No-op unless the creator enabled the Vibrate permission.

Example

Vibrates an on/off pattern, given as a JSON string. Most pages use the standard navigator.vibrate([...]), which calls this for you.

Returns: nothing. Needs: turn on Vibrate in Step 4 (Access) when you build. Without it the call does nothing.

The standard way:

if ('vibrate' in navigator) navigator.vibrate([100, 50, 100]);   // buzz, pause, buzz

The raw call takes the same web-style pattern as a JSON string:

function pattern(list) {
  if (window.WebToApk && typeof window.WebToApk.vibratePattern === 'function') {
    window.WebToApk.vibratePattern(JSON.stringify(list));
  }
}

pattern([200]);                     // one 200 ms buzz
pattern([100, 50, 100, 50, 300]);   // short, short, long
pattern([]);                        // empty list stops a running vibration

Notes: The first number is a buzz, then pause, buzz, pause ... (web order). The app adds Android's leading "wait" for you, so do not put a 0 first yourself: [0, 100] means "buzz 0 ms, pause 100 ms" and you feel nothing. Negative numbers count as 0. The pattern plays once.

Generated from the app runtime and its example files on every docs build. Read it as Markdown ยท All families.

Checked against the shipped bridge on 2026-09-23.