패키지, 저장소 및 앱 카테고리 검색

패키지 상세v1.3.0

websocket_universal

모든 플랫폼(IO 및 웹/HTML 포함)에 적합한 편리한 웹소켓 핸들러입니다. 웹소켓 메시지 라우팅, 상태 및 기타 기능은 사용하기 쉬운 인터페이스를 제공합니다.

AndroidiOSWebmacOSWindowsLinux
30일 다운로드
994
좋아요
36
Pub 점수
130

패키지 설치

flutter pub add websocket_universal

패키지 개요

공개 정보를 바탕으로 생성한 선택 가이드입니다.

안드로이드, iOS, 웹, macOS, 윈도우, 리눅스에서 원활하게 작동하도록 설계된 플러터용 크로스플랫폼 웹소켓 핸들러입니다. 웹소켓 연결 관리, 메시지 라우팅, 연결 상태 모니터링을 위한 간단하고 통합된 인터페이스를 제공합니다. 다양한 기기 및 플랫폼에서 일관된 동작이 필요한 실시간 통신 앱에 적합합니다. 이 패키지는 플랫폼별 복잡성을 추상화하여 웹소켓 이벤트의 설정, 유지, 응답을 쉽게 할 수 있는 API를 제공합니다.

사용 사례

  • 실시간 채팅 애플리케이션
  • 실시간 데이터 스트리밍
  • 사물인터넷 장치 통신
  • 멀티플레이어 게임 동기화
  • 서버 전송 이벤트 처리

주요 기능

  • 크로스 플랫폼 호환성
  • 메시지 라우팅 시스템
  • 연결 상태 모니터링
  • 설정 및 관리를 위한 간단한 API
  • IO 및 웹 플랫폼 모두 지원

적합한 대상

  • 실시간 기능을 구축하는 개발자
  • 다중 플랫폼 대상 프로젝트
  • 신뢰할 수 있는 WebSocket 통합이 필요한 앱
  • 다양한 플랫폼 간 코드 재사용을 우선시하는 팀
  • 자주 서버 업데이트가 이루어지는 애플리케이션

고려 사항

  • 불안정한 네트워크 조건에서 오류 처리에 주의가 필요합니다
  • 재연결 전략을 위한 추가 로직이 필요할 수 있습니다
  • 고주파 메시지 폭발에 최적화되지 않음
  • 기본 사용법을 넘어서는 문서가 제한적
  • 업데이트를 위해 외부 저장소에 의존합니다

원본 README

연결된 소스 저장소의 README 원문 스냅샷입니다. 최신 내용은 저장소에서 확인하세요.

websocket_universal

CHECKOUT

Dart and Flutter webSocket client package for all the platforms (web, mobile, desktop)

Easy-to-use interface:

  1. Easy-to-use websocket methods and usage examples included!
  2. Universal socket status changes stream.
  3. Ping delay measurement and easy setup for ping/pong interaction with server!
  4. Auto-reconnection feature for IWebSocketHandler ws handler.

Contact & support me:

  1. Telegram
  2. LinkedIn
  3. Support me on patreon

Fast start:

// ignore_for_file: avoid_print
import 'package:websocket_universal/websocket_universal.dart';

/// Example works with Postman Echo server
void main() async {
  /// 1. Create webSocket handler:
  final textSocketHandler = IWebSocketHandler<String, String>.createClient(
    'wss://ws.postman-echo.com/raw', // Postman echo ws server
    SocketSimpleTextProcessor(),
  );

  /// 2. Listen to webSocket messages:
  textSocketHandler.incomingMessagesStream.listen((inMsg) {
    print('> webSocket  got text message from server: "$inMsg" '
        '[ping: ${textSocketHandler.pingDelayMs}]');
  });
  textSocketHandler.outgoingMessagesStream.listen((inMsg) {
    print('> webSocket sent text message to   server: "$inMsg" '
        '[ping: ${textSocketHandler.pingDelayMs}]');
  });

  /// 3. Connect & send message:
  await textSocketHandler.connect();
  textSocketHandler.sendMessage('Hello server!');
  await Future<void>.delayed(const Duration(seconds: 4));

  // 4. Disconnect & close connection:
  await textSocketHandler.disconnect('manual disconnect');
  textSocketHandler.close();
}

#1 Simple example with String messages (from and to server):

