You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Dart中通过SignalR订阅事件并触发音效?

Dart中SignalR事件订阅与音效播放的正确实现

问题背景

需要在Dart项目中通过SignalR订阅后端推送的事件,当事件触发时自动播放音效。已有JS参考实现,但当前Dart代码存在逻辑问题,无法正常工作。

示例推送数据

{
  "id": "1234",
  "date": "2022-08-29T12:05:27.770Z",
  "base": "BaseNameExample",
  "additionInfo": "there is no example",
  "dataId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}

参考JS实现

function Notifications(data) {
    // console.log(data)
    this.id = data.id;
    this.date = data.date;
    this.alarm.play();
}

现有Dart代码问题分析

  1. 事件参数处理错误:hubConnection.on('GetNotifications')中使用arguments == ['id']这类无效比较,未正确解析推送的对象数据
  2. Logger配置冗余:重复创建Logger监听,导致代码冗余且可能出现重复输出
  3. 方法调用不规范:Dart方法名应遵循小驼峰规范(如Alarm应改为alarm),且播放音效的异步操作未正确使用await
  4. 逻辑混淆:将主动获取数据的invoke('GetNotifications')与监听推送事件的on('GetNotifications')逻辑混在一起,订阅事件是持续监听行为,无需依赖单次invoke操作

修正后的完整代码

import 'package:signalr_core/signalr_core.dart';
import 'package:logger/logger.dart';
import 'package:audioplayers/audioplayers.dart';

class EventsSubscriber {
  final AudioPlayer _audioPlayer = AudioPlayer();
  final Logger _logger = Logger(level: Level.all);

  Future<List> initializeNotifications() async {
    // 统一配置Logger监听
    _logger.onRecord.listen((LogRecord rec) {
      print('${rec.level.name}: ${rec.time}: ${rec.message}');
    });

    final httpConnectionOptions = HttpConnectionOptions(
      accessTokenFactory: () => SharedPreferenceService().loginWithToken(),
      skipNegotiation: true,
      transport: HttpTransportType.webSockets,
    );

    final hubConnection = HubConnectionBuilder()
        .withUrl(
          'http://securelink/home',
          options: httpConnectionOptions,
        )
        .build();

    // 监听连接关闭事件
    hubConnection.onclose(({error}) {
      if (error != null) {
        _logger.e('连接关闭: ${error.message}');
        // 可选:添加自动重连逻辑
        // _reconnect(hubConnection);
      }
    });

    // 启动SignalR连接
    await hubConnection.start();
    _logger.i('SignalR连接成功');

    // 主动获取历史通知(按需保留)
    List notifications = [];
    if (hubConnection.state == HubConnectionState.connected) {
      final result = await hubConnection.invoke('GetNotifications');
      notifications = result as List;
      _logger.i('获取历史通知: $notifications');
      // 播放初始通知音效(按需保留)
      await _playSound('assets/notifSound.mp3');
    }

    // 订阅实时推送的GetNotifications事件
    hubConnection.on('GetNotifications', (arguments) {
      if (arguments != null && arguments.isNotEmpty) {
        // 解析推送的第一个参数(后端推送的通知对象)
        final notificationData = arguments[0] as Map<String, dynamic>;
        final id = notificationData['id'];
        final date = notificationData['date'];
        _logger.i('收到新通知: ID=$id, Date=$date');
        
        // 播放提醒音效
        _playSound('assets/wanted.mp3');
      } else {
        _stopSound();
      }
    });

    return notifications;
  }

  // 封装音效播放方法
  Future<void> _playSound(String assetPath) async {
    try {
      await _audioPlayer.play(AssetSource(assetPath));
    } catch (e) {
      _logger.e('播放音效失败: $e');
    }
  }

  // 封装音效停止方法
  Future<void> _stopSound() async {
    try {
      await _audioPlayer.stop();
    } catch (e) {
      _logger.e('停止音效失败: $e');
    }
  }

  // 可选:自动重连逻辑
  // Future<void> _reconnect(HubConnection hubConnection) async {
  //   await Future.delayed(const Duration(seconds: 5));
  //   try {
  //     await hubConnection.start();
  //     _logger.i('重连成功');
  //   } catch (e) {
  //     _logger.e('重连失败: $e');
  //     _reconnect(hubConnection);
  //   }
  // }
}

关键实现说明

  1. 事件参数解析:SignalR推送的事件参数以数组形式传递,第一个元素为实际数据对象,需通过arguments[0] as Map<String, dynamic>解析
  2. 音效播放优化:使用audioplayers官方推荐的AssetSource加载本地资源,封装异步播放方法并处理异常
  3. 连接稳定性:添加连接关闭监听,可选实现自动重连逻辑,避免因网络波动导致的监听中断
  4. 代码规范:遵循Dart小驼峰命名法,统一Logger配置,减少冗余代码

内容的提问来源于stack exchange,提问作者user16357470

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 13:17:00