Flutter 튜토리얼 55편: 플랫폼 통합 기초
Flutter 플랫폼 통합 기초
Flutter는 단일 코드베이스로 여러 플랫폼에 앱을 배포할 수 있습니다. 이 튜토리얼에서는 Flutter가 지원하는 플랫폼과 네이티브 코드를 통합하는 기본 방법을 배웁니다.
학습 목표
- Flutter가 지원하는 플랫폼 이해하기
- 데스크톱 앱 개발 환경 설정하기
- FFI로 네이티브 코드 호출하기
- 플랫폼별 고려사항 파악하기
1. 지원 플랫폼 개요
Why: 플랫폼별 특성을 알아야 하는 이유
각 플랫폼은 고유한 특성과 요구사항이 있습니다. 이를 이해하면 최적화된 앱을 개발할 수 있습니다.
What: Flutter가 지원하는 플랫폼
What: 모바일 플랫폼 지원
| 플랫폼 | 지원 버전 | 아키텍처 |
|---|---|---|
| Android | API 21+ (Android 5.0) | arm64-v8a, armeabi-v7a, x86_64 |
| iOS | iOS 12+ | arm64 |
What: 데스크톱 플랫폼 지원
| 플랫폼 | 지원 버전 | 아키텍처 |
|---|---|---|
| Windows | Windows 10+ | x64, arm64 |
| macOS | Catalina (10.15)+ | x64, arm64 |
| Linux | Debian, Ubuntu 등 | x64 |
What: 웹 플랫폼 지원
| 브라우저 | 지원 |
|---|---|
| Chrome | ✅ 완전 지원 |
| Firefox | ✅ 완전 지원 |
| Safari | ✅ 완전 지원 |
| Edge | ✅ 완전 지원 |
How: 플랫폼별 프로젝트 생성
# 모든 플랫폼 지원 프로젝트 생성flutter create my_app
# 특정 플랫폼만 지원flutter create --platforms=android,ios,web my_app
# 기존 프로젝트에 플랫폼 추가flutter create --platforms=windows,macos,linux .Watch out: 주의사항
모든 패키지가 모든 플랫폼을 지원하는 것은 아닙니다. pub.dev에서 패키지의 플랫폼 호환성을 확인하세요.
2. 데스크톱 개발 환경 설정
Why: 데스크톱 앱이 필요한 이유
데스크톱 앱은 모바일보다 더 많은 리소스와 화면 공간을 활용할 수 있습니다. 생산성 도구, 전문 소프트웨어 등에 적합합니다.
What: 플랫폼별 필수 도구
How: Windows 개발 환경
# 필수 도구 설치# 1. Visual Studio 2022 with "Desktop development with C++" 워크로드# 2. Windows 10 SDK
# Flutter 설정 확인flutter doctor
# Windows 앱 실행flutter run -d windowsHow: macOS 개발 환경
# Xcode 설치 (App Store에서)# Xcode Command Line Tools 설치xcode-select --install
# CocoaPods 설치sudo gem install cocoapods
# Flutter 설정 확인flutter doctor
# macOS 앱 실행flutter run -d macosHow: Linux 개발 환경
# Ubuntu/Debian 필수 패키지 설치sudo apt-get updatesudo apt-get install clang cmake ninja-build pkg-config \ libgtk-3-dev liblzma-dev libstdc++-12-dev
# Flutter 설정 확인flutter doctor
# Linux 앱 실행flutter run -d linuxHow: 데스크톱 앱 빌드
# Windows 빌드flutter build windows
# macOS 빌드flutter build macos
# Linux 빌드flutter build linux빌드 결과물 위치:
| 플랫폼 | 위치 |
|---|---|
| Windows | build/windows/x64/runner/Release/ |
| macOS | build/macos/Build/Products/Release/ |
| Linux | build/linux/x64/release/bundle/ |
Watch out: 주의사항
데스크톱 앱은 화면 크기가 다양합니다. 반응형 레이아웃을 구현하여 다양한 윈도우 크기에 대응하세요.
3. FFI 기초 (Foreign Function Interface)
Why: FFI가 필요한 이유
Flutter만으로 구현하기 어려운 기능이 있습니다. FFI1를 사용하면 C/C++ 등의 네이티브 라이브러리를 직접 호출할 수 있습니다.
What: FFI vs Platform Channels
| 방식 | 장점 | 단점 | 적합한 경우 |
|---|---|---|---|
| FFI | 빠름, 직접 호출 | 플랫폼별 빌드 필요 | C 라이브러리 사용 |
| Platform Channels | 유연함, 플랫폼 API 접근 | 오버헤드 있음 | 플랫폼 기능 호출 |
What: FFI 지원 플랫폼
| 플랫폼 | FFI 지원 |
|---|---|
| Android | ✅ |
| iOS | ✅ |
| Windows | ✅ |
| macOS | ✅ |
| Linux | ✅ |
| Web | ❌ (WASM 별도) |
How: FFI 패키지 프로젝트 생성
# FFI 템플릿으로 프로젝트 생성flutter create --template=package_ffi native_add생성되는 구조:
native_add/├── lib/│ └── native_add.dart # Dart API├── src/│ └── native_add.c # C 소스 코드├── hook/│ └── build.dart # 빌드 훅└── pubspec.yamlHow: C 코드 작성
#include <stdint.h>
// FFI_PLUGIN_EXPORT는 함수를 외부에 노출합니다#if _WIN32#define FFI_PLUGIN_EXPORT __declspec(dllexport)#else#define FFI_PLUGIN_EXPORT#endif
// 간단한 덧셈 함수FFI_PLUGIN_EXPORT int32_t native_add(int32_t a, int32_t b) { return a + b;}
// 문자열 반환 예제FFI_PLUGIN_EXPORT const char* get_platform_name() { #if _WIN32 return "Windows"; #elif __APPLE__ return "macOS"; #elif __linux__ return "Linux"; #elif __ANDROID__ return "Android"; #else return "Unknown"; #endif}How: Dart 바인딩 작성
import 'dart:ffi';import 'dart:io';
import 'package:ffi/ffi.dart';
// 네이티브 함수 시그니처 정의typedef NativeAddFunc = Int32 Function(Int32 a, Int32 b);typedef NativeAdd = int Function(int a, int b);
typedef GetPlatformNameFunc = Pointer<Utf8> Function();typedef GetPlatformName = Pointer<Utf8> Function();
class NativeAddBindings { late final DynamicLibrary _lib; late final NativeAdd _nativeAdd; late final GetPlatformName _getPlatformName;
NativeAddBindings() { _lib = _loadLibrary(); _nativeAdd = _lib .lookupFunction<NativeAddFunc, NativeAdd>('native_add'); _getPlatformName = _lib .lookupFunction<GetPlatformNameFunc, GetPlatformName>('get_platform_name'); }
DynamicLibrary _loadLibrary() { if (Platform.isAndroid) { return DynamicLibrary.open('libnative_add.so'); } else if (Platform.isIOS) { return DynamicLibrary.process(); } else if (Platform.isWindows) { return DynamicLibrary.open('native_add.dll'); } else if (Platform.isMacOS) { return DynamicLibrary.open('libnative_add.dylib'); } else if (Platform.isLinux) { return DynamicLibrary.open('libnative_add.so'); } throw UnsupportedError('현재 플랫폼은 지원하지 않습니다'); }
int add(int a, int b) => _nativeAdd(a, b);
String getPlatformName() { final ptr = _getPlatformName(); return ptr.toDartString(); }}Watch out: 주의사항
FFI는 메모리를 직접 다루므로 주의가 필요합니다. 잘못된 포인터 사용은 앱 크래시를 유발할 수 있습니다.
4. 빌드 훅 시스템
Why: 빌드 훅이 필요한 이유
네이티브 코드는 플랫폼마다 다르게 빌드해야 합니다. 빌드 훅2을 사용하면 이 과정을 자동화할 수 있습니다.
What: 빌드 훅의 역할
How: 빌드 훅 작성
import 'package:native_assets_cli/native_assets_cli.dart';import 'package:native_toolchain_c/native_toolchain_c.dart';
void main(List<String> args) async { await build(args, (config, output) async { final packageName = config.packageName; final cBuilder = CBuilder.library( name: packageName, assetName: '${packageName}_bindings_generated.dart', sources: [ 'src/$packageName.c', ], ); await cBuilder.run( config: config, output: output, logger: Logger('')..level = Level.ALL, ); });}How: pubspec.yaml 설정
name: native_adddescription: A native add package using FFI.version: 1.0.0
environment: sdk: ">=3.0.0 <4.0.0" flutter: ">=3.0.0"
dependencies: ffi: ^2.0.0
dev_dependencies: ffigen: ^9.0.0 native_assets_cli: ^0.5.0 native_toolchain_c: ^0.5.0Watch out: 주의사항
빌드 훅은 Flutter 3.16 이상에서 사용할 수 있습니다. 이전 버전에서는 수동으로 네이티브 코드를 빌드해야 합니다.
5. 플랫폼별 고려사항
Why: 플랫폼마다 다른 점을 알아야 하는 이유
각 플랫폼은 고유한 UI 가이드라인과 사용자 기대가 있습니다. 이를 무시하면 어색한 사용자 경험을 제공하게 됩니다.
What: 플랫폼별 UI 특성
| 플랫폼 | 내비게이션 | 스크롤 | 텍스트 선택 |
|---|---|---|---|
| Android | 뒤로가기 버튼 | 물리 기반 | 드래그 핸들 |
| iOS | 스와이프 백 | 바운스 | 커서 + 루페 |
| 데스크톱 | 메뉴바 | 마우스휠 | 마우스 드래그 |
| 웹 | 브라우저 네비게이션 | 네이티브 | 네이티브 |
How: 플랫폼 감지
import 'dart:io';import 'package:flutter/foundation.dart';
// 플랫폼 확인if (Platform.isAndroid) { // Android 전용 로직}
if (Platform.isIOS) { // iOS 전용 로직}
if (Platform.isWindows || Platform.isMacOS || Platform.isLinux) { // 데스크톱 전용 로직}
// 웹 확인 (dart:io 사용 불가)if (kIsWeb) { // 웹 전용 로직}How: 플랫폼별 UI 적용
import 'package:flutter/cupertino.dart';import 'package:flutter/material.dart';
class AdaptiveButton extends StatelessWidget { final VoidCallback onPressed; final Widget child;
const AdaptiveButton({ super.key, required this.onPressed, required this.child, });
@override Widget build(BuildContext context) { final platform = Theme.of(context).platform;
if (platform == TargetPlatform.iOS || platform == TargetPlatform.macOS) { return CupertinoButton( onPressed: onPressed, child: child, ); }
return ElevatedButton( onPressed: onPressed, child: child, ); }}How: 플랫폼별 네비게이션
import 'package:flutter/material.dart';
class AdaptiveScaffold extends StatelessWidget { final Widget body; final String title;
const AdaptiveScaffold({ super.key, required this.body, required this.title, });
@override Widget build(BuildContext context) { final isDesktop = MediaQuery.of(context).size.width > 600;
if (isDesktop) { return Scaffold( body: Row( children: [ NavigationRail( destinations: const [ NavigationRailDestination( icon: Icon(Icons.home), label: Text('홈'), ), NavigationRailDestination( icon: Icon(Icons.settings), label: Text('설정'), ), ], selectedIndex: 0, onDestinationSelected: (index) {}, ), Expanded(child: body), ], ), ); }
return Scaffold( appBar: AppBar(title: Text(title)), body: body, bottomNavigationBar: NavigationBar( destinations: const [ NavigationDestination( icon: Icon(Icons.home), label: '홈', ), NavigationDestination( icon: Icon(Icons.settings), label: '설정', ), ], selectedIndex: 0, onDestinationSelected: (index) {}, ), ); }}Watch out: 주의사항
dart:io는 웹에서 사용할 수 없습니다.
웹을 지원하는 앱에서는 kIsWeb으로 먼저 확인한 후
Platform 클래스를 사용하세요.
6. 플랫폼 통합 체크리스트
환경 설정
- 타겟 플랫폼별 개발 도구 설치
-
flutter doctor로 환경 확인 - 플랫폼별 시뮬레이터/에뮬레이터 설정
FFI 사용 시
- C 코드 작성 및 테스트
- 플랫폼별 빌드 설정
- Dart 바인딩 작성
- 메모리 관리 확인
배포 준비
- 플랫폼별 UI 테스트
- 성능 테스트 (각 플랫폼에서)
- 패키지 호환성 확인
- 플랫폼별 빌드 및 서명
마무리
이번 튜토리얼에서는 Flutter가 지원하는 플랫폼과 네이티브 코드를 통합하는 기본 방법을 배웠습니다.
핵심 정리
| 주제 | 핵심 내용 |
|---|---|
| 지원 플랫폼 | Android, iOS, Windows, macOS, Linux, Web |
| 데스크톱 개발 | 플랫폼별 개발 도구 필요 |
| FFI | dart |
| 빌드 훅 | 네이티브 코드 자동 빌드 |
| 플랫폼 적응 | Platform, kIsWeb으로 분기 |
다음 단계
- Flutter 공식 문서에서 더 자세한 플랫폼별 가이드를 확인해보세요.
참고 자료
Footnotes
공유
이 글이 도움이 되었다면 다른 사람과 공유해주세요!