You don't need your own ws server to run this code.
Example postman echo server is used in this example.

  1. Send message to server using sendMessage(Y messageToServer) and listen messages coming from server using incomingMessagesStream
  2. Listen to websocket states socketStateStream or all events that are happening logEventStream. Define how you process your messages to and from server and ping/pong interaction using IMessageProcessor<Tin,Yout> generic interface or use convinient SocketMessageProcessor implementation (see example #2).
import 'package:websocket_universal/websocket_universal.dart';

/// Example works with Postman Echo server
void main() async {
  /// Postman echo ws server (you can use your own server URI)
  /// 'wss://ws.postman-echo.com/raw'
  /// For local server it could look like 'ws://127.0.0.1:42627/websocket'
  const websocketConnectionUri = 'wss://ws.postman-echo.com/raw';
  const textMessageToServer = 'Hello server!';
  const connectionOptions = SocketConnectionOptions(
    pingIntervalMs: 3000, // send Ping message every 3000 ms
    timeoutConnectionMs: 4000, // connection fail timeout after 4000 ms
    /// see ping/pong messages in [logEventStream] stream
    skipPingMessages: false,

    /// Set this attribute to `true` if do not need any ping/pong
    /// messages and ping measurement. Default is `false`
    pingRestrictionForce: false,
  );

  /// Example with simple text messages exchanges with server
  /// (not recommended for applications)
  /// [<String, String>] generic types mean that we receive [String] messages
  /// after deserialization and send [String] messages to server.
  final IMessageProcessor<String, String> textSocketProcessor =
      SocketSimpleTextProcessor();
  final textSocketHandler = IWebSocketHandler<String, String>.createClient(
    websocketConnectionUri, // Postman echo ws server
    textSocketProcessor,
    connectionOptions: connectionOptions,
  );

  // Listening to webSocket status changes
  textSocketHandler.socketHandlerStateStream.listen((stateEvent) {
    // ignore: avoid_print
    print('> status changed to ${stateEvent.status}');
  });

  // Listening to server responses:
  textSocketHandler.incomingMessagesStream.listen((inMsg) {
    // ignore: avoid_print
    print('> webSocket  got text message from server: "$inMsg" '
        '[ping: ${textSocketHandler.pingDelayMs}]');
  });

  // Listening to debug events inside webSocket
  textSocketHandler.logEventStream.listen((debugEvent) {
    // ignore: avoid_print
    print('> debug event: ${debugEvent.socketLogEventType}'
        ' [ping=${debugEvent.pingMs} ms]. Debug message=${debugEvent.message}');
  });

  // Listening to outgoing messages:
  textSocketHandler.outgoingMessagesStream.listen((inMsg) {
    // ignore: avoid_print
    print('> webSocket sent text message to   server: "$inMsg" '
        '[ping: ${textSocketHandler.pingDelayMs}]');
  });

  // Connecting to server:
  final isTextSocketConnected = await textSocketHandler.connect();
  if (!isTextSocketConnected) {
    // ignore: avoid_print
    print('Connection to [$websocketConnectionUri] failed for some reason!');
    return;
  }

  textSocketHandler.sendMessage(textMessageToServer);

  await Future<void>.delayed(const Duration(seconds: 30));
  // Disconnecting from server:
  await textSocketHandler.disconnect('manual disconnect');
  // Disposing webSocket:
  textSocketHandler.close();
}

#2 Recommended way to exchange messages with server (typed Messages):

You don't need your own ws server to run this code.
Example postman echo server is used in this example.

import 'package:websocket_universal/websocket_universal.dart';

void main() async {
  /// Postman echo ws server (you can use your own server URI)
  /// For local server it could look like 'ws://127.0.0.1:42627/websocket'
  const websocketConnectionUri = 'wss://ws.postman-echo.com/raw';
  const textMessageToServer = 'Hello server!';
  const connectionOptions = SocketConnectionOptions(
    pingIntervalMs: 3000, // send Ping message every 3000 ms
    timeoutConnectionMs: 4000, // connection fail timeout after 4000 ms
    /// see ping/pong messages in [logEventStream] stream
    skipPingMessages: false,
  );

  /// Complex example:
  /// Example using [ISocketMessage] and [IMessageToServer]
  /// (recommended for applications, server must deserialize
  /// [ISocketMessage] serialized string to [ISocketMessage] object)
  final IMessageProcessor<ISocketMessage<Object?>, IMessageToServer>
      messageProcessor = SocketMessageProcessor();
  final socketHandler =
      IWebSocketHandler<ISocketMessage<Object?>, IMessageToServer>.createClient(
    websocketConnectionUri,
    messageProcessor,
    connectionOptions: connectionOptions,
  );

  // Listening to debug events inside webSocket
  socketHandler.logEventStream.listen((debugEvent) {
    // ignore: avoid_print
    print('> debug event: ${debugEvent.socketLogEventType}'
        ' ping=${debugEvent.pingMs} ms. Debug message=${debugEvent.message}');
  });

  // Listening to webSocket status changes
  socketHandler.socketStateStream.listen((stateEvent) {
    // ignore: avoid_print
    print('> status changed to ${stateEvent.status}');
  });

  // [IMessageToServer] also implements [ISocketMessage] interface.
  // So basically we are sending and receiving equally-typed messages.
  const messageTypeStr = '[ISocketMessage]';
  // Listening to server responses:
  socketHandler.incomingMessagesStream.listen((inMsg) {
    // ignore: avoid_print
    print('> webSocket  got $messageTypeStr: $inMsg');
  });

  // Listening to outgoing messages:
  socketHandler.outgoingMessagesStream.listen((inMsg) {
    // ignore: avoid_print
    print('> webSocket sent $messageTypeStr: $inMsg');
  });

  // Connecting to server:
  final isConnected = await socketHandler.connect();

  if (!isConnected) {
    // ignore: avoid_print
    print('Connection to [$websocketConnectionUri] failed for some reason!');
    return;
  }

  // Sending message with routing path 'test' and simple JSON payload:
  final outMsg = MessageToServerImpl.onlyHost(
    host: 'test',
    data: '{"payload": "$textMessageToServer"}',
    error: null,
  );
  socketHandler.sendMessage(outMsg);

  await Future<void>.delayed(const Duration(seconds: 8));
  // Disconnecting from server:
  await socketHandler.disconnect('manual disconnect');
  // Disposing webSocket:
  socketHandler.close();
}

#3 Handling byte messages (from and to server) on client side:

import 'dart:convert';

import 'package:websocket_universal/websocket_universal.dart';

/// Bytes array example:
void main() async {
  /// For getting/answering byte-array messages (`List<int> in dart`)
  /// you will need your own server and handle messages as byte-arrays
  /// on the backend side too. On client side it will look like this:
  const websocketLocalExample = 'ws://127.0.0.1:42627/websocket';
  const textMessageToServer = 'Hello server!';
  const connectionOptions = SocketConnectionOptions(
    pingIntervalMs: 3000, // send Ping message every 3000 ms
    timeoutConnectionMs: 4000, // connection fail timeout after 4000 ms
    /// see ping/pong messages in [logEventStream] stream
    skipPingMessages: false,
  );

  final IMessageProcessor<List<int>, List<int>> bytesSocketProcessor =
      SocketSimpleBytesProcessor();
  final bytesSocketHandler =
      IWebSocketHandler<List<int>, List<int>>.createClient(
    websocketLocalExample, // Local ws server
    bytesSocketProcessor,
    connectionOptions: connectionOptions,
  );

  // Listening to debug events inside webSocket
  bytesSocketHandler.logEventStream.listen((debugEvent) {
    // ignore: avoid_print
    print('> debug event: ${debugEvent.socketLogEventType}'
        ' ping=${debugEvent.pingMs} ms. Debug message=${debugEvent.message}');
  });

  // Listening to server responses:
  bytesSocketHandler.incomingMessagesStream.listen((inMsg) {
    // ignore: avoid_print
    print('> webSocket  got bytes message from server: "$inMsg"');
  });

  // Listening to outgoing messages:
  bytesSocketHandler.outgoingMessagesStream.listen((inMsg) {
    // ignore: avoid_print
    print('> webSocket sent bytes message to   server: "$inMsg"');
  });

  // Connecting to server:
  final isBytesSocketConnected = await bytesSocketHandler.connect();
  if (!isBytesSocketConnected) {
    // ignore: avoid_print
    print('Connection to [$websocketLocalExample] for bytesSocketHandler '
        'failed for some reason!');
    return;
  }
  final bytesMessage = utf8.encode(textMessageToServer);
  //textMessageToServer
  bytesSocketHandler.sendMessage(bytesMessage);

  await Future<void>.delayed(const Duration(seconds: 7));
  // Disconnecting from server:
  await bytesSocketHandler.disconnect('manual disconnect');
  // Disposing webSocket:
  bytesSocketHandler.close();
}

#4 Advanced ISocketMessage handling. Composite server response example:

import 'dart:convert';

import 'package:websocket_universal/websocket_universal.dart';

void main() async {
  /// Postman echo ws server (you can use your own server URI)
  /// For local server it could look like 'ws://127.0.0.1:42627/websocket'
  const websocketConnectionUri = 'wss://ws.postman-echo.com/raw';
  const connectionOptions = SocketConnectionOptions(
    pingIntervalMs: 3000, // send Ping message every 3000 ms
    timeoutConnectionMs: 4000, // connection fail timeout after 4000 ms
    /// see ping/pong messages in [logEventStream] stream
    skipPingMessages: false,
  );

  /// Complex example:
  /// Example using [ISocketMessage] and [IMessageToServer]
  /// (recommended for applications, server must deserialize
  /// [ISocketMessage] serialized string to [ISocketMessage] object)
  final IMessageProcessor<ISocketMessage<Object?>, IMessageToServer>
      messageProcessor = SocketMessageProcessor();
  final socketHandler =
      IWebSocketHandler<ISocketMessage<Object?>, IMessageToServer>.createClient(
    websocketConnectionUri,
    messageProcessor,
    connectionOptions: connectionOptions,
  );

  /// Creating websocket_manager:
  /// `ISocketManagerMiddleware` processes requests before sending and
  /// after receiving ISocketMessage. See test implementation for details.
  final ISocketManagerMiddleware middleware = SocketManagerMiddleware();
  final IWebSocketRequestManager requestManager = WebSocketRequestManager(
    middleware: middleware,
    webSocketHandler: socketHandler,
  );
  final IWebSocketDataBridge dataBridge = WebSocketDataBridge(requestManager);

  ///
  // Connecting to server:
  final isConnected = await socketHandler.connect();

  if (!isConnected) {
    // ignore: avoid_print
    print('Connection to [$websocketConnectionUri] failed for some reason!');
    return;
  }

  // Sending message with routing path 'test' and simple JSON payload:
  final requestGame = MessageToServerImpl.duo(
    host: TestDecoder.host,
    topic1: CustomGameModel.topic1,
    data: jsonEncode(
      const CustomGameModel(
        name: 'MakeWorld strategy',
        playersAmount: 8,
      ),
    ),
    error: null,
  );
  final socketRequest = SocketRequest(requestMessage: requestGame);

  final result =
      await dataBridge.singleRequestFull<CustomGameModel>(socketRequest);
  // ignore: avoid_print
  print('Got result: ${result.data}');

  final outMsgList = MessageToServerImpl.duo(
    host: TestDecoder.host,
    topic1: CustomGameModel.topic1List,
    data: jsonEncode([
      const CustomGameModel(
        name: 'MakeWorld strategy',
        playersAmount: 8,
      ),
      const CustomGameModel(
        name: 'New patch',
        playersAmount: 4,
      ),
    ]),
    error: null,
  );
  final socketRequestList = SocketRequest(requestMessage: outMsgList);

  final listResult = await dataBridge
      .singleRequestFull<List<CustomGameModel>>(socketRequestList);
  // ignore: avoid_print
  print('Got list result: ${listResult.data}');

  // Creating composite request with 2 response topics required
  final topicSingle = SocketTopicImpl.duo(
    host: TestDecoder.host,
    topic1: CustomGameModel.topic1,
  );
  final topicList = SocketTopicImpl.duo(
    host: TestDecoder.host,
    topic1: CustomGameModel.topic1List,
  );
  // Assemple composite request, that, in fact, requests CustomGameModel
  // using [requestGame] to request single game and awaits to receive 2 topics
  // from server: [topicSingle] and [topicList]
  final compositeRequest = SocketRequest(
    requestMessage: requestGame,
    responseTopics: {topicSingle, topicList},
  );
  // Running task:
  final compositeTask = dataBridge.compositeRequest(compositeRequest);
  // Emulating server 2nd response (real server should response with 2
  // messages without 2nd request)
  dataBridge.requestData(socketRequestList);
  final compositeResp = await compositeTask;

  // In result we can get multiple results from composite response:
  final responseOne = compositeResp.getData<CustomGameModel>();
  final responseTwo = compositeResp.getData<List<CustomGameModel>>();

  // ignore: avoid_print
  print('Got composite result. Answers = ${compositeResp.dataCached.length}'
      '[$responseOne] and [$responseTwo]');

  // Disconnecting from server:
  await socketHandler.disconnect('manual disconnect');
  // Disposing webSocket:
  requestManager.close();
  socketHandler.close();
}

Source repository

카테고리

의존성

의존성 목록 3 개

소스 저장소

이 패키지를 사용하는 프로젝트

아직 데이터가 없습니다.