Method Channel_IOS

Platform Channel 한 번에 이해하기 - IOS(swift) / Android(kotlin)

플랫폼 통신(IOS) - Event Channel
플랫폼 통신(Android) - Method Channel
플랫폼 통신(Android) - Event Channel

flutter로 프로젝트를 진행하다 보면 접근할 수 없는 고유 기능이나 뷰와 같은 사용을 위해 네이티브 코드를 작성해야 할 필요성이 생긴다.

최근에 플러터 웹뷰의 사용이 불안정하여 웹뷰가 사용되는 스크린에 한해서 네이티브 사용을 고려해보고 있어 플랫폼 채널에 대해 작성해보도록 하겠다.

우선 코드를 보면 플러터로 플랫폼 채널을 연결하는게 그리 어려워 보이지는 않지만 역시나 네이티브 코드를 모르면 채널 연결을 해도 의미가 없게된다 ㅠ

Flutter 공식 레퍼런스에 예제로 올라와있는 디바이스 배터리 정보를 체크하는 기능으로 연습을 하려고 한다.

flutter

MethodChannel안에 채널명을 넣어주기만 하면 된다.
채널명은 자유롭게 사용이 가능하며, 한 개의 채널로 여러 개의 기능을 리턴 받아도 된다고 한다.

  static final batteryChannel = MethodChannel('samples.flutter.dev/battery');
  String batteryLevel = 'wating...';

버튼을 눌러서 배터리 레벨을 가져오는 부분의 코드이다.

onTap : () async {
          int _batteryLevel =
              await batteryChannel.invokeMethod('getBatteryLevel');
          setState(() {
            batteryLevel = "${_batteryLevel}";
          });
        },

swift

XCode를 열어서 AppDelegate.swift 파일안에 작성하여도 되고
flutter_project > IOS > Runner > AppDelegate.swift 파일에 작성해도 무관하다.

swift 코드에서도 플러터의 플랫폼 채널명과 동일한 채널명으로 연결하여 준다.

  let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
    let batteryChannel = FlutterMethodChannel(name: "samples.flutter.dev/battery",
                                              binaryMessenger: controller.binaryMessenger)
    
  batteryChannel.setMethodCallHandler({
  [weak self] (call: FlutterMethodCall, result: FlutterResult) -> Void in
  // This method is invoked on the UI thread.
  guard call.method == "getBatteryLevel" else {
    result(FlutterMethodNotImplemented)
    return
  }
  self?.receiveBatteryLevel(result: result)
})

아래 리턴 함수 receiveBatteryLevel() 작성 부분이다.

배터리 상태를 알 수 없으면 에러를 발생시키는 로직이다.

 private func receiveBatteryLevel(result: FlutterResult) {
  let device = UIDevice.current
  device.isBatteryMonitoringEnabled = true
  if device.batteryState == UIDevice.BatteryState.unknown {
    
    result(FlutterError(code: "UNAVAILABLE",
                       message: "Battery level not available.",
                        details: nil))
  } else {
    result(Int(device.batteryLevel * 100))
  }

전체 코드

import UIKit
import Flutter

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {

    let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
    let batteryChannel = FlutterMethodChannel(name: "samples.flutter.dev/battery",
                                              binaryMessenger: controller.binaryMessenger)
    
  batteryChannel.setMethodCallHandler({
  [weak self] (call: FlutterMethodCall, result: FlutterResult) -> Void in
  // This method is invoked on the UI thread.
  guard call.method == "getBatteryLevel" else {
    result(FlutterMethodNotImplemented)
    return
  }
  self?.receiveBatteryLevel(result: result)
})
  

    GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
  private func receiveBatteryLevel(result: FlutterResult) {
  let device = UIDevice.current
  device.isBatteryMonitoringEnabled = true
  if device.batteryState == UIDevice.BatteryState.unknown {
    result(55)
    // result(FlutterError(code: "UNAVAILABLE",
    //                     message: "Battery level not available.",
    //                     details: nil))
  } else {
    result(Int(device.batteryLevel * 100))
  }
}
}

시뮬레이터로는 작동을 하지 않는다. 시뮬레이터에 배터리 레벨이 없어 실제 디바이스로 테스트 하면된다.

다음 글에서는 단순히 변수를 리턴 받는 것이 아닌 뷰를 리턴하여 네이티브로 뷰를 오픈하는 기능에 대해서 작성하겠다.

profile
Flutter Developer

2개의 댓글

comment-user-thumbnail
2023년 8월 9일

안녕하세요! 글 감사합니다!! 혹시 SwiftUI로 제작된 Native 뷰를 Flutter를 통해 렌더링 시킬 수 있나요?? 찾아보니 불가능 하다고 하는거 같은데 본문에서 "고유 기능이나 뷰와 같은 사용을 위해 네이티브 코드를 작성해야 할 필요성이 생긴다." 라고 작성하셔서 여쭤봅니다! 감사합니다.

1개의 답글