hackrf_flutter 0.0.2
hackrf_flutter: ^0.0.2 copied to clipboard
A Flutter plugin for interfacing with HackRF devices. Supports Android platform.
HackRF Flutter Plugin #
A Flutter plugin for interfacing with HackRF One software-defined radios on Android. This library bridges your Flutter app and the native hackrf_android Java library, enabling direct control and transmission via HackRF from Dart.
Ideal for mobile SDR (Software Defined Radio) applications, remote-control transmitters, educational radio tools, and more.
Features #
- Automatic Device Discovery: Detects HackRF devices and requests required USB permissions.
- Device Information: Retrieve the board ID of the connected HackRF.
- Transmission Control:
- Set transmission frequency (
setFrequency) - Set sample rate (
setSampleRate) - Set TX VGA (IF) gain (
setTxVgaGain) - Start and stop transmission (
startTx,stopTx)
- Set transmission frequency (
- Data Streaming: Send I/Q data (
Uint8Listbuffers) to HackRF for direct transmission.
Requirements #
Hardware #
- HackRF One (or compatible device, e.g., Rad1o)
- Android device with USB OTG support
- USB OTG cable/adapter to connect HackRF
Software #
- Android only: Uses native Android libraries (no iOS support)
- Minimum Android SDK version:
minSdkVersion21 or higher
Installation #
1. Add the Dependency #
Add to your pubspec.yaml:
dependencies:
flutter:
sdk: flutter
hackrf_flutter:
path: ../hackrf_flutter # Adjust path to your plugin location if necessary
Run:
flutter pub get
2. Android Configuration (Required!) #
A. Update minSdkVersion
In android/app/build.gradle:
android {
defaultConfig {
minSdkVersion 21
// ...other config...
}
}
B. Custom MainActivity for Plugin Registration
Create android/app/src/main/kotlin/com/yourcompany/yourapp/MainActivity.kt (adjust package name):
package com.yourcompany.yourapp // Change to your actual package name
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import com.sarahroselives.hackrf_flutter.HackrfFlutterPlugin // Import your plugin
class MainActivity: FlutterActivity() {
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
// Register plugin
flutterEngine.plugins.add(HackrfFlutterPlugin())
}
}
C. Update AndroidManifest.xml
Ensure your manifest points to your new MainActivity:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application ...>
<activity
android:name=".MainActivity"
android:exported="true"
...>
<!-- ...your intent filters... -->
</activity>
<!-- ... -->
</application>
</manifest>
Usage Example #
Here's a basic example that initializes HackRF and starts transmission:
import 'package:flutter/material.dart';
import 'dart:typed_data';
import 'dart:math';
import 'package:hackrf_flutter/hackrf_flutter.dart';
class RadioScreen extends StatefulWidget {
const RadioScreen({super.key});
@override
State<RadioScreen> createState() => _RadioScreenState();
}
class _RadioScreenState extends State<RadioScreen> {
final _hackrf = HackrfFlutter();
bool _isInitialized = false;
bool _isTransmitting = false;
@override
void initState() {
super.initState();
initDevice();
}
Future<void> initDevice() async {
try {
bool? success = await _hackrf.init();
if (success ?? false) {
setState(() => _isInitialized = true);
print("HackRF Initialized!");
int? boardId = await _hackrf.getBoardId();
print("Board ID: $boardId");
} else {
print("Failed to initialize HackRF. Is it connected?");
}
} catch (e) {
print("Error initializing HackRF: $e");
}
}
Future<void> startTransmission() async {
if (!_isInitialized) return;
// Generate I/Q data (262,144 bytes)
const packetSize = 262144;
final iqData = Int8List(packetSize);
for (int i = 0; i < packetSize; i += 2) {
final angle = 2 * pi * (i / 2) / 100.0;
iqData[i] = (sin(angle) * 127).round(); // I
iqData[i + 1] = (cos(angle) * 127).round(); // Q
}
try {
await _hackrf.setFrequency(433920000); // 433.92 MHz
await _hackrf.setSampleRate(8000000); // 8 MSPS
await _hackrf.setTxVgaGain(30); // 30 dB (0–47)
await _hackrf.startTx();
setState(() => _isTransmitting = true);
print("TRANSMITTING...");
while (_isTransmitting) {
await _hackrf.sendData(iqData.buffer.asUint8List());
}
} catch (e) {
print("Transmission error: $e");
}
}
Future<void> stopTransmission() async {
setState(() => _isTransmitting = false); // Breaks loop
await _hackrf.stopTx();
print("Transmission stopped.");
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ElevatedButton(
onPressed: _isTransmitting ? stopTransmission : startTransmission,
child: Text(_isTransmitting ? 'Stop Transmit' : 'Start Transmit'),
),
),
);
}
}
How It Works #
- Flutter (Dart): You call methods such as
_hackrf.setFrequency(). - MethodChannel: Dart sends method calls to the native side using Flutter MethodChannel.
- Native Plugin (
HackrfFlutterPlugin.kt): Receives calls, delegates to Java code. - Java Library (
Hackrf.javain demantz/hackrf_android): Handles USB communication with HackRF. - HackRF Device: Executes the requested command.
This plugin is a direct bridge to hackrf_android—all core SDR logic and USB handling is provided by that Java library.