플러터 플랫폼통합, 패키지

LeeWonjin·2024년 4월 27일
0

플러터

목록 보기
11/15

플랫폼 통합
(Platform integration)

  • Platform-specific 코드와 플랫폼 적응에 대해 다룬다.

https://docs.flutter.dev/platform-integration/platform-channels?tab=type-mappings-kotlin

플랫폼 채널

개념

플랫폼 채널의 통신참여 주체를 두 개로 나눌 수 있다

  • 클라이언트(UI, 플러터 앱)
  • 호스트(플랫폼)

플러터 앱은 네이티브 호스트와 비동기 메시지를 주고받는다.
그리고 그런 메시지 교환을 지원하기 위한 클래스도 이미 플러터에 구현되어있다.

  • 플러터가 네이티브 호스트에게 메시지 보내기 : MethodChannel
  • 네이티브가 플러터의 메시지 받고 응답하기
    • 안드로이드-->플러터 : MethodChannel, MethodChannelAndroid
    • IOS-->플러터 : FlutterMethodChannel, MethodChanneliOS

플러터 공식문서의 배터리 잔량 확인 예제

플러터 클라이언트 코드 작성

  1. State위젯에서 메소드 채널 인스턴스를 만든다.
    채널 이름은 앱 내에서 고유하면 되는데, 도메인/진짜이름으로 정할 수 있음

  2. 만들어진 메소드 채널에 대해 호출하고자 하는 메소드를 지정

  3. (원한다면) UI에 보여주기

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

...

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

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

class _MyHomePageState extends State<MyHomePage> {
  // 1.
  static const platform = MethodChannel('samples.flutter.dev/battery');
  int _batteryLevel = -1;

  Future<void> _getBatteryLevel() async {
    int batteryLevel;
    try {
      // 2.
      final result = await platform.invokeMethod<int>('getBatteryLevel');
      batteryLevel = result ?? -1;
    } on PlatformException catch (e) {
      batteryLevel = -1;
    }

    setState(() {
      _batteryLevel = batteryLevel;
    });
  }

  
  Widget build(BuildContext context) {
    return Material(
      child: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: [
            ElevatedButton(
              onPressed: _getBatteryLevel,
              child: const Text('Get Battery Level'),
            ),
            // 3.
            Text('$_batteryLevel'),
          ],
        ),
      ),
    );
  }
}

안드로이드에서

프로젝트명/android/app/src/main/kotlin/com/example/batterylevel/MainActivity.kt 에 작업

코드 작성을 vscode에서 해도 되는데 안드로이드 스튜디오에서 하는게 정신건강에 좋아보였다. (vscode에 코틀린 공식 익스텐션이 없는듯)
실행은 원래 하던대로 본인 에디터(vs code 등)에서 해도 된다.

안드로이드 스튜디오 - File - Open - 플러터 프로젝트의 android폴더 선택

  • 안드로이드 말고 그냥 플러터 프로젝트 루트 골랐다가, 라이브러리들 못불러와서 한참 헤맸다.
  • 기본 라이브러리들 못불러오는 등 뭔가 이상한 문제들이 있다면
    • flutter 플러그인 깔기 (안드로이드 스튜디오에서)
    • file - invalid cache 시도
    • 안되면 gradle sync 시도
    • 안되면 gradle에 의존성 넣기 시도

코드는 아래와 같다. 요약하면 이런듯

  • 아래 메소드에서 플러터가 보낸 메시지를 수신하고 처리해서 응답한다.
    • MethodChannel(대충 플러터 내장 뭐, 채널 이름).setMethodCallHandler
  • 특정 메소드를 포착해서 처리한다
    • if (call.method == "getBatteryLevel")
  • 응답은 이렇게 돌려준다
    • result.success(응답할 값)
    • result.error("에러코드", "에러메세지", 에러 디테일)
package com.뭐시기.패키지이름

import androidx.annotation.NonNull
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel

import android.content.Context
import android.content.ContextWrapper
import android.content.Intent
import android.content.IntentFilter
import android.os.BatteryManager
import android.os.Build.VERSION
import android.os.Build.VERSION_CODES

class MainActivity: FlutterActivity() {
    private val CHANNEL = "samples.flutter.dev/battery"

    override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler {
                call, result ->
            if (call.method == "getBatteryLevel") {
                val batteryLevel = getBatteryLevel()

                if (batteryLevel != -1) {
                    result.success(batteryLevel)
                } else {
                    result.error("UNAVAILABLE", "Battery level not available.", null)
                }
            } else {
                result.notImplemented()
            }
        }
    }

    private fun getBatteryLevel(): Int {
        val batteryLevel: Int
        if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
            val batteryManager = getSystemService(Context.BATTERY_SERVICE) as BatteryManager
            batteryLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
        } else {
            val intent = ContextWrapper(applicationContext).registerReceiver(null, IntentFilter(Intent.ACTION_BATTERY_CHANGED))
            batteryLevel = intent!!.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) * 100 / intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1)
        }

        return batteryLevel
    }

}

아이폰에서

맥북이 없어서 아직 못해봤다.
아무튼 프로젝트 이름/ios/Runner/AppDelegate.swift 에 코드 작성

공식문서는 대충 이렇게 쓴다. 안드로이드랑 별 다를게 없어보인다.

** 주의 : iOS 시뮬레이터는 배터리 API지원 안한다.

 let batteryChannel = FlutterMethodChannel(name: "samples.flutter.dev/battery",
                                              binaryMessenger: controller.binaryMessenger)
    batteryChannel.setMethodCallHandler({
        [weak self] (call: FlutterMethodCall, result: FlutterResult) -> Void in
      guard call.method == "getBatteryLevel" else {
        result(FlutterMethodNotImplemented)
        return
    }
    self?.receiveBatteryLevel(result: result)
  })
})

Pigeon : 플랫폼 채널 타입안전

https://pub.dev/packages/pigeon

MethodChannel 대신 Pigeon 패키지 사용할 수 있음.
타입안전도 얻고, 구조적으로 메시지를 보낼 수 있다.
코드생성기임. (마치 이전에 본 json_serializable 처럼)

flutter pub get
flutter pub run pigeon

자동 플랫폼 적응

Automatic platform adaptations.

플랫폼 적응성에 고려되는 동작은 두 가지로 나눌 수 있음

  • OS 동작 : 플러터로 자동적응 할 수 있음
  • 특정 OS의 앱 내에서 일반적으로 구현되는 동작 : 알아서 적응 시켜야함.

OS동작에 해당해서 플러터가 알잘딱 플랫폼적응 해주는 것들을 나열한다.
영상이랑 그림, 기본설정 바꾸는 방법까지 있으니까 밑에 가서 보는게 빠르다. 요약할게 딱히 없다.

https://docs.flutter.dev/platform-integration/platform-adaptations

  • 페이지 네비게이션 트랜지션
  • 스크롤링
  • 타이포그래피
  • 아이콘
  • 햅틱 피드백
  • 텍스트 편집
  • UI 컴포넌트
    • adaptive 생성자
    • app bar, navigation bar
    • bottom navigation bar
    • text field
    • alert dialog
profile
노는게 제일 좋습니다.

0개의 댓글

관련 채용 정보