This guide provides detailed integration instructions for the Android Kiosk Mode plugin.
npm install @capgo/capacitor-android-kiosk
npx cap syncAdd the launcher intent filter to your main activity in android/app/src/main/AndroidManifest.xml:
<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">
<!-- Default launcher intent -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!-- Add this to make app available as device launcher/home app -->
<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>Add hardware key blocking support in android/app/src/main/java/.../MainActivity.java:
package com.example.app;
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 instance
CapacitorAndroidKioskPlugin kioskPlugin = null;
try {
kioskPlugin = (CapacitorAndroidKioskPlugin)
this.getBridge().getPlugin("CapacitorAndroidKiosk").getInstance();
} catch (Exception e) {
// Plugin not found or error getting instance
}
// Check if key should be blocked
if (kioskPlugin != null && kioskPlugin.shouldBlockKey(event.getKeyCode())) {
return true; // Block the key event
}
return super.dispatchKeyEvent(event);
}
@Override
public void onBackPressed() {
// Get the kiosk plugin instance
CapacitorAndroidKioskPlugin kioskPlugin = null;
try {
kioskPlugin = (CapacitorAndroidKioskPlugin)
this.getBridge().getPlugin("CapacitorAndroidKiosk").getInstance();
} catch (Exception e) {
// Plugin not found
}
// Check if we're in kiosk mode
if (kioskPlugin != null) {
// Let the plugin handle back press (it will block if in kiosk mode)
// Don't call super to prevent default back behavior
} else {
super.onBackPressed();
}
}
}No additional configuration needed in capacitor.config.ts.
import { CapacitorAndroidKiosk } from '@capgo/capacitor-android-kiosk';
async function initializeKiosk() {
// Check if app is set as launcher
const { isLauncher } = await CapacitorAndroidKiosk.isSetAsLauncher();
if (!isLauncher) {
alert('Please set this app as your device launcher');
await CapacitorAndroidKiosk.setAsLauncher();
return;
}
// Enter kiosk mode
await CapacitorAndroidKiosk.enterKioskMode();
console.log('Kiosk mode active');
}
// Initialize on app start
initializeKiosk();async function setupKioskWithVolumeControl() {
// Allow volume buttons but block everything else
await CapacitorAndroidKiosk.setAllowedKeys({
volumeUp: true,
volumeDown: true,
back: false,
home: false,
recent: false,
power: false
});
await CapacitorAndroidKiosk.enterKioskMode();
}async function exitKioskWithPin() {
const pin = prompt('Enter PIN to exit kiosk mode:');
if (pin === '1234') {
await CapacitorAndroidKiosk.exitKioskMode();
alert('Exited kiosk mode');
} else {
alert('Incorrect PIN');
}
}import { useEffect, useState } from 'react';
import { CapacitorAndroidKiosk } from '@capgo/capacitor-android-kiosk';
function useKioskMode() {
const [isInKiosk, setIsInKiosk] = useState(false);
const [isLauncher, setIsLauncher] = useState(false);
useEffect(() => {
checkStatus();
}, []);
async function checkStatus() {
const { isInKioskMode } = await CapacitorAndroidKiosk.isInKioskMode();
const { isLauncher } = await CapacitorAndroidKiosk.isSetAsLauncher();
setIsInKiosk(isInKioskMode);
setIsLauncher(isLauncher);
}
async function enterKiosk() {
await CapacitorAndroidKiosk.enterKioskMode();
await checkStatus();
}
async function exitKiosk() {
await CapacitorAndroidKiosk.exitKioskMode();
await checkStatus();
}
return {
isInKiosk,
isLauncher,
enterKiosk,
exitKiosk,
checkStatus
};
}
// Usage in component
function KioskApp() {
const { isInKiosk, isLauncher, enterKiosk, exitKiosk } = useKioskMode();
return (
<div>
<p>Kiosk Mode: {isInKiosk ? 'Active' : 'Inactive'}</p>
<p>Is Launcher: {isLauncher ? 'Yes' : 'No'}</p>
<button onClick={enterKiosk}>Enter Kiosk</button>
<button onClick={exitKiosk}>Exit Kiosk</button>
</div>
);
}import { ref, onMounted } from 'vue';
import { CapacitorAndroidKiosk } from '@capgo/capacitor-android-kiosk';
export function useKioskMode() {
const isInKiosk = ref(false);
const isLauncher = ref(false);
async function checkStatus() {
const kioskStatus = await CapacitorAndroidKiosk.isInKioskMode();
const launcherStatus = await CapacitorAndroidKiosk.isSetAsLauncher();
isInKiosk.value = kioskStatus.isInKioskMode;
isLauncher.value = launcherStatus.isLauncher;
}
async function enterKiosk() {
await CapacitorAndroidKiosk.enterKioskMode();
await checkStatus();
}
async function exitKiosk() {
await CapacitorAndroidKiosk.exitKioskMode();
await checkStatus();
}
onMounted(() => {
checkStatus();
});
return {
isInKiosk,
isLauncher,
enterKiosk,
exitKiosk,
checkStatus
};
}- Build and run your app on an Android device or emulator
- Call
setAsLauncher()to open home screen settings - Select your app as the default launcher
- Test kiosk mode functionality
During development, you can exit kiosk mode in several ways:
- Programmatically: Call
exitKioskMode()in your app - Via Settings: Set a different app as launcher
- ADB: Use
adb shell am start -a android.settings.HOME_SETTINGS
# Check if app is launcher
adb shell cmd package get-home-app
# Open home settings
adb shell am start -a android.settings.HOME_SETTINGS
# Force stop app
adb shell am force-stop com.example.app
# Clear app as default launcher
adb shell pm clear-default-launcherIssue: Hardware buttons still work in kiosk mode
Solution: Ensure you've overridden dispatchKeyEvent in MainActivity.java as shown in Step 2
Issue: App doesn't appear in launcher selection
Solution: Verify the HOME intent filter is added to AndroidManifest.xml
Issue: App crashes when calling enterKioskMode()
Solution: Check Android version compatibility and permissions
Issue: Back button exits the app even in kiosk mode
Solution: Override onBackPressed() in MainActivity.java
- Always provide an exit mechanism: Implement a PIN, gesture, or admin interface to exit kiosk mode
- Test on multiple devices: Different Android versions may behave differently
- Handle configuration changes: Ensure kiosk mode persists through orientation changes
- Battery management: Consider implementing screen timeout or brightness control
- Error handling: Always wrap plugin calls in try-catch blocks
- User communication: Clearly communicate to users when they're in kiosk mode
- Exit mechanism: Always implement a secure way to exit kiosk mode
- Admin protection: Protect admin functions with authentication
- Updates: Plan how to update the app while in kiosk mode
- Recovery: Have a plan for recovering devices if the app crashes
- Permissions: Only request necessary permissions
- Full kiosk mode support
- Requires being set as launcher for full functionality
- Hardware key blocking supported
- Works on Android 6.0 (API 23) through Android 15 (API 35)
- Not supported - use Guided Access instead
- Plugin will return error messages directing to Guided Access
- Guided Access URL: https://support.apple.com/en-us/HT202612
- Not supported - stub implementation only
- All methods return warnings and default values