Android TV Remote
Control Android TV devices from Flutter: discover, pair, and send remote commands (DPAD, Home, Back, media, etc.) over the Android TV Remote protocol.
Note: Works with Android/Google TV devices that support the official Remote pairing flow.
β¨ Features
- π Network Connection - Connect to Android/Google TV over local network
- π Secure Pairing - PIN-based pairing via mutual TLS authentication
- ποΈ Remote Commands - Send DPAD, Home, Back, Play/Pause, Volume, and more
- π¦ Simple API - Clean workflow: initialize β connect β show PIN β pair β control
π¦ Installation
Add this package to your pubspec.yaml
:
dependencies:
androidtvremote: ^0.0.1
π Certificate Setup (Required for iOS)
This plugin uses mutual TLS to securely pair with your TV. You need two certificate files:
cert.der
- Client certificate (DER format)cert.p12
- PKCS#12 archive (contains private key + certificate)
Generate Certificates with OpenSSL
Option 1: No Password (Development)
# 1. Generate a private key
openssl genrsa -out client.key 2048
# 2. Create self-signed certificate
openssl req -new -x509 -key client.key -out client.crt -days 1825 \
-subj "/CN=androidtvremote"
# 3. Export to DER format
openssl x509 -in client.crt -outform der -out cert.der
# 4. Export PKCS#12 without password
openssl pkcs12 -export -out cert.p12 -inkey client.key -in client.crt \
-passout pass:
Option 2: Password-Protected (Production)
# Follow steps 1-3 above, then:
# 4. Export PKCS#12 with password
openssl pkcs12 -export -out cert.p12 -inkey client.key -in client.crt \
-passout pass:YOUR_SECURE_PASSWORD
β οΈ Security Warning: Keep your private key and P12 file secure! Never commit them to public repositories.
Add Certificates to Flutter App
- Place the certificate files in your
assets/
directory - Update your
pubspec.yaml
:
flutter:
assets:
- assets/cert.der
- assets/cert.p12
Note: On iOS, the plugin copies these files to app storage before use.
π Quick Start
import 'package:androidtvremote/androidtvremote.dart';
Future<void> connectAndControl(String tvIp, String pin) async {
try {
// Initialize with certificate paths
await Androidtvremote.initializeWithCertificatePaths(
certDerPath: '/path/to/cert.der',
certP12Path: '/path/to/cert.p12',
// certP12Password: 'YOUR_PASSWORD', // if using password-protected P12
);
// Connect to TV
await Androidtvremote.connect(tvIp);
// Pair with PIN shown on TV screen
await Androidtvremote.sendCode(pin);
// Now you can control the TV
await Androidtvremote.dpadCenter();
await Androidtvremote.home();
await Androidtvremote.playPause();
} on TVRemoteException catch (e) {
print('Error: ${e.message}');
}
}
π§© Complete Example with GetX Controller
Here's a comprehensive controller implementation:
class RemoteController extends GetxController {
final RxBool isConnected = false.obs;
final RxBool isConnecting = false.obs;
final RxString errorMessage = ''.obs;
final RxString currentTVIP = ''.obs;
/// Connect to Android TV
Future<void> connect(String tvIp, String certDerPath, String certP12Path) async {
isConnecting.value = true;
errorMessage.value = '';
try {
await Androidtvremote.initializeWithCertificatePaths(
certDerPath: certDerPath,
certP12Path: certP12Path,
);
await Androidtvremote.connect(tvIp);
currentTVIP.value = tvIp;
} on TVRemoteException catch (e) {
errorMessage.value = e.message ?? 'Connection failed';
} finally {
isConnecting.value = false;
}
}
/// Pair with TV using PIN
Future<void> pair(String pin) async {
try {
await Androidtvremote.sendCode(pin);
isConnected.value = true;
errorMessage.value = '';
} on TVRemoteException catch (e) {
errorMessage.value = e.message ?? 'Pairing failed';
}
}
/// Navigation Commands
Future<void> dpadUp() => Androidtvremote.dpadUp();
Future<void> dpadDown() => Androidtvremote.dpadDown();
Future<void> dpadLeft() => Androidtvremote.dpadLeft();
Future<void> dpadRight() => Androidtvremote.dpadRight();
Future<void> dpadCenter() => Androidtvremote.dpadCenter();
/// System Commands
Future<void> home() => Androidtvremote.home();
Future<void> back() => Androidtvremote.back();
/// Media Commands
Future<void> playPause() => Androidtvremote.playPause();
}
π― Available Commands
Navigation
dpadUp()
- Navigate updpadDown()
- Navigate downdpadLeft()
- Navigate leftdpadRight()
- Navigate rightdpadCenter()
- Select/OK
System
home()
- Go to home screenback()
- Go back
Media Control
playPause()
- Toggle play/pause
π οΈ Troubleshooting
Issue | Solution |
---|---|
TVRemoteException | Pairing failed or TV rejected certificate. Verify certificates and TV compatibility |
PIN not showing | Ensure device supports Android TV Remote protocol and is on the same network |
Certificate errors | Verify assets are included in build and copied to writable directory |
Password-protected P12 | Use certP12Password parameter in initialization |
π± Platform Support
Platform | Status |
---|---|
iOS | β Fully supported |
Android | β³ Coming soon |
π Security Best Practices
- Never commit certificates to public repositories
- Use password-protected P12 files in production
- Store passwords securely using environment variables or platform keychain
- Regenerate certificates periodically for enhanced security
π€ Contributing
We welcome contributions! Please feel free to submit issues and pull requests.
π Support
- Email: mohammadhanan824@gmail.com
- GitHub: @hanan0007
For bugs and feature requests, please open an issue on GitHub.
π License
This project is licensed under the MIT License - see the LICENSE file for details.
Made with β€οΈ by Mohammad Hanan
Libraries
- androidtvremote
- A Flutter plugin for controlling Android TV devices via remote control protocols.
- androidtvremote_method_channel
- androidtvremote_platform_interface