본문으로 건너뛰기
cccskills
무료GitHub에 공개

websocket-integration

WebSocket and Socket.io integration for real-time communication in Flutter

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

설치 방법 보기

포함된 파일(1)

  • SKILL.md8.1 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

Skill 16: WebSocket Integration

Overview

This skill enables real-time bidirectional communication between Flutter apps and servers using WebSocket or Socket.io protocols. Perfect for chat applications, live updates, notifications, and collaborative features.

Features

  • WebSocket client with auto-reconnection
  • Socket.io integration with fallback
  • Connection state management
  • Message queuing when offline
  • Heartbeat/ping-pong handling
  • Multiple concurrent connections

Installation

Dependencies

dependencies:
  web_socket_channel: ^2.4.0
  socket_io_client: ^2.0.3
  connectivity_plus: ^5.0.2

Basic Usage

1. WebSocket Service

import 'package:web_socket_channel/web_socket_channel.dart';
import 'package:web_socket_channel/io.dart';

class WebSocketService {
  WebSocketChannel? _channel;
  final String url;
  final Function(dynamic)? onMessage;
  final Function()? onConnect;
  final Function(dynamic)? onError;
  final Function(int?)? onClose;

  WebSocketService({
    required this.url,
    this.onMessage,
    this.onConnect,
    this.onError,
    this.onClose,
  });

  void connect() {
    try {
      _channel = IOWebSocketChannel.connect(url);

      _channel!.stream.listen(
        (message) {
          onMessage?.call(message);
        },
        onDone: () {
          onClose?.call(_channel?.closeCode);
        },
        onError: (error) {
          onError?.call(error);
        },
      );

      onConnect?.call();
    } catch (e) {
      onError?.call(e);
    }
  }

  void send(dynamic message) {
    _channel?.sink.add(message);
  }

  void disconnect() {
    _channel?.sink.close();
    _channel = null;
  }
}

2. WebSocket Provider with Riverpod

import 'package:flutter_riverpod/flutter_riverpod.dart';

class WebSocketState {
  final bool isConnected;
  final List<String> messages;
  final String? error;

  WebSocketState({
    this.isConnected = false,
    this.messages = const [],
    this.error,
  });

  WebSocketState copyWith({
    bool? isConnected,
    List<String>? messages,
    String? error,
  }) {
    return WebSocketState(
      isConnected: isConnected ?? this.isConnected,
      messages: messages ?? this.messages,
      error: error,
    );
  }
}

class WebSocketNotifier extends StateNotifier<WebSocketState> {
  late final WebSocketService _service;

  WebSocketNotifier() : super(WebSocketState()) {
    _service = WebSocketService(
      url: 'wss://your-server.com/ws',
      onMessage: _handleMessage,
      onConnect: () => state = state.copyWith(isConnected: true),
      onClose: (_) => state = state.copyWith(isConnected: false),
      onError: (error) => state = state.copyWith(error: error.toString()),
    );
  }

  void connect() => _service.connect();
  void disconnect() => _service.disconnect();
  void send(String message) => _service.send(message);

  void _handleMessage(dynamic message) {
    final messages = [...state.messages, message.toString()];
    state = state.copyWith(messages: messages);
  }
}

final webSocketProvider = StateNotifierProvider<WebSocketNotifier, WebSocketState>(
  (ref) => WebSocketNotifier(),
);

3. Socket.io Implementation

import 'package:socket_io_client/socket_io_client.dart' as io;

class SocketIOService {
  io.Socket? _socket;
  final String url;

  SocketIOService({required this.url});

  void connect() {
    _socket = io.io(url, <String, dynamic>{
      'transports': ['websocket'],
      'autoConnect': true,
    });

    _socket!.onConnect((_) {
      print('Connected to Socket.io');
    });

    _socket!.onDisconnect((_) {
      print('Disconnected from Socket.io');
    });

    _socket!.on('message', (data) {
      print('Received: $data');
    });
  }

  void emit(String event, dynamic data) {
    _socket?.emit(event, data);
  }

  void on(String event, Function(dynamic) handler) {
    _socket?.on(event, handler);
  }

  void disconnect() {
    _socket?.disconnect();
  }
}

Advanced Features

Auto-Reconnection with Exponential Backoff

class ReconnectingWebSocket {
  final String url;
  final Duration initialDelay;
  final Duration maxDelay;
  final int maxAttempts;

  int _attempts = 0;
  Timer? _reconnectTimer;

  void _scheduleReconnect() {
    if (_attempts >= maxAttempts) return;

    final delay = Duration(
      milliseconds: min(
        initialDelay.inMilliseconds * pow(2, _attempts),
        maxDelay.inMilliseconds,
      ),
    );

    _reconnectTimer = Timer(delay, () {
      _attempts++;
      connect();
    });
  }
}

Message Queue for Offline Support

class WebSocketMessageQueue {
  final List<String> _queue = [];

  void enqueue(String message) {
    _queue.add(message);
  }

  void flush(WebSocketService service) {
    while (_queue.isNotEmpty) {
      final message = _queue.removeAt(0);
      service.send(message);
    }
  }
}

Usage Example: Chat Application

class ChatPage extends ConsumerWidget {
  const ChatPage({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final wsState = ref.watch(webSocketProvider);
    final wsNotifier = ref.read(webSocketProvider.notifier);
    final messageController = TextEditingController();

    return Scaffold(
      appBar: AppBar(
        title: Text('Chat ${wsState.isConnected ? "(Online)" : "(Offline)"}'),
      ),
      body: Column(
        children: [
          Expanded(
            child: ListView.builder(
              itemCount: wsState.messages.length,
              itemBuilder: (context, index) {
                return ListTile(
                  title: Text(wsState.messages[index]),
                );
              },
            ),
          ),
          Padding(
            padding: const EdgeInsets.all(8.0),
            child: Row(
              children: [
                Expanded(
                  child: TextField(
                    controller: messageController,
                    decoration: const InputDecoration(
                      hintText: 'Type a message...',
                    ),
                  ),
                ),
                IconButton(
                  icon: const Icon(Icons.send),
                  onPressed: () {
                    if (messageController.text.isNotEmpty) {
                      wsNotifier.send(messageController.text);
                      messageController.clear();
                    }
                  },
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

Testing

import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';

class MockWebSocketChannel extends Mock implements WebSocketChannel {}

void main() {
  test('WebSocket connection test', () async {
    final service = WebSocketService(url: 'ws://test.com');

    bool connected = false;
    service.onConnect = () => connected = true;

    service.connect();

    expect(connected, true);
  });
}

Best Practices

  1. Always handle disconnection gracefully - Implement reconnection logic
  2. Use message queuing - Queue messages when offline
  3. Implement heartbeat - Keep connection alive with ping/pong
  4. Secure connections - Use WSS (WebSocket Secure) in production
  5. Limit concurrent connections - Don't open too many WebSocket connections
  6. Clean up on dispose - Always close connections when not needed

Security Considerations

  • Use WSS (WebSocket Secure) instead of WS
  • Implement authentication tokens in connection headers
  • Validate all incoming messages
  • Rate limiting on server side
  • Sanitize user inputs

Troubleshooting

Connection drops frequently

  • Check network stability
  • Implement heartbeat/ping-pong
  • Increase timeout values

Messages not received

  • Verify server is broadcasting correctly
  • Check event names match exactly
  • Ensure listener is registered before connection

High battery usage

  • Reduce reconnection frequency
  • Close connection when app is backgrounded
  • Use push notifications instead of persistent connection

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

Machine Learning integration for Flutter using TensorFlow Lite and Firebase ML

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

HabitaNexus/monorepo32026년 10월 15일 업데이트

Google Maps and Mapbox integration for Flutter applications

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

HabitaNexus/monorepo32026년 10월 15일 업데이트

Implement tasks from an OpenSpec change. Use when the user wants to start implementing, continue implementation, or work through tasks.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

HabitaNexus/monorepo32026년 10월 15일 업데이트

Archive a completed change in the experimental workflow. Use when the user wants to finalize and archive a change after implementation is complete.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

HabitaNexus/monorepo32026년 10월 15일 업데이트

Enter explore mode - a thinking partner for exploring ideas, investigating problems, and clarifying requirements. Use when the user wants to think through something before or during a change.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

HabitaNexus/monorepo32026년 10월 15일 업데이트

Propose a new change with all artifacts generated in one step. Use when the user wants to quickly describe what they want to build and get a complete proposal with design, specs, and tasks ready for implementation.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

HabitaNexus/monorepo32026년 10월 15일 업데이트

HabitaNexus의 스킬 모두 보기

이 스킬의 문제 신고