Flutter USSD指令发射插件ussd_launcher的使用
Flutter USSD指令发射插件 ussd_launcher
的使用
ussd_launcher
是一个用于在 Android 设备上直接从应用程序中启动 USSD 请求并管理多步 USSD 会话的 Flutter 插件。以下是该插件的详细使用说明。
特性
- 发射简单的 USSD 请求
- 管理多步 USSD 会话
- 检查和请求必要的辅助功能权限
- 兼容 API 级别 26 及以上的 Android 设备
- 优雅地处理 USSD 响应和错误
- 如果服务未启用,则打开辅助功能设置
- 获取 SIM 卡信息
安装
在 pubspec.yaml
文件中添加 ussd_launcher
作为依赖项:
dependencies:
ussd_launcher: ^latest_version
请确保将 ^latest_version
替换为实际可用的最新版本号。
配置
Android
你需要在 Android 清单文件中添加以下权限:
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
多会话 USSD 支持
在 Android 清单文件中添加 USSD 对话辅助功能服务:
<application>
...
<service
android:name="com.kavina.ussd_launcher.UssdAccessibilityService"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
android:exported="false">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
<meta-data
android:name="android.accessibilityservice"
android:resource="@xml/accessibility_service_config" />
</service>
</application>
使用方法
示例代码
以下是一个完整的示例应用,展示了如何使用 ussd_launcher
插件进行单步和多步 USSD 请求。
import 'package:flutter/material.dart';
import 'package:ussd_launcher/ussd_launcher.dart';
import 'package:permission_handler/permission_handler.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
title: const Text('USSD Launcher Demo'),
bottom: const TabBar(
tabs: [
Tab(text: 'Single Session'),
Tab(text: 'Multi Session'),
],
),
),
body: const TabBarView(
children: [
SingleSessionTab(),
MultiSessionTab(),
],
),
),
),
);
}
}
class SingleSessionTab extends StatefulWidget {
const SingleSessionTab({super.key});
[@override](/user/override)
_SingleSessionTabState createState() => _SingleSessionTabState();
}
class _SingleSessionTabState extends State<SingleSessionTab> {
final TextEditingController _controller = TextEditingController();
String _ussdResponse = '';
List<Map<String, dynamic>> _simCards = [];
int? _selectedSimId;
[@override](/user/override)
void initState() {
super.initState();
_loadSimCards();
}
Future<void> _loadSimCards() async {
var status = await Permission.phone.request();
if (status.isGranted) {
try {
final simCards = await UssdLauncher.getSimCards();
setState(() {
_simCards = simCards;
if (simCards.isNotEmpty) {
_selectedSimId = simCards[0]['subscriptionId'] as int?;
}
});
} catch (e) {
print("Erreur lors du chargement des cartes SIM: $e");
}
} else {
print("Permission téléphone non accordée");
}
}
Future<void> _sendUssdRequest() async {
setState(() {
_ussdResponse = 'Envoi de la requête USSD...';
});
try {
String? response = await UssdLauncher.sendUssdRequest(
ussdCode: _controller.text,
subscriptionId: _selectedSimId ?? -1,
);
setState(() {
_ussdResponse = response ?? 'Aucune réponse reçue';
});
} catch (e) {
setState(() {
_ussdResponse = 'Erreur: ${e.toString()}';
});
}
}
[@override](/user/override)
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
DropdownButton<int>(
value: _selectedSimId,
hint: const Text('Sélectionner SIM'),
items: _simCards.map((sim) {
return DropdownMenuItem<int>(
value: sim['subscriptionId'],
child: Text("${sim['displayName']} (${sim['carrierName']})"),
);
}).toList(),
onChanged: (value) {
setState(() {
_selectedSimId = value;
});
},
),
const SizedBox(height: 16),
TextField(
controller: _controller,
decoration: const InputDecoration(labelText: 'Entrer le code USSD'),
),
const SizedBox(height: 16),
ElevatedButton(
onPressed: _sendUssdRequest,
child: const Text('Envoyer USSD'),
),
const SizedBox(height: 16),
const Text('Réponse USSD :'),
Text(
_ussdResponse,
style: const TextStyle(color: Colors.blue, fontWeight: FontWeight.bold),
),
],
),
);
}
[@override](/user/override)
void dispose() {
_controller.dispose();
super.dispose();
}
}
class MultiSessionTab extends StatefulWidget {
const MultiSessionTab({super.key});
[@override](/user/override)
_MultiSessionTabState createState() => _MultiSessionTabState();
}
class _MultiSessionTabState extends State<MultiSessionTab> {
final TextEditingController _ussdController = TextEditingController();
final List<TextEditingController> _optionControllers = [];
List<String> _ussdMessages = []; // Liste pour stocker les messages USSD
bool _isLoading = false;
List<Map<String, dynamic>> _simCards = [];
int? _selectedSlotIndex;
String _sessionStatus = '';
[@override](/user/override)
void initState() {
super.initState();
_loadSimCards();
// Configurer le listener pour les messages USSD
UssdLauncher.setUssdMessageListener(_onUssdMessageReceived);
}
/// Méthode appelée lorsque un message USSD est reçu.
void _onUssdMessageReceived(String message) {
print("Message USSD reçu: $message"); // Journalisation
setState(() {
// Ne garder que le dernier message
_ussdMessages = [message];
if (message.contains("completed") || message.contains("cancelled")) {
_sessionStatus = "Session USSD terminée.";
}
});
}
Future<void> _loadSimCards() async {
var statut = await Permission.phone.request();
if (statut.isGranted) {
final simCards = await UssdLauncher.getSimCards();
setState(() {
_simCards = simCards;
if (simCards.isNotEmpty) {
_selectedSlotIndex = simCards[0]['slotIndex'];
}
});
} else {
print("Permission téléphone non accordée");
}
}
void _launchMultiSessionUssd() async {
setState(() {
_isLoading = true;
_ussdMessages.clear(); // Réinitialiser la liste au début d'une nouvelle session
_sessionStatus = '';
});
try {
List<String> options = _optionControllers.map((controller) => controller.text).toList();
await UssdLauncher.multisessionUssd(
code: _ussdController.text,
slotIndex: (_selectedSlotIndex ?? 0),
options: options,
);
// Aucun besoin de gérer 'res1' ici, les messages sont reçus via le listener
} catch (e) {
_updateUssdMessages('\nErreur : ${e.toString()}');
} finally {
setState(() {
_isLoading = false;
});
}
}
void _updateUssdMessages(String newText) {
setState(() {
_ussdMessages.add(newText);
});
}
void _addOptionField() {
setState(() {
_optionControllers.add(TextEditingController());
});
}
void _removeOptionField() {
setState(() {
if (_optionControllers.isNotEmpty) {
_optionControllers.removeLast().dispose();
}
});
}
[@override](/user/override)
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(16.0),
child: SingleChildScrollView(
child: Column(
children: [
// Affichage en temps réel de slotIndex
Text(
'Slot SIM sélectionné : ${_selectedSlotIndex ?? "Aucun"}',
style: const TextStyle(fontWeight: FontWeight.bold),
),
const SizedBox(height: 16),
DropdownButton<int>(
value: _selectedSlotIndex,
hint: const Text('Sélectionner SIM'),
items: _simCards.map((sim) {
return DropdownMenuItem<int>(
value: sim['slotIndex'],
child: Text("${sim['displayName']} (${sim['carrierName']})"),
);
}).toList(),
onChanged: (value) {
setState(() {
_selectedSlotIndex = value;
});
},
),
const SizedBox(height: 16),
TextField(
controller: _ussdController,
decoration: const InputDecoration(labelText: 'Entrer le code USSD'),
),
..._optionControllers.asMap().entries.map((entry) {
return Padding(
padding: const EdgeInsets.only(top: 8.0),
child: TextField(
controller: entry.value,
keyboardType: TextInputType.number,
decoration: InputDecoration(labelText: 'Option ${entry.key + 1}'),
),
);
}),
const SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
onPressed: _addOptionField,
child: const Text('Ajouter Option'),
),
ElevatedButton(
onPressed: _optionControllers.isNotEmpty ? _removeOptionField : null,
child: const Text('Retirer Option'),
),
],
),
const SizedBox(height: 16),
ElevatedButton(
onPressed: _isLoading ? null : _launchMultiSessionUssd,
child: const Text('Lancer USSD Multi-Session'),
),
const SizedBox(height: 16),
const Text('Réponses USSD :'),
Container(
height: 200,
decoration: BoxDecoration(
border: Border.all(color: Colors.blueAccent),
borderRadius: BorderRadius.circular(8.0),
),
padding: const EdgeInsets.all(8.0),
child: ListView.builder(
itemCount: _ussdMessages.length,
itemBuilder: (context, index) {
final isLastMessage = index == _ussdMessages.length - 1;
return Text(
_ussdMessages[index],
style: TextStyle(
color: isLastMessage ? Colors.red : Colors.blue,
fontWeight: isLastMessage ? FontWeight.bold : FontWeight.normal,
fontSize: isLastMessage ? 16 : 14,
),
);
},
),
),
const SizedBox(height: 16),
if (_sessionStatus.isNotEmpty)
Text(
_sessionStatus,
style: const TextStyle(color: Colors.green, fontWeight: FontWeight.bold),
),
],
),
),
);
}
[@override](/user/override)
void dispose() {
// Nettoyer les contrôleurs de texte
for (var controller in _optionControllers) {
controller.dispose();
}
_ussdController.dispose();
super.dispose();
}
}
更多关于Flutter USSD指令发射插件ussd_launcher的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter USSD指令发射插件ussd_launcher的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是一个关于如何在Flutter项目中使用ussd_launcher
插件来发射USSD指令的示例代码。这个插件允许你通过Flutter应用发送USSD请求,并接收响应。
首先,确保你已经在pubspec.yaml
文件中添加了ussd_launcher
依赖:
dependencies:
flutter:
sdk: flutter
ussd_launcher: ^最新版本号 # 请替换为当前最新版本号
然后,运行flutter pub get
来获取依赖。
接下来,在你的Flutter项目中,你可以按照以下步骤使用ussd_launcher
插件:
1. 导入插件
在你的Dart文件中导入ussd_launcher
:
import 'package:ussd_launcher/ussd_launcher.dart';
2. 请求USSD代码
你可以使用UssdLauncher().launch
方法来发送USSD请求。下面是一个完整的示例,展示如何在一个按钮点击事件中发送USSD请求并处理响应:
import 'package:flutter/material.dart';
import 'package:ussd_launcher/ussd_launcher.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'USSD Launcher Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String _ussdResponse = "";
void _launchUssdCode() async {
String code = "*100#"; // 替换为你想要发送的USSD代码
try {
String result = await UssdLauncher().launch(code);
setState(() {
_ussdResponse = result;
});
} catch (e) {
setState(() {
_ussdResponse = "Error: ${e.message}";
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('USSD Launcher Demo'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'USSD Response:',
style: TextStyle(fontSize: 20),
),
SizedBox(height: 10),
Text(
_ussdResponse,
style: TextStyle(fontSize: 18),
textAlign: TextAlign.center,
),
SizedBox(height: 20),
ElevatedButton(
onPressed: _launchUssdCode,
child: Text('Launch USSD Code'),
),
],
),
),
);
}
}
3. 运行应用
将上述代码添加到你的Flutter项目中,然后运行应用。点击按钮后,应用将尝试发送指定的USSD代码,并在界面上显示响应结果。
注意事项
- 并非所有设备和运营商都支持通过编程方式发送USSD请求。在某些设备上,可能需要用户手动确认权限。
- 在实际开发中,处理异常和错误响应是非常重要的,以确保用户有良好的体验。
- 请确保你遵守所有适用的隐私政策和法律要求,尤其是在处理用户信息和通信数据时。
希望这个示例代码能帮助你理解如何在Flutter项目中使用ussd_launcher
插件来发射USSD指令。