본문 바로가기

dev/flutter

플랫폼 통신 BasicMessageChannel (안드로이드, IOS)

MethodChannel과 다르게 네이티브에서 단순 스트링만 전달하고 싶다면 BasicMessageChannel을 사용하면 된다.

 

안드로이드

플러터에서 보내는 메세지를 받을 수 있다.  

(플러터에서 메세지를 받는 것과 보내는 것은 아래쪽에 있다.)

 

 

 

 

보낼 때는 아래와 같이 한다. 액티비티가 보여질때(onResume) 메세지를 보낸다.

 

 

 

package com.example.flutter_life_cycle

import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.BasicMessageChannel
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.StringCodec

class MainActivity: FlutterActivity() {

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        
        // MethodChannel
        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "example.channel/test").setMethodCallHandler {
                call, result ->
            if (call.method == "test") {
                result.success("안드로이드 MethodChannel OK")
            }
        }

        // basicMessageChannel
        val basicMessageChannel = BasicMessageChannel<String>(
            flutterEngine.dartExecutor,
            "example.channel/test",
            StringCodec.INSTANCE
        )
        basicMessageChannel.setMessageHandler { message, reply ->
            reply.reply("안드로이드 basicMessageChannel 응답 $message")
        }
    }
    

    override fun onResume() {
        super.onResume()

        val basicMessageChannel = BasicMessageChannel<String>(
            flutterEngine!!.dartExecutor.binaryMessenger,
            "example.channel/test",
            StringCodec.INSTANCE
        )

        basicMessageChannel.send("onResume")
    }
}

 

 

IOS

AppDelegate.swift 에 통신할 채널을 생성한다.

 

 

 

메세지를 전달할 부분에 사용하면 된다. 앱을 resume 시킬 때 메세지를 던지도록 하였다.

 

 

 

import UIKit
import Flutter

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {

  var basicMessageChannel: FlutterBasicMessageChannel! // BasicMessageChannel 선언

  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    GeneratedPluginRegistrant.register(with: self)

    // FlutterViewController
    let controller : FlutterViewController = window?.rootViewController as! FlutterViewController

    // BasicMessageChannel 세팅
    basicMessageChannel = FlutterBasicMessageChannel(
      name: "example.channel/test",
      binaryMessenger: controller.binaryMessenger,
      codec: FlutterStringCodec.sharedInstance()
    )

    // MethodChannel 세팅
    let methodChannel = FlutterMethodChannel(name: "example.channel/test", binaryMessenger: controller.binaryMessenger)

    methodChannel.setMethodCallHandler { [weak self] (call, result) in
      if call.method == "test" {
        // 통신
        result("OK")
      } else {
        result(FlutterMethodNotImplemented)
      }
    }

    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }

  // 앱 종료
  override func applicationWillTerminate(_ application: UIApplication) {
    basicMessageChannel.sendMessage("applicationWillTerminate")
  }

  // 포그라운드
  override func applicationWillEnterForeground(_ application: UIApplication) {
    basicMessageChannel.sendMessage("applicationWillEnterForeground");
  }

  // 백그라운드
  override func applicationDidEnterBackground(_ application: UIApplication) {
    basicMessageChannel.sendMessage("applicationDidEnterBackground")
  }
}

 

 

플러터

BasicMessageChannel을 선언해주고 setMessageHandler함수를 통해 이벤트 처리를 한다.

 

 

메세지를 받을 수도 있고 보낼 수도 있다.

 

메세지를 받을 때 / 보낼 때

 

import 'dart:developer';

import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> with WidgetsBindingObserver {
  final Dio dio = Dio();

  final BasicMessageChannel<String> basicMessageChannel = const BasicMessageChannel<String>("example.channel/test", StringCodec()); // BasicMessageChannel
  final MethodChannel methodChannel = const MethodChannel("example.channel/test"); // MethodChannel

  @override
  void initState() {

    // basicMessageChannel 수신
    basicMessageChannel.setMessageHandler((message) async {
      log("message: $message");

      switch (message) {
        // do something..
      }
      return message!;
    });

    // 앱 상태 감지 등록
    // WidgetsBinding.instance.addObserver(this);
    super.initState();
  }

  @override
  void dispose() {
    //앱 상태 감지 해제
    // WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }
  
  // 앱 상태에 따른 분기처리
  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {

    log("state: $state");

    switch (state) {
      case AppLifecycleState.resumed: // 포그라운드 상태
        log("AppLifecycleState resumed");
        break;
      case AppLifecycleState.inactive: // 비활성화 상태 -> 이후 paused 발생
        log("AppLifecycleState inactive");
        break;
      case AppLifecycleState.paused: // 백그라운드 상태
        log("AppLifecycleState paused");
        break;
      case AppLifecycleState.detached: // 종료
        log("AppLifecycleState detached");
        break;
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            ElevatedButton(
              onPressed: () {
                // methodChannel 통신
                methodChannel.invokeMethod("test").then((value) {
                  String result = value.toString();
                  log("result: $result");
                });
      
              },
               child: Text("methodChannel")
            ),
            ElevatedButton(
              onPressed: () async {
                // basicMessageChannel 통신
                await basicMessageChannel.send('Hello from Dart').then((value) {
                  log("value: $value");
                });
      
              },
               child: Text("basicMessageChannel")
            ),
            
          ],
        ),
      ),
    );
  }
}