A complete prototype system demonstrating Over-The-Air (OTA) updates for a Flutter app using a WebView to render a VueJS-based UI with bi-directional JavaScript-to-Flutter native bridge communication.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Flutter App β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β WebView Container β β
β β ββββββββββββββββββββββββββββββββββββββββββββββ β β
β β β VueJS Web Application β β β
β β β β’ TypeScript β β β
β β β β’ Scanner UI Button β β β
β β β β’ Native Bridge (JS β Flutter) β β β
β β ββββββββββββββββββββββββββββββββββββββββββββββ β β
β β β β β
β β JavascriptChannel Bridge β β
β β β β β
β β ββββββββββββββββββββββββββββββββββββββββββββββ β β
β β β Flutter Native Layer β β β
β β β β’ Native Bridge Handler β β β
β β β β’ Mobile Scanner (Camera) β β β
β β β β’ OTA Update Service β β β
β β ββββββββββββββββββββββββββββββββββββββββββββββ β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
Network (HTTP)
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Backend OTA Server β
β β’ Express.js + TypeScript β
β β’ Serves version.json β
β β’ Serves web assets β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ota_prototype/
βββ webui/ # VueJS Web App
β βββ src/
β β βββ App.vue # Main Vue component with scanner UI
β β βββ main.ts # Entry point with bridge setup
β β βββ types/
β β β βββ native-bridge.d.ts # TypeScript definitions
β β βββ style.css
β βββ index.html
β βββ package.json
β βββ vite.config.ts
β βββ tsconfig.json
β
βββ flutter_app/ # Flutter Native App
β βββ lib/
β β βββ main.dart # App entry with OTA check
β β βββ screens/
β β β βββ webview_screen.dart # WebView container
β β βββ services/
β β β βββ native_bridge.dart # Bridge handler
β β β βββ ota_service.dart # OTA update logic
β β βββ widgets/
β β βββ scanner_overlay.dart # Scanner UI
β βββ android/
β β βββ app/src/main/AndroidManifest.xml # Permissions
β βββ ios/
β β βββ Runner/Info.plist # iOS permissions
β βββ pubspec.yaml # Dependencies
β βββ assets/webui/ # Bundled web assets
β
βββ backend/ # OTA Update Server
β βββ src/
β β βββ server.ts # Express server
β βββ assets/ # Served web assets
β β βββ version.json # Version manifest
β βββ package.json
β βββ tsconfig.json
β
βββ build.sh # Build automation script
βββ task.md # Original specification
βββ README.md # This file
- Node.js (v18+)
- Flutter SDK (3.0+)
- Android Studio / Xcode (for mobile development)
cd webui
npm install
npm run buildcd flutter_app
flutter pub get
# Copy web assets to Flutter assets folder
mkdir -p assets/webui
cp -r ../webui/dist/* assets/webui/cd backend
npm install
# Copy web assets to backend
mkdir -p assets
cp -r ../webui/dist/* assets/
# Start server
npm run devThe server will run on http://localhost:3000
cd flutter_app
flutter runImportant: Update the OTA server URL in lib/services/ota_service.dart based on your platform:
- Android Emulator:
http://10.0.2.2:3000 - iOS Simulator:
http://localhost:3000 - Physical Device:
http://<YOUR_COMPUTER_IP>:3000
chmod +x build.sh
./build.sh- App Launch: Flutter app checks backend for new version
- Version Check: Compares local version with
version.jsonfrom server - Download: If newer version available, downloads all files
- Atomic Replace: Downloads to temp folder, then swaps atomically
- Reload: WebView loads updated assets
// In VueJS
window.NativeBridgeChannel.postMessage(
JSON.stringify({ type: "scanner", action: "open" })
);// In Flutter
controller.runJavaScript(
"window.onFlutterScanResult('scanned_code_here');"
);- User clicks "Scan QR/Barcode" button in VueJS UI
- VueJS sends message via
NativeBridgeChannel - Flutter receives message and shows camera scanner overlay
- User scans code
- Flutter sends result back to JavaScript
- VueJS displays the scanned code
- VueJS 3 + TypeScript web app
- Vite build system for optimized assets
- Flutter WebView integration
- Bi-directional native bridge
- Mobile camera scanner (QR/Barcode)
- OTA update mechanism with version checking
- Atomic asset replacement
- Express.js backend server
- TypeScript throughout
- Android & iOS support
- Camera permissions handling
- Network connectivity for OTA
| Type | Direction | Description |
|---|---|---|
scanner |
JS β Flutter | Opens camera scanner |
showDialog |
JS β Flutter | Shows native alert dialog |
getDeviceInfo |
JS β Flutter | Requests device information |
onFlutterScanResult |
Flutter β JS | Returns scanned code |
onFlutterMessage |
Flutter β JS | Generic Flutter response |
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET" /><key>NSCameraUsageDescription</key>
<string>This app needs camera access to scan QR codes</string>Default: 3000
Change in backend/src/server.ts:
const PORT = 3000;Configure in flutter_app/lib/services/ota_service.dart:
static const String _updateUrlBase = 'http://10.0.2.2:3000';Version is stored in version.json:
{
"version": "1.0.0",
"timestamp": "2025-11-10T00:00:00.000Z",
"files": ["index.html", "assets/index.css", "assets/index.js"]
}- Build and run the app with initial assets
- Modify the VueJS app (e.g., change button text)
- Rebuild:
cd webui && npm run build - Update backend assets:
cp -r dist/* ../backend/assets/ - Update version in
backend/assets/version.json - Restart the Flutter app
- App should detect and download the update
vue^3.4.0vite^5.0.0typescript^5.3.0
webview_flutter^4.4.0mobile_scanner^3.5.0http^1.1.0path_provider^2.1.0shared_preferences^2.2.0
express^4.18.0cors^2.8.5typescript^5.3.0
- Check file paths in
webview_screen.dart - Verify assets are in
flutter_app/assets/webui/ - Check
pubspec.yamlincludes assets folder
- Verify backend server is running
- Check network connectivity
- Verify correct IP/URL for your platform
- Check version.json is properly formatted
- Verify camera permissions are granted
- Check
AndroidManifest.xmlandInfo.plist - Test on physical device (camera not available on emulators)
- Check JavaScript console in WebView
- Verify
JavascriptChannelis registered - Ensure JSON.stringify is used for messages
This is a prototype for educational purposes.
Built following the specification in task.md with complete TypeScript integration and modern best practices.
Ready to test! Follow the Getting Started guide above to build and run the complete system.