main.dart 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. import 'dart:async';
  2. import 'dart:isolate';
  3. import 'dart:math';
  4. import 'dart:ui';
  5. import 'package:fast_gbk/fast_gbk.dart';
  6. import 'package:flutter/material.dart';
  7. import 'package:mqtt_client/mqtt_client.dart';
  8. import 'package:mqtt_client/mqtt_server_client.dart';
  9. import 'package:flutter_notification_listener/flutter_notification_listener.dart';
  10. import 'package:uuid/uuid.dart';
  11. Future<void> main() async {
  12. runApp(const MyApp());
  13. }
  14. class MyApp extends StatelessWidget {
  15. const MyApp({super.key});
  16. @override
  17. Widget build(BuildContext context) {
  18. return MaterialApp(
  19. title: 'MokiBox',
  20. theme: ThemeData(
  21. primarySwatch: Colors.blue,
  22. ),
  23. home: const MyHomePage(title: 'Moki收款宝'),
  24. );
  25. }
  26. }
  27. class Listener {
  28. Mqtt mqtt = Mqtt();
  29. Listener() {
  30. initPlatformState();
  31. }
  32. @pragma('vm:entry-point')
  33. static void _callback(NotificationEvent evt) {
  34. final SendPort? send =
  35. IsolateNameServer.lookupPortByName("notifications_send_port");
  36. if (send == null) print("can't find the sender");
  37. send?.send(evt);
  38. }
  39. void testSendMsg() {
  40. String msg =
  41. "{\"type\":\"tts_dynamic\",\"msgid\":\"${Random().nextInt(999999)}\",\"txt\":\"设备已连接!\"}";
  42. mqtt.sendMsg(msg);
  43. }
  44. void onData(NotificationEvent event) {
  45. String? msg;
  46. if (event.packageName == 'com.eg.android.AlipayGphone' &&
  47. event.title == '店员通') {
  48. msg = event.text;
  49. if (msg == null) return;
  50. final number = RegExp(r'\d+\.\d+').firstMatch(msg);
  51. final orderId = Random().nextInt(999999);
  52. if (number != null) {
  53. final regAmount = double.parse(number.group(0)!);
  54. String amount = regAmount.toStringAsFixed(2);
  55. if (amount.endsWith('.00')) {
  56. amount = amount.replaceAll('.00', '');
  57. }
  58. String msgPush = '866374061547503|1007-2|$orderId|2001|$amount|7571';
  59. mqtt.sendMsg(msgPush);
  60. }
  61. }
  62. if (event.packageName == 'com.tencent.mm' && event.title == '微信收款助手') {
  63. msg = event.text;
  64. if (msg == null) return;
  65. final number = RegExp(r'\d+\.\d+').firstMatch(msg);
  66. final orderId = Random().nextInt(999999);
  67. if (number != null) {
  68. final regAmount = double.parse(number.group(0)!);
  69. String amount = regAmount.toStringAsFixed(2);
  70. if (amount.endsWith('.00')) {
  71. amount = amount.replaceAll('.00', '');
  72. }
  73. String msgPush = '866374061547503|1007-2|$orderId|2003|$amount|7571';
  74. mqtt.sendMsg(msgPush);
  75. }
  76. }
  77. }
  78. // 监听到消息后转到处理函数
  79. Future<void> initPlatformState() async {
  80. NotificationsListener.initialize(callbackHandle: _callback);
  81. // register you event handler in the ui logic.
  82. NotificationsListener.receivePort?.listen((evt) => onData(evt));
  83. }
  84. void startListening() async {
  85. print("start listening");
  86. var isR = await NotificationsListener.isRunning;
  87. if (!isR!) {
  88. await NotificationsListener.startService();
  89. }
  90. }
  91. Future<void> checkPermission() async {
  92. var hasPermission = await NotificationsListener.hasPermission;
  93. if (!hasPermission!) {
  94. print("no permission, so open settings");
  95. NotificationsListener.openPermissionSettings();
  96. return;
  97. }
  98. }
  99. }
  100. class Mqtt {
  101. late MqttServerClient client;
  102. Mqtt() {
  103. connect();
  104. }
  105. Future<MqttServerClient> connect() async {
  106. var uuid = const Uuid();
  107. client = MqttServerClient.withPort('47.92.50.210', uuid.v4(), 9883);
  108. client.logging(on: true);
  109. String willMsg =
  110. "{\"type\":\"tts_dynamic\",\"msgid\":\"${Random().nextInt(999999)}\",\"txt\":\"lost connect!\"}";
  111. final connMessage = MqttConnectMessage()
  112. .authenticateAs('moki', 'Moki@886.')
  113. .withWillTopic('866374061547503')
  114. .withWillMessage(willMsg)
  115. .startClean() // 清理会话
  116. .withWillQos(MqttQos.atLeastOnce);
  117. client.connectionMessage = connMessage;
  118. client.autoReconnect = true;
  119. client.keepAlivePeriod = 120;
  120. try {
  121. await client.connect();
  122. } catch (e) {
  123. print('Exception: $e');
  124. client.disconnect();
  125. }
  126. return client;
  127. }
  128. Future<String> sendMsg(String msg) async {
  129. // 发布消息
  130. final builder = MqttClientPayloadBuilder();
  131. // builder.addString(msg);
  132. final bytes = gbk.encode(msg);
  133. for (var element in bytes) {
  134. builder.addByte(element);
  135. }
  136. // MqttServerClient client = await connect();
  137. client.publishMessage(
  138. '866374061547503', MqttQos.atLeastOnce, builder.payload!);
  139. return 'success';
  140. }
  141. // // 断开连接
  142. // await
  143. //
  144. // client.disconnect();
  145. }
  146. class MyHomePage extends StatefulWidget {
  147. const MyHomePage({Key? key, required this.title}) : super(key: key);
  148. final String title;
  149. @override
  150. State<StatefulWidget> createState() => _MyHomePageState();
  151. }
  152. class _MyHomePageState extends State<MyHomePage> {
  153. late Listener listener = Listener();
  154. // 弹框信息
  155. void _showDialog(BuildContext context, String msg, bool tag) {
  156. String title = tag ? '成功!' : '失败';
  157. showDialog(
  158. context: context,
  159. builder: (BuildContext context) {
  160. return Theme(
  161. data: Theme.of(context).copyWith(
  162. dialogTheme: DialogTheme(
  163. shape: RoundedRectangleBorder(
  164. borderRadius: BorderRadius.circular(5.0)))),
  165. child: AlertDialog(
  166. title: Text(title),
  167. content: Text(msg),
  168. actions: <Widget>[
  169. TextButton(
  170. child: const Center(child: Text('确定')),
  171. onPressed: () {
  172. Navigator.of(context).pop();
  173. },
  174. ),
  175. ],
  176. ));
  177. },
  178. );
  179. }
  180. @override
  181. Widget build(BuildContext context) {
  182. return Scaffold(
  183. appBar: AppBar(
  184. title: Text(widget.title),
  185. backgroundColor: Colors.cyan,
  186. ),
  187. body: Center(
  188. child: Column(
  189. mainAxisAlignment: MainAxisAlignment.center,
  190. children: <Widget>[
  191. const Text(
  192. '欢迎使用魔基盒收款宝',
  193. style: TextStyle(
  194. fontSize: 22, // 设置字体大小为20
  195. ),
  196. textAlign: TextAlign.center,
  197. ),
  198. const Text(
  199. '请依次点击如下按钮!',
  200. style: TextStyle(
  201. fontSize: 16, // 设置字体大小为20
  202. ),
  203. textAlign: TextAlign.center,
  204. ),
  205. ElevatedButton.icon(
  206. icon: const Icon(Icons.ad_units_outlined),
  207. label: const Text("申请权限"),
  208. style: ElevatedButton.styleFrom(
  209. foregroundColor: Colors.white,
  210. backgroundColor: Colors.cyan,
  211. shape: RoundedRectangleBorder(
  212. borderRadius: BorderRadius.circular(5), // 设置按钮的圆角半径为10
  213. ),
  214. ),
  215. onPressed: () async {
  216. listener.checkPermission();
  217. },
  218. ),
  219. ElevatedButton.icon(
  220. icon: const Icon(Icons.add_chart_rounded),
  221. onPressed: () async {
  222. listener.startListening();
  223. _showDialog(context, '服务已成功启动!', true);
  224. },
  225. label: const Text('开启监听'),
  226. style: ElevatedButton.styleFrom(
  227. foregroundColor: Colors.white,
  228. backgroundColor: Colors.greenAccent,
  229. shape: RoundedRectangleBorder(
  230. borderRadius: BorderRadius.circular(5), // 设置按钮的圆角半径为10
  231. ),
  232. ),
  233. ),
  234. ElevatedButton.icon(
  235. icon: const Icon(Icons.add_alert_outlined),
  236. onPressed: () async {
  237. listener.testSendMsg();
  238. },
  239. label: const Text('检测设备'),
  240. style: ElevatedButton.styleFrom(
  241. foregroundColor: Colors.white,
  242. backgroundColor: Colors.grey,
  243. shape: RoundedRectangleBorder(
  244. borderRadius: BorderRadius.circular(5), // 设置按钮的圆角半径为10
  245. ),
  246. ),
  247. )
  248. ],
  249. ),
  250. ),
  251. );
  252. }
  253. }