ussd_advanced_flutter
A Flutter plugin that allows you to send and read USSD codes programmatically on Android β with support for dual-SIM devices, real-time streaming, and timeout handling.
πͺ Works through a custom Android Accessibility Service β no root required.
π Features
β
Send USSD codes directly from Flutter
β
Receive the final USSD response as a Future
β
Listen to all intermediate USSD messages in real time
β
Choose which SIM slot to use (dual-SIM supported)
β
Built-in timeout, no-SIM, and weak-signal handling
β
Works on Android 6.0+ with Kotlin backend
π¦ Installation
Add this to your pubspec.yaml:
dependencies:
ussd_advanced_flutter: ^1.0.0
Then run:
flutter pub get
βοΈ Android Setup
1οΈβ£ Add required permissions
In your appβs AndroidManifest.xml (under android/app/src/main):
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"
tools:ignore="ProtectedPermissions" />
```
#### 2οΈβ£ Register the Accessibility Service
Inside the `<application>` tag:
```xml
<service
android:name="com.example.ussd_advanced_flutter.UssdAccessibilityService"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
android:exported="true">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
<meta-data
android:name="android.accessibilityservice"
android:resource="@xml/ussd_accessibility_service_config" />
</service>
Ensure the file xml/ussd_accessibility_service_config.xml exists in:
android/app/src/main/res/xml/
π§© Example Usage
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:ussd_advanced_flutter/ussd_advanced_flutter.dart';
void main() => runApp(const MyApp());
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String? _lastResponse;
@override
void initState() {
super.initState();
UssdAdvancedFlutter.ussdStream.listen((event) {
debugPrint('USSD Stream: $event');
});
}
Future<void> _ensurePermissions() async {
final status = await Permission.phone.request();
if (!status.isGranted) openAppSettings();
}
Future<void> _sendUssd() async {
await _ensurePermissions();
try {
final response = await UssdAdvancedFlutter.sendUssdForResponse(
'*100#',
simSlot: 0,
timeout: const Duration(seconds: 10),
);
setState(() => _lastResponse = response);
} catch (e) {
debugPrint('USSD Error: $e');
}
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('USSD Advanced Example')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: UssdAdvancedFlutter.openAccessibilitySettings,
child: const Text('Enable Accessibility Service'),
),
const SizedBox(height: 16),
ElevatedButton(
onPressed: _sendUssd,
child: const Text('Send *100#'),
),
const SizedBox(height: 16),
Text('Response:\n${_lastResponse ?? "β"}'),
],
),
),
),
);
}
}
π API Reference
| Method | Description |
|---|---|
sendUssd(String code, {int simSlot = 0}) |
Sends a USSD code (fire-and-forget). |
sendUssdForResponse(String code, {int simSlot = 0, Duration timeout}) |
Sends a USSD code and waits for the final response. |
ussdStream |
Broadcast stream of all live USSD responses. |
openAccessibilitySettings() |
Opens Android settings to enable the pluginβs service. |
β οΈ Limitations
- Android only β iOS doesnβt allow USSD automation.
- User must manually enable the Accessibility Service for this plugin.
- Some OEMs (Xiaomi, Huawei, Oppo) may require keeping the app in the background whitelist.
- USSD session duration depends on the carrier β recommended timeout: 8β12 seconds.
π§° Troubleshooting
| Problem | Solution |
|---|---|
| No USSD responses received. | Increase timeout or check signal strength. |
PlatformException(PERMISSION) |
Grant CALL_PHONE and READ_PHONE_STATE permissions. |
No MaterialLocalizations found. |
Wrap your app with MaterialApp. |
| No SIM card detected. | Insert and activate a SIM before running. |
| Weak or dropped signal. | Move to an area with better reception and retry. |
π Example (short version for pub.flutter-io.cn)
final resp = await UssdAdvancedFlutter.sendUssdForResponse(
"*100#",
simSlot: 0,
timeout: const Duration(seconds: 10),
);
print(resp); // Example: "Your balance is 989.49 SYP"
π§βπ» Author
Numa Alset π GitHub: numaalset π§ numaalset@gmail.com
πͺͺ License
MIT License β see LICENSE for details.