A demo Android app showing how to integrate JavaScript in a WebView with native Android APIs.
This demo showcases bidirectional communication between WebView JavaScript and native Android:
- Get device details (manufacturer, model, Android version)
- Get app version information
- Check network connectivity status
- Get battery level and charging status
- Show native Android Toast messages (short and long)
- Trigger device vibration
- Copy text to clipboard
- Request camera permission
- Request location permission
- Handle permission results with JavaScript callbacks
- Share content using Android share sheet
- Open URLs in external browser
- Log debug messages to Android logcat
- Real-time battery status updates
- Network connectivity changes
- Screen on/off events
- App lifecycle events (resume/pause)
- Automatic event broadcasting to JavaScript
- Download remote video files for offline access
- Progress tracking during downloads
- Store videos in app's private storage
- Play videos in native Android video player (outside WebView)
- List, manage, and delete downloaded videos
- Get file size information
app/src/main/java/com/example/jsbridgetest/
├── MainActivity.kt # WebView host, permission handling, and event callbacks
├── WebAppInterface.kt # JavaScript bridge with @JavascriptInterface methods
├── AndroidEventManager.kt # Broadcast receivers for system events
├── VideoManager.kt # Video download and file management
├── VideoPlayerActivity.kt # Native video player activity
└── ui/theme/ # Theme files (legacy, not used)
JavaScript code calls Android methods directly:
// Show a toast
Android.showToast("Hello from JavaScript!");
// Get device info (returns JSON string)
const deviceInfo = JSON.parse(Android.getDeviceInfo());
console.log(deviceInfo.manufacturer, deviceInfo.model);Android code executes JavaScript functions:
// Call a JavaScript function with parameters
webView.evaluateJavascript("onPermissionResult('camera', 'granted')", null)Android can push events to JavaScript automatically:
// Start listening for Android events
Android.startEventListening();
// Handle events from Android
function onAndroidEvent(eventName, data) {
if (eventName === 'battery_changed') {
console.log('Battery:', data.percentage + '%');
console.log('Charging:', data.isCharging);
} else if (eventName === 'network_changed') {
console.log('Network:', data.networkType);
}
}
// Stop listening
Android.stopEventListening();Available events:
battery_changed- Battery level, charging status, temperaturenetwork_changed- Network connectivity and typelifecycle- App resume/pause eventsscreen_on/screen_off- Screen state changes
Download and play videos outside the WebView:
// Download a video with progress tracking
Android.downloadVideo('https://example.com/video.mp4', 'myvideo.mp4');
// Handle download progress
function onVideoDownloadProgress(fileName, percent) {
console.log('Downloading ' + fileName + ': ' + percent + '%');
}
// Handle download completion
function onVideoDownloadComplete(fileName, filePath) {
console.log('Downloaded: ' + fileName);
// Now you can play it
Android.playVideo(fileName);
}
// Check if video is already downloaded
if (Android.isVideoDownloaded('myvideo.mp4') === 'true') {
// Play the video in native player
Android.playVideo('myvideo.mp4');
}
// List all downloaded videos
const result = JSON.parse(Android.getDownloadedVideos());
console.log('Downloaded videos:', result.videos);
// Get video file size
const size = JSON.parse(Android.getVideoSize('myvideo.mp4'));
console.log('Size:', size.formatted); // e.g., "15 MB"
// Delete a video
Android.deleteVideo('myvideo.mp4');The video plays in a native Android VideoView activity, completely outside the WebView, demonstrating true native-web integration.
./gradlew assembleDebug./gradlew installDebug./gradlew test
./gradlew connectedAndroidTestTo add a new native Android feature to the bridge:
- Add the method to WebAppInterface.kt:
@JavascriptInterface
fun yourNewFeature(param: String): String {
// Your Android code here
return "result"
}- Add required permissions to AndroidManifest.xml (if needed):
<uses-permission android:name="android.permission.YOUR_PERMISSION" />
<uses-feature android:name="android.hardware.feature" android:required="false" />- Call from JavaScript:
const result = Android.yourNewFeature("parameter");The application loads an embedded HTML page with a modern, responsive UI that includes:
- Device information display
- Interactive buttons for testing native features
- Permission request controls
- Share/external action buttons
- Video download with progress bar and offline playback
- Real-time Android event viewer (battery, network, lifecycle)
- Debug console showing all interactions
All UI is styled with CSS and uses vanilla JavaScript (no frameworks required).
The app includes a comprehensive event system that demonstrates push notifications from Android to JavaScript:
- Click "Start Listening" to register for system events
- Android broadcast receivers capture system changes
- Events are automatically pushed to JavaScript in real-time
- See live updates for:
- Battery level changes and charging status
- Network connectivity changes
- App lifecycle (when you switch apps)
- Screen on/off (when you lock/unlock device)
This demonstrates the complete bidirectional communication pattern - JavaScript can call Android methods, and Android can push updates back to JavaScript without polling.
- Language: Kotlin
- Min SDK: 35 (Android 15)
- Target SDK: 36
- Bridge: @JavascriptInterface annotation
- Permissions: Activity Result API
- Back Navigation: OnBackPressedDispatcher
This demo is ideal for:
- Converting PWAs to native Android apps
- Adding native features to web applications
- Training teams transitioning from web to mobile
- Understanding WebView-Android communication patterns
- Prototyping hybrid mobile applications
- JavaScript is enabled in the WebView (required for bridge)
- The
@JavascriptInterfaceannotation exposes methods to JavaScript - Be cautious when loading external URLs - only load trusted content
- Validate all input from JavaScript before using in Android code
- Consider using HTTPS for remote content
This is a demonstration project for educational purposes.