← 홈으로 돌아가기

통신 가이드

Flutter와 웹앱 간 양방향 통신 구현

🔄 통신 아키텍처

Vue/React/Angular 웹앱
        ↓ (JavaScript)
FlutterBridge.request()
        ↓
  JavaScript Channel
        ↓
    Flutter 앱
        ↓
   Native 기능
        ↓
     응답 반환
        ↓
  Promise resolve
        ↓
     웹앱 수신
                

📡 웹앱 → Flutter

기본 사용법

// JavaScript에서 Flutter로 메시지 전송
const bridge = new FlutterBridge();

// 위치 요청
const location = await bridge.getLocation();
console.log(location); // { lat: 37.123, lng: 127.456 }

내부 동작

// 1. 요청 ID 생성
const requestId = generateId();

// 2. Promise 생성 및 저장
const promise = new Promise((resolve, reject) => {
    pendingRequests[requestId] = { resolve, reject };
});

// 3. Flutter로 메시지 전송
window.FlutterBridge.postMessage(JSON.stringify({
    action: 'GET_LOCATION',
    payload: { requestId }
}));

// 4. Promise 반환 (응답 대기)
return promise;

📲 Flutter → 웹앱

응답 전송

// Flutter에서 웹앱으로 응답
await _controller.runJavaScript('''
  if (window.FlutterBridge && window.FlutterBridge.handleResponse) {
    window.FlutterBridge.handleResponse(
      '$requestId',
      'SUCCESS',
      ${jsonEncode(responseData)}
    );
  }
''');

이벤트 전송

// Flutter에서 웹앱으로 이벤트 전송 (요청 없이)
await _controller.runJavaScript('''
  window.dispatchEvent(new CustomEvent('flutter-event', {
    detail: { type: 'location-updated', data: $locationJson }
  }));
''');

⚙️ 요청-응답 시스템

1. 요청 생성 (웹앱)

async request(action, payload = {}) {
    const requestId = this.generateId();
    
    return new Promise((resolve, reject) => {
        // 타임아웃 설정
        const timeout = setTimeout(() => {
            delete this.pendingRequests[requestId];
            reject(new Error('Request timeout'));
        }, this.timeout);
        
        // 요청 저장
        this.pendingRequests[requestId] = {
            resolve,
            reject,
            timeout
        };
        
        // Flutter로 전송
        this.sendToFlutter(action, { ...payload, requestId });
    });
}

2. 요청 처리 (Flutter)

Future _handleBridgeMessage(String rawJson) async {
  final data = jsonDecode(rawJson);
  final action = data['action'];
  final payload = data['payload'] ?? {};
  final requestId = payload['requestId'] ?? '';
  
  switch (action) {
    case 'GET_LOCATION':
      await _getLocation(requestId);
      break;
    // 기타 액션들...
  }
}

3. 응답 전송 (Flutter)

Future _sendResponse(
  String requestId,
  String status,
  Map data
) async {
  await _controller.runJavaScript('''
    if (window.FlutterBridge) {
      window.FlutterBridge.handleResponse(
        '$requestId',
        '$status',
        ${jsonEncode(data)}
      );
    }
  ''');
}

4. 응답 수신 (웹앱)

handleResponse(requestId, status, data) {
    const request = this.pendingRequests[requestId];
    
    if (!request) return;
    
    clearTimeout(request.timeout);
    delete this.pendingRequests[requestId];
    
    if (status === 'SUCCESS') {
        request.resolve(data);
    } else {
        request.reject(new Error(data.message));
    }
}

🔐 에러 처리

타임아웃

try {
    const location = await bridge.getLocation();
} catch (error) {
    if (error.message === 'Request timeout') {
        console.log('요청 시간 초과');
    }
}

권한 거부

try {
    const location = await bridge.getLocation();
} catch (error) {
    if (error.message.includes('permission')) {
        console.log('위치 권한이 필요합니다');
    }
}

🎯 실전 예제

Vue 3 Composition API

<script setup>
import { ref } from 'vue';
import FlutterBridge from './bridge';

const bridge = new FlutterBridge();
const location = ref(null);
const error = ref(null);

async function getLocation() {
  try {
    location.value = await bridge.getLocation();
  } catch (err) {
    error.value = err.message;
  }
}
</script>

React Hooks

import { useState } from 'react';
import FlutterBridge from './bridge';

const bridge = new FlutterBridge();

function App() {
  const [location, setLocation] = useState(null);
  
  const getLocation = async () => {
    try {
      const loc = await bridge.getLocation();
      setLocation(loc);
    } catch (error) {
      console.error(error);
    }
  };
  
  return <button onClick={getLocation}>위치</button>;
}

📊 메시지 형식

요청 메시지

{
  "action": "GET_LOCATION",
  "payload": {
    "requestId": "req_1234567890",
    // 기타 파라미터
  }
}

응답 메시지

{
  "requestId": "req_1234567890",
  "status": "SUCCESS",
  "data": {
    "lat": 37.123,
    "lng": 127.456,
    "accuracy": 10
  }
}

💡 베스트 프랙티스

API 문서에서 모든 기능 확인하기 →