The @capgo/capacitor-android-kiosk package provides Android Kiosk Mode functionality for Capacitor apps, allowing you to lock devices into kiosk mode with full control over hardware buttons and launcher functionality. This tutorial will guide you through installation, configuration, and usage.
Important: This plugin is Android-only. For iOS kiosk mode, use the device's built-in Guided Access feature.
Install the package using your preferred package manager:
npm install @capgo/capacitor-android-kiosk
npx cap sync android
import { CapacitorAndroidKiosk } from '@capgo/capacitor-android-kiosk';
The simplest way to use the plugin is to enter and exit kiosk mode:
async function enableKioskMode() {
try {
await CapacitorAndroidKiosk.enterKioskMode();
console.log('Kiosk mode activated');
} catch (error) {
console.error('Failed to enter kiosk mode:', error);
}
}
async function disableKioskMode() {
try {
await CapacitorAndroidKiosk.exitKioskMode();
console.log('Kiosk mode deactivated');
} catch (error) {
console.error('Failed to exit kiosk mode:', error);
}
}
You can check if kiosk mode is currently active:
async function checkKioskStatus() {
const { isInKioskMode } = await CapacitorAndroidKiosk.isInKioskMode();
console.log('Kiosk mode active:', isInKioskMode);
return isInKioskMode;
}
For full kiosk mode functionality (blocking home button, preventing task switching), your app must be set as the device launcher.
async function setupAsLauncher() {
try {
// Check if app is already the launcher
const { isLauncher } = await CapacitorAndroidKiosk.isSetAsLauncher();
if (!isLauncher) {
// Open system settings for user to select your app as launcher
await CapacitorAndroidKiosk.setAsLauncher();
alert('Please select this app as your Home app from the list');
} else {
console.log('App is already set as launcher');
}
} catch (error) {
console.error('Failed to set as launcher:', error);
}
}
async function checkLauncherStatus() {
const { isLauncher } = await CapacitorAndroidKiosk.isSetAsLauncher();
console.log('App is launcher:', isLauncher);
return isLauncher;
}
Control which hardware buttons are allowed to function in kiosk mode:
async function blockAllKeys() {
await CapacitorAndroidKiosk.setAllowedKeys({});
console.log('All hardware keys blocked');
}
async function allowVolumeKeys() {
await CapacitorAndroidKiosk.setAllowedKeys({
volumeUp: true,
volumeDown: true,
back: false,
home: false,
recent: false,
power: false
});
console.log('Volume keys allowed, other keys blocked');
}
The setAllowedKeys method accepts the following options:
volumeUp (boolean): Allow volume up buttonvolumeDown (boolean): Allow volume down buttonback (boolean): Allow back buttonhome (boolean): Allow home buttonrecent (boolean): Allow recent apps buttonpower (boolean): Allow power buttoncamera (boolean): Allow camera button (if present)menu (boolean): Allow menu button (if present)All options default to false (blocked).
Here's a complete example showing how to set up a kiosk application:
import { CapacitorAndroidKiosk } from '@capgo/capacitor-android-kiosk';
class KioskManager {
private isInitialized = false;
async initialize() {
try {
// Step 1: Check if app is set as launcher
const { isLauncher } = await CapacitorAndroidKiosk.isSetAsLauncher();
if (!isLauncher) {
// Prompt user to set app as launcher
await CapacitorAndroidKiosk.setAsLauncher();
alert('Please select this app as your Home app to enable kiosk mode');
return false;
}
// Step 2: Configure allowed hardware keys
await CapacitorAndroidKiosk.setAllowedKeys({
volumeUp: true,
volumeDown: true,
back: false,
home: false,
recent: false,
power: false,
camera: false,
menu: false
});
// Step 3: Enter kiosk mode
await CapacitorAndroidKiosk.enterKioskMode();
this.isInitialized = true;
console.log('Kiosk mode initialized successfully');
return true;
} catch (error) {
console.error('Failed to initialize kiosk mode:', error);
return false;
}
}
async exit() {
try {
await CapacitorAndroidKiosk.exitKioskMode();
this.isInitialized = false;
console.log('Exited kiosk mode');
} catch (error) {
console.error('Failed to exit kiosk mode:', error);
}
}
async getStatus() {
const { isInKioskMode } = await CapacitorAndroidKiosk.isInKioskMode();
const { isLauncher } = await CapacitorAndroidKiosk.isSetAsLauncher();
return {
kioskMode: isInKioskMode,
launcher: isLauncher,
initialized: this.isInitialized
};
}
}
// Usage
const kioskManager = new KioskManager();
// Initialize kiosk mode
await kioskManager.initialize();
// Check status
const status = await kioskManager.getStatus();
console.log('Kiosk Status:', status);
// Exit kiosk mode
await kioskManager.exit();
To enable full hardware key blocking, you need to override dispatchKeyEvent in your MainActivity.java:
package your.package.name;
import android.os.Bundle;
import android.view.KeyEvent;
import com.getcapacitor.BridgeActivity;
import ee.forgr.plugin.android_kiosk.CapacitorAndroidKioskPlugin;
public class MainActivity extends BridgeActivity {
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
// Get the kiosk plugin
CapacitorAndroidKioskPlugin kioskPlugin = (CapacitorAndroidKioskPlugin)
this.getBridge().getPlugin("CapacitorAndroidKiosk").getInstance();
if (kioskPlugin != null && kioskPlugin.shouldBlockKey(event.getKeyCode())) {
return true; // Block the key
}
return super.dispatchKeyEvent(event);
}
@Override
public void onBackPressed() {
// Don't call super.onBackPressed() to disable back button
// The plugin will handle this based on setAllowedKeys configuration
}
}
Add launcher intent filter to make your app selectable as a launcher:
<activity
android:name=".MainActivity"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode"
android:label="@string/title_activity_main"
android:launchMode="singleTask"
android:theme="@style/AppTheme.NoActionBarLaunch">
<!-- Existing intent filter -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!-- Add this to make app selectable as launcher -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.HOME" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
async function setupKiosk() {
const { isLauncher } = await CapacitorAndroidKiosk.isSetAsLauncher();
if (!isLauncher) {
await CapacitorAndroidKiosk.setAsLauncher();
// Wait for user to set app as launcher before proceeding
return;
}
await CapacitorAndroidKiosk.enterKioskMode();
}
Always provide a way for authorized users to exit kiosk mode:
async function exitWithConfirmation() {
// Implement your authentication logic here
const isAuthorized = await authenticateAdmin();
if (isAuthorized) {
await CapacitorAndroidKiosk.exitKioskMode();
}
}
// Example: Secret tap pattern
let tapCount = 0;
let tapTimer: NodeJS.Timeout;
function handleSecretTap() {
tapCount++;
clearTimeout(tapTimer);
if (tapCount === 5) {
exitWithConfirmation();
tapCount = 0;
} else {
tapTimer = setTimeout(() => {
tapCount = 0;
}, 2000);
}
}
Re-enter kiosk mode when app resumes:
import { App } from '@capacitor/app';
App.addListener('resume', async () => {
const { isInKioskMode } = await CapacitorAndroidKiosk.isInKioskMode();
const { isLauncher } = await CapacitorAndroidKiosk.isSetAsLauncher();
if (isLauncher && !isInKioskMode) {
await CapacitorAndroidKiosk.enterKioskMode();
}
});
Always handle errors gracefully:
async function safeEnterKioskMode() {
try {
await CapacitorAndroidKiosk.enterKioskMode();
return true;
} catch (error) {
console.error('Failed to enter kiosk mode:', error);
// Notify user or log to analytics
return false;
}
}
async function setupRetailKiosk() {
// Block all keys except volume
await CapacitorAndroidKiosk.setAllowedKeys({
volumeUp: true,
volumeDown: true
});
await CapacitorAndroidKiosk.enterKioskMode();
// Keep screen on
// Implement auto-reset after inactivity
}
async function setupDigitalSignage() {
// Block all keys
await CapacitorAndroidKiosk.setAllowedKeys({});
await CapacitorAndroidKiosk.enterKioskMode();
// Auto-refresh content
// Implement scheduled updates
}
async function setupEducationalDevice() {
// Allow volume control for accessibility
await CapacitorAndroidKiosk.setAllowedKeys({
volumeUp: true,
volumeDown: true
});
await CapacitorAndroidKiosk.enterKioskMode();
// Restrict access to educational apps only
}
Get the native Capacitor plugin version.
const { version } = await CapacitorAndroidKiosk.getPluginVersion();
console.log('Plugin version:', version);
Launcher Requirement: For full kiosk mode functionality (blocking home button, preventing task switching), your app must be set as the device launcher.
Testing: When testing, you can exit kiosk mode programmatically or by setting another app as the launcher through device settings.
Android Versions: The plugin uses modern Android APIs for Android 11+ and falls back to older methods for compatibility with Android 6.0+.
Security: This plugin is designed for legitimate kiosk applications. Always provide authorized users with a way to exit kiosk mode.
Battery: Kiosk mode may keep the screen on. Consider implementing your own screen timeout or brightness management to save battery.
Permissions: No special permissions are required in AndroidManifest.xml, but the launcher intent filter is necessary for full functionality.
For iOS devices, use the built-in Guided Access feature:
Make sure your app is set as the device launcher:
const { isLauncher } = await CapacitorAndroidKiosk.isSetAsLauncher();
if (!isLauncher) {
await CapacitorAndroidKiosk.setAsLauncher();
}
Ensure you've implemented the dispatchKeyEvent override in MainActivity.java as shown in the Android Configuration section.
Add app lifecycle listeners to re-enter kiosk mode on resume:
App.addListener('resume', async () => {
await CapacitorAndroidKiosk.enterKioskMode();
});
The @capgo/capacitor-android-kiosk plugin provides a comprehensive solution for creating kiosk applications on Android devices. By combining launcher functionality with hardware key control, you can create secure, locked-down experiences for retail, education, digital signage, and other kiosk use cases.
For more information and updates, visit the GitHub repository.