Flutter는 구글이 개발한 강력한 UI 툴킷으로, 단일 코드베이스를 통해 모바일, 웹, 데스크톱 애플리케이션을 아름답고 네이티브하게 컴파일할 수 있게 해줍니다. Flutter 생태계의 핵심적인 강점 중 하나는 바로 패키지(Package) 시스템입니다. 패키지는 다른 개발자들이 만든 기능을 손쉽게 가져와 내 프로젝트에 통합할 수 있게 해주어, 개발 속도를 획기적으로 높이고 코드의 품질을 향상시킵니다. 수많은 개발자들이 pub.dev를 통해 유용한 패키지를 공유하고 있습니다.
하지만 단순히 다른 사람의 패키지를 사용하는 것을 넘어, 직접 나만의 패키지를 만들어 본 경험은 개발자로서 한 단계 더 성장하는 중요한 계기가 됩니다. 이 글에서는 Flutter 패키지를 왜 만들어야 하는지부터 시작하여, 실제 패키지를 개발하고, 테스트하며, 전 세계 개발자들과 공유하기 위해 pub.dev에 배포하는 전체 과정을 상세하고 친절하게 안내합니다.
1. 왜 나만의 Flutter 패키지를 만들어야 할까?
이미 수많은 훌륭한 패키지가 있는데, 굳이 직접 패키지를 만들어야 할 이유가 있을까요? 정답은 '그렇다'입니다. 나만의 패키지를 만드는 것은 단순히 코드를 재사용하는 것을 넘어 여러 가지 중요한 이점을 제공합니다.
- 궁극의 코드 재사용성: 여러 프로젝트에서 공통적으로 사용되는 기능(예: 커스텀 위젯, 유틸리티 함수, API 클라이언트 등)이 있다면, 이를 패키지로 분리하여 관리할 수 있습니다. 새로운 프로젝트를 시작할 때마다 코드를 복사-붙여넣기 할 필요 없이,
pubspec.yaml
파일에 한 줄만 추가하면 됩니다. - 체계적인 유지보수: 공통 코드가 여러 프로젝트에 흩어져 있다면, 버그 수정이나 기능 개선이 필요할 때 모든 프로젝트를 일일이 찾아다니며 수정해야 합니다. 이는 매우 비효율적이며 실수를 유발하기 쉽습니다. 하지만 패키지로 관리하면, 패키지 코드만 수정하고 버전을 업데이트하면 해당 패키지를 사용하는 모든 프로젝트에 일괄적으로 개선 사항을 적용할 수 있습니다.
- 프로젝트 모듈화 및 관심사 분리: 거대한 단일 애플리케이션(Monolithic)은 구조가 복잡해지고 관리가 어려워지는 경향이 있습니다. 핵심 기능을 독립적인 패키지로 분리하면 프로젝트의 구조가 명확해지고, 각 팀이나 개발자가 특정 모듈에만 집중할 수 있어 협업 효율성이 높아집니다.
- 오픈소스 커뮤니티 기여: 내가 만든 유용한 기능을 패키지로 만들어 공개하면 전 세계의 다른 Flutter 개발자들에게 큰 도움이 될 수 있습니다. 이는 Flutter 생태계를 더욱 풍성하게 만드는 의미 있는 기여이며, 다른 개발자들로부터 피드백을 받으며 코드를 개선하고 실력을 향상시키는 좋은 기회가 됩니다.
- 개인 포트폴리오 강화: 잘 만들어진 패키지는 개발자로서의 당신의 실력을 증명하는 훌륭한 포트폴리오가 될 수 있습니다.
패키지(Package)와 플러그인(Plugin)의 차이점
Flutter에서 '패키지'라는 용어는 종종 두 가지 의미로 사용됩니다. 이 둘의 차이점을 명확히 이해하는 것이 중요합니다.
- 패키지 (Package): 순수하게 Dart 언어로만 작성된 코드를 포함합니다. UI 컴포넌트, 비즈니스 로직, 헬퍼 클래스 등 플랫폼별 네이티브 코드와의 통신이 필요 없는 모든 기능이 여기에 해당합니다. 이 글에서 다루는 주된 내용입니다.
- 플러그인 (Plugin): Dart 코드와 함께 Android(Kotlin/Java) 또는 iOS(Swift/Objective-C) 같은 플랫폼별 네이티브 코드를 포함하는 특별한 종류의 패키지입니다. 배터리 정보, GPS, 카메라, 블루투스 등 디바이스의 고유 기능을 사용해야 할 때 플랫폼 채널(Platform Channels)을 통해 네이티브 API를 호출하는 역할을 합니다.
간단히 말해, 모든 플러그인은 패키지이지만, 모든 패키지가 플러그인은 아닙니다. 이번 가이드에서는 순수 Dart로만 구성된 '패키지' 제작에 집중하겠습니다.
2. 패키지 개발을 위한 환경 설정
본격적으로 패키지 개발을 시작하기 전에, 필요한 개발 환경이 올바르게 구성되어 있는지 확인해야 합니다. 대부분의 Flutter 개발자들은 이미 환경 설정이 완료되었겠지만, 처음 시작하거나 점검이 필요한 분들을 위해 간단히 짚고 넘어가겠습니다.
Flutter SDK 설치 및 확인
Flutter 패키지 개발은 당연히 Flutter SDK를 기반으로 합니다. 아직 설치하지 않았다면 아래 단계를 따라주세요.
- Flutter 공식 웹사이트에서 자신의 운영체제에 맞는 최신 버전의 Flutter SDK를 다운로드합니다.
- 다운로드한 압축 파일을 원하는 위치(예:
C:\src\flutter
또는~/development/flutter
)에 해제합니다. - 시스템 환경 변수
PATH
에 방금 압축 해제한 폴더 안의flutter/bin
디렉토리 경로를 추가합니다. 이 과정을 통해 터미널 어디에서든flutter
명령어를 실행할 수 있게 됩니다. - 터미널을 새로 열고 아래 명령어를 실행하여 설치 상태를 점검합니다.
$ flutter doctor
flutter doctor
명령어는 Flutter 개발에 필요한 요소(Android toolchain, Xcode, Chrome, Android Studio 등)들이 제대로 설치되고 설정되었는지 종합적으로 검사해주는 매우 유용한 도구입니다. 만약 [!]
또는 [X]
표시와 함께 문제점이 보고된다면, 해당 메시지의 안내에 따라 문제를 해결해야 합니다.
Dart SDK 확인
Flutter SDK에는 Dart SDK가 이미 포함되어 있습니다. 따라서 Flutter를 정상적으로 설치했다면 별도로 Dart SDK를 설치할 필요가 없습니다. 터미널에서 다음 명령어를 실행하여 Dart가 제대로 인식되는지 확인할 수 있습니다.
$ dart --version
Flutter와 함께 번들된 Dart의 버전 정보가 출력된다면 모든 준비가 완료된 것입니다.
코드 에디터 준비
VS Code나 Android Studio/IntelliJ와 같은 IDE(통합 개발 환경)를 사용하는 것을 강력히 추천합니다. 이들 에디터는 Flutter와 Dart를 위한 공식 확장 프로그램(Extension/Plugin)을 제공하여, 코드 자동 완성, 디버깅, 핫 리로드 등 개발 생산성을 극대화하는 다양한 기능을 지원합니다.
3. 첫 번째 Flutter 패키지 생성하기
환경 설정이 끝났다면, 이제 드디어 나만의 패키지를 만들어 볼 차례입니다. Flutter CLI는 패키지 프로젝트의 기본 골격을 자동으로 생성해주는 편리한 명령어를 제공합니다.
패키지 프로젝트 생성
터미널을 열고 패키지를 생성하고 싶은 상위 디렉토리로 이동한 후, 다음 명령어를 실행하세요. 패키지 이름은 소문자와 언더스코어(_)만 사용해야 합니다(lower_case_with_underscores).
$ flutter create --template=package simple_validator
위 명령어를 실행하면 simple_validator
라는 이름의 디렉토리가 생성되고, 그 안에 Flutter 패키지에 필요한 기본 파일과 폴더 구조가 자동으로 만들어집니다. --template=package
플래그는 Flutter CLI에게 일반적인 앱이 아닌, 재사용 가능한 패키지를 생성하도록 지시하는 역할을 합니다.
생성된 패키지 구조 살펴보기
생성된 simple_validator
디렉토리로 이동하여 내부 구조를 살펴보겠습니다. 각 파일과 폴더는 중요한 역할을 담당합니다.
simple_validator/
├── .gitignore
├── .metadata
├── CHANGELOG.md
├── LICENSE
├── README.md
├── analysis_options.yaml
├── example/
│ ├── ... (패키지를 테스트하고 시연하기 위한 예제 Flutter 앱)
├── lib/
│ ├── simple_validator.dart
│ └── src/
├── pubspec.yaml
└── test/
└── simple_validator_test.dart
lib/
: 이 폴더는 패키지의 심장입니다. 패키지를 사용하는 외부 프로젝트에서 접근할 수 있는 모든 공개(public) 코드는 이 폴더 안에 위치해야 합니다.lib/simple_validator.dart
: 패키지의 메인 파일입니다. 다른 프로젝트에서import 'package:simple_validator/simple_validator.dart';
와 같이 이 파일을 임포트하여 패키지의 기능을 사용하게 됩니다.lib/src/
: 패키지 내부에서만 사용되는 비공개(private) 구현 코드를 넣는 곳입니다.src
폴더 안의 파일들은 외부에서 직접 임포트하지 않도록 하는 것이 관례입니다.
pubspec.yaml
: 패키지의 모든 메타데이터를 정의하는 가장 중요한 파일입니다. 패키지 이름, 설명, 버전, 저자 정보, 그리고 다른 패키지에 대한 의존성 등을 명시합니다.README.md
: 패키지에 대한 설명서입니다. 이 패키지가 무엇을 하는지, 어떻게 설치하고 사용하는지, 어떤 기능을 제공하는지 등을 상세히 작성해야 합니다. pub.dev에 패키지를 게시하면 이 파일의 내용이 패키지 소개 페이지에 표시됩니다.CHANGELOG.md
: 각 버전별 변경 사항을 기록하는 파일입니다. 새로운 기능 추가, 버그 수정, 주요 변경점 등을 사용자가 쉽게 파악할 수 있도록 도와줍니다.LICENSE
: 패키지의 라이선스를 명시하는 파일입니다. 다른 개발자들이 어떤 조건 하에 당신의 코드를 사용할 수 있는지 법적으로 정의합니다. 특별한 이유가 없다면 MIT나 Apache 2.0과 같은 관대한 오픈소스 라이선스를 사용하는 것이 일반적입니다.test/
: 패키지의 코드를 테스트하기 위한 테스트 코드가 위치하는 폴더입니다. 품질 높은 패키지를 만들기 위해서는 테스트 작성이 필수적입니다.example/
: 이 패키지를 실제로 어떻게 사용하는지 보여주는 예제 Flutter 애플리케이션이 들어있는 폴더입니다. 사용자는 이 예제 앱을 실행해보며 패키지의 기능을 직관적으로 이해할 수 있으며, 개발자에게는 패키지를 개발하면서 실제 앱 환경에서 테스트해보는 훌륭한 공간이 됩니다.
간단한 기능 구현하기
이제 simple_validator
패키지에 실제 기능을 추가해 보겠습니다. 이메일 형식과 빈 문자열을 검증하는 간단한 유효성 검사 클래스를 만들어 봅시다.
먼저, lib/simple_validator.dart
파일을 열고 기존 내용을 모두 삭제한 후, 아래 코드를 작성합니다.
/// 간단한 문자열 유효성 검사 기능을 제공하는 라이브러리입니다.
library simple_validator;
// 패키지 내부 구현 코드를 외부에 노출시키기 위해 export 합니다.
export 'src/validator.dart';
다음으로, lib/src/
폴더 안에 validator.dart
라는 새 파일을 만들고 아래와 같이 클래스를 작성합니다. 실제 로직은 이 파일에 구현됩니다.
/// 문자열 유효성 검사 메서드를 모아놓은 클래스
class Validator {
/// 주어진 문자열이 유효한 이메일 형식인지 확인합니다.
///
/// 간단한 정규 표현식을 사용합니다.
/// ```dart
/// Validator.isEmail('test@example.com'); // true
/// Validator.isEmail('test.com'); // false
/// ```
static bool isEmail(String email) {
if (email.isEmpty) return false;
// 간단한 이메일 정규식
final RegExp emailRegExp = RegExp(
r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$',
);
return emailRegExp.hasMatch(email);
}
/// 주어진 문자열이 비어있지 않은지 확인합니다.
///
/// 앞뒤 공백을 제거한 후 길이를 확인합니다.
/// ```dart
/// Validator.isNotEmpty('hello'); // true
/// Validator.isNotEmpty(' '); // false
/// Validator.isNotEmpty(null); // false
/// ```
static bool isNotEmpty(String? text) {
return text?.trim().isNotEmpty ?? false;
}
}
이렇게 lib/src/
에 실제 구현을 두고 메인 파일(lib/simple_validator.dart
)에서 export
하는 구조는 패키지의 내부 구현을 숨기고 외부에 필요한 API만 노출시키는 좋은 방법입니다.
4. 패키지 테스트하기
신뢰할 수 있는 패키지를 만들기 위해서는 철저한 테스트가 필수입니다. 테스트는 코드가 예상대로 동작하는지 보장하고, 향후 리팩토링이나 기능 추가 시 발생할 수 있는 예기치 않은 버그(회귀 버그)를 방지하는 안전망 역할을 합니다.
단위 테스트(Unit Test) 작성하기
단위 테스트는 가장 작고 독립적인 코드 단위(함수, 메서드, 클래스)를 테스트하는 것입니다. 우리
는 방금 만든 Validator
클래스의 각 메서드가 정확하게 동작하는지 확인하는 단위 테스트를 작성할 것입니다.
test/simple_validator_test.dart
파일을 열고 다음 코드로 내용을 교체합니다.
import 'package:flutter_test/flutter_test.dart';
import 'package:simple_validator/simple_validator.dart';
void main() {
// 테스트들을 그룹화하여 가독성을 높입니다.
group('Validator.isEmail', () {
test('유효한 이메일 주소를 전달하면 true를 반환한다', () {
// Arrange (준비)
const email = 'test@example.com';
// Act (실행)
final result = Validator.isEmail(email);
// Assert (검증)
expect(result, isTrue);
});
test('골뱅이(@)가 없는 이메일 주소는 false를 반환한다', () {
expect(Validator.isEmail('testexample.com'), isFalse);
});
test('도메인이 없는 이메일 주소는 false를 반환한다', () {
expect(Validator.isEmail('test@'), isFalse);
});
test('빈 문자열은 false를 반환한다', () {
expect(Validator.isEmail(''), isFalse);
});
});
group('Validator.isNotEmpty', () {
test('내용이 있는 문자열은 true를 반환한다', () {
expect(Validator.isNotEmpty('hello'), isTrue);
});
test('공백만 있는 문자열은 false를 반환한다', () {
expect(Validator.isNotEmpty(' '), isFalse);
});
test('빈 문자열은 false를 반환한다', () {
expect(Validator.isNotEmpty(''), isFalse);
});
test('null 값은 false를 반환한다', () {
expect(Validator.isNotEmpty(null), isFalse);
});
});
}
위 코드는 test
패키지에서 제공하는 group
, test
, expect
함수를 사용합니다. 각 테스트 케이스는 특정 조건에서 함수가 기대하는 값을 반환하는지 검증합니다. 이제 터미널에서 패키지의 루트 디렉토리로 이동한 후 다음 명령어를 실행하여 테스트를 진행합니다.
$ flutter test
모든 테스트가 성공적으로 통과했다는 메시지가 나타나면, 우리 패키지의 핵심 로직이 잘 작동하고 있음을 확신할 수 있습니다.
예제 앱으로 테스트하기
단위 테스트가 로직의 정확성을 보장한다면, 예제 앱은 실제 Flutter 환경에서 패키지가 어떻게 사용되고 동작하는지 확인하는 데 매우 유용합니다. example/
디렉토리로 이동하여 일반적인 Flutter 앱을 개발하듯이 코드를 작성하고 실행할 수 있습니다.
example/lib/main.dart
파일을 수정하여 우리가 만든 Validator
를 사용하는 간단한 UI를 만들어보세요. 이를 통해 개발 중인 패키지를 실제 앱처럼 사용해보며 테스트하고 디버깅할 수 있습니다.
5. pub.dev에 패키지 배포하기
패키지 개발과 테스트를 마쳤다면, 이제 전 세계 개발자들과 공유할 시간입니다. Flutter 패키지의 공식 저장소인 pub.dev에 배포하는 과정을 알아보겠습니다.
배포 전 준비사항
패키지를 배포하기 전에 몇 가지 중요한 파일을 점검하고 내용을 채워야 합니다. 이는 패키지의 품질을 높이고 다른 사용자들이 패키지를 쉽게 이해하고 사용할 수 있도록 돕습니다.
pubspec.yaml
업데이트:패키지의 메타데이터를 정확하게 기입합니다. 특히 다음 필드들은 매우 중요합니다.
description
: 패키지에 대한 간결하고 명확한 설명입니다. pub.dev 검색 결과와 패키지 페이지 상단에 표시됩니다. 최소 60자 이상으로 작성하는 것이 좋습니다.version
: 패키지의 버전입니다. 유의적 버전(Semantic Versioning) 규칙(MAJOR.MINOR.PATCH
)을 따르는 것이 좋습니다. 첫 배포이므로1.0.0
또는0.0.1
로 시작할 수 있습니다.homepage
: (선택사항이지만 강력히 권장) 패키지의 소스 코드가 있는 GitHub 저장소나 공식 웹사이트 URL을 기입합니다. 사용자들이 소스 코드를 보거나 이슈를 제기하는 데 도움이 됩니다.repository
: (선택사항) 패키지의 버전 관리 시스템(VCS) 저장소 URL을 명시합니다. 보통homepage
와 동일한 GitHub 저장소 주소를 넣습니다.
name: simple_validator description: A simple and lightweight package for string validation, including email and non-empty checks. version: 1.0.0 homepage: https://github.com/your_username/simple_validator repository: https://github.com/your_username/simple_validator environment: sdk: '>=2.19.0 <4.0.0' flutter: ">=1.17.0" dependencies: flutter: sdk: flutter dev_dependencies: flutter_test: sdk: flutter flutter_lints: ^2.0.0
README.md
작성: 패키지의 사용법을 상세히 설명하는 문서를 작성합니다. 좋은 README는 패키지의 첫인상을 결정합니다.CHANGELOG.md
작성: 첫 배포이므로, 초기 버전에 대한 설명을 작성합니다. (예: `## 1.0.0 - Initial release.`)LICENSE
파일 확인: 어떤 라이선스를 사용할지 결정하고 파일 내용을 확인합니다. MIT 라이선스가 가장 널리 사용됩니다.
배포 명령어 실행
모든 준비가 끝났다면, 이제 터미널을 통해 패키지를 배포할 수 있습니다.
1. 드라이 런 (Dry Run):
실제로 배포하기 전에, 배포 과정에서 발생할 수 있는 문제점들을 미리 확인하는 것이 좋습니다. --dry-run
플래그를 사용하면 실제 배포 없이 시뮬레이션만 실행합니다.
$ flutter pub publish --dry-run
이 명령어는 pubspec.yaml
, README.md
, CHANGELOG.md
등의 파일이 잘 준비되었는지, 코드에 경고나 에러는 없는지 등을 검사합니다. "Package has 0 warnings." 메시지가 나타나면 배포 준비가 완료된 것입니다. 만약 경고나 에러가 있다면, 메시지를 잘 읽고 해당 문제를 수정한 후 다시 시도해야 합니다.
2. 실제 배포 (Publish):
드라이 런을 성공적으로 통과했다면, 이제 진짜 배포를 진행합니다.
$ flutter pub publish
이 명령어를 처음 실행하면, pub.dev에 인증하기 위해 구글 계정으로 로그인하라는 메시지와 함께 브라우저 창이 열립니다. 로그인을 완료하고 권한을 부여하면 터미널에서 배포가 계속 진행됩니다. 정말로 배포할 것인지 묻는 메시지(Are you ready to publish simple_validator 1.0.0 (y/N)?
)가 나타나면 y
를 입력하고 엔터를 누릅니다.
잠시 후 "Successfully uploaded package." 메시지가 보이면 배포가 성공적으로 완료된 것입니다!
배포 후 확인
이제 웹 브라우저에서 https://pub.dev/packages/your_package_name
(예: https://pub.dev/packages/simple_validator
)으로 접속하여 당신의 패키지가 잘 올라왔는지 확인해보세요. README 내용이 잘 보이는지, 버전 정보와 메타데이터가 정확한지 등을 점검합니다. pub.dev는 패키지의 코드 품질, 문서화 수준 등을 분석하여 'Pub Points'라는 점수를 매겨주는데, 이 점수를 높이기 위해 노력하는 것도 좋은 목표가 될 수 있습니다.
마치며: 당신의 여정은 이제 시작입니다
이 글을 통해 우리는 Flutter 패키지를 만들고, 테스트하며, 전 세계에 공유하는 전체 과정을 함께 여행했습니다. 이제 당신은 단순히 코드를 작성하는 개발자를 넘어, 다른 개발자들의 생산성을 높이고 Flutter 생태계에 기여할 수 있는 패키지 제작자의 역량을 갖추게 되었습니다.
자신만의 첫 번째 패키지를 만드는 것은 때로는 도전적일 수 있지만, 그 과정에서 얻는 경험과 지식은 무엇과도 바꿀 수 없는 자산이 될 것입니다. 반복되는 코드를 발견하면 주저하지 말고 패키지로 만들어보세요. 작고 사소한 유틸리티라도 좋습니다. 당신의 작은 시작이 누군가에게는 큰 도움이 될 수 있습니다.
궁금한 점이 있다면 언제나 Flutter 공식 문서를 참고하고, pub.dev에서 다른 훌륭한 패키지들의 소스 코드를 분석하며 영감을 얻는 것을 추천합니다. 당신의 멋진 아이디어가 담긴 패키지를 pub.dev에서 만나기를 기대하겠습니다. Happy coding!
0 개의 댓글:
Post a Comment