Tuesday, August 6, 2019

Flutter 프로젝트, 첫 단추 제대로 끼우기: Kotlin/Swift 기반 최신 앱 개발 시작법

Flutter는 구글이 개발한 오픈소스 UI 소프트웨어 개발 키트로, 단일 코드베이스를 통해 Android, iOS, 웹, 데스크톱 등 다양한 플랫폼에서 네이티브 수준의 성능을 내는 아름다운 애플리케이션을 제작할 수 있게 해줍니다. 개발자들은 Flutter의 빠른 개발 속도, 풍부한 위젯 라이브러리, 그리고 뛰어난 성능에 매료되어 빠르게 Flutter 생태계로 유입되고 있습니다. 하지만 Flutter 프로젝트의 여정을 시작하는 가장 첫 단계, 바로 flutter create 명령어 뒤에 숨겨진 중요한 선택지를 놓치는 경우가 많습니다.

대부분의 Flutter 입문 가이드는 단순히 flutter create my_app이라는 명령어를 알려주는 데 그칩니다. 이 명령어를 실행하면 프로젝트는 문제없이 생성되지만, 한 가지 중요한 사실을 간과하게 됩니다. 바로 네이티브 플랫폼의 기본 언어가 Android는 Java, iOS는 Objective-C로 설정된다는 점입니다. Java와 Objective-C는 오랫동안 각 플랫폼의 표준 언어였지만, 이제는 새로운 시대의 주역인 KotlinSwift에게 자리를 내어주고 있습니다. 이 글에서는 왜 새로운 Flutter 프로젝트를 시작할 때 Kotlin과 Swift를 선택해야 하는지, 그리고 어떻게 설정하는지, 더 나아가 flutter create 명령어의 다양한 옵션을 활용하여 프로젝트를 완벽하게 제어하는 방법을 심도 있게 다룰 것입니다.

1. 왜 Kotlin과 Swift인가? 구시대의 언어를 넘어서야 하는 이유

Flutter는 Dart 언어로 UI와 비즈니스 로직을 작성하지만, 최종적으로 앱이 사용자 기기에서 실행되기 위해서는 각 플랫폼의 네이티브 코드로 컴파일되고 패키징되는 과정을 거칩니다. 카메라, GPS, 블루투스 등 기기의 고유 기능을 사용하거나, 특정 플랫폼에만 존재하는 SDK를 연동해야 할 때 Flutter는 '플랫폼 채널(Platform Channels)'을 통해 네이ティブ 코드와 통신합니다. 이때 우리가 마주하게 되는 코드가 바로 Android의 Kotlin/Java, iOS의 Swift/Objective-C 코드입니다.

Kotlin: 구글이 선택한 안드로이드의 미래

2019년, 구글은 안드로이드 앱 개발의 공식 언어(First-class language)로 Kotlin을 지정했습니다. 이는 안드로이드 생태계의 패러다임이 Java에서 Kotlin으로 완전히 전환되었음을 의미합니다. 새로운 Flutter 프로젝트에서 Kotlin을 사용해야 하는 이유는 명확합니다.

  • 간결하고 표현력 있는 문법: Kotlin은 Java의 장황한 상용구(boilerplate) 코드를 대폭 줄여줍니다. 같은 기능을 구현하더라도 훨씬 적은 양의 코드로 작성할 수 있어 가독성과 생산성이 향상됩니다.
  • Null 안정성(Null Safety): Kotlin의 타입 시스템은 Null Pointer Exception(NPE)을 근본적으로 방지하도록 설계되었습니다. 이는 '10억 달러의 실수'라고 불리는 NPE로부터 앱의 안정성을 획기적으로 높여줍니다.
  • 코루틴(Coroutines)을 통한 비동기 처리: 복잡한 콜백 지옥(Callback Hell) 없이 비동기 코드를 동기 코드처럼 간결하게 작성할 수 있게 해주는 코루틴은 현대적인 앱 개발의 필수 요소입니다.
  • 100% Java 호환성: 기존의 방대한 Java 라이브러리와 프레임워크를 아무런 문제 없이 Kotlin 프로젝트에서 그대로 사용할 수 있습니다.
  • 활발한 커뮤니티와 공식 지원: 구글의 전폭적인 지원 아래 최신 안드로이드 기능과 Jetpack 라이브러리들은 Kotlin을 우선적으로 지원하며, 관련 자료와 커뮤니티 역시 빠르게 성장하고 있습니다.

Swift: 애플이 만든 안전하고 빠른 언어

애플은 2014년에 Swift를 공개하며 iOS 및 macOS 개발의 새로운 시대를 열었습니다. Swift는 Objective-C를 대체하기 위해 만들어졌으며, 현대적인 프로그래밍 언어의 장점을 집약했습니다.

  • 안전성(Safety): Swift는 옵셔널(Optionals) 개념을 통해 변수가 값을 가지지 않는 경우(nil)를 명시적으로 처리하도록 강제하여, 예기치 않은 런타임 오류를 컴파일 시점에 발견할 수 있도록 돕습니다.
  • 속도(Speed): 이름에서 알 수 있듯이, Swift는 C++에 버금가는 높은 성능을 목표로 설계되었습니다. 강력한 컴파일러 최적화를 통해 Objective-C보다 월등한 실행 속도를 보여줍니다.
  • 현대적인 문법: Swift는 다른 현대 언어들처럼 읽고 쓰기 쉬운 깔끔한 문법을 제공합니다. 이는 코드의 유지보수성을 높이고 새로운 개발자의 진입 장벽을 낮춥니다.
  • ARC (Automatic Reference Counting): 메모리 관리를 자동화하여 개발자가 메모리 누수 걱정 없이 비즈니스 로직에 집중할 수 있도록 해줍니다.
  • 애플의 지속적인 투자: 애플은 매년 Swift 언어를 업데이트하며 새로운 기능과 성능 개선을 선보이고 있습니다. SwiftUI와 같은 차세대 프레임워크는 Swift 언어를 기반으로만 동작합니다.

결론적으로, 새로운 Flutter 프로젝트를 Java와 Objective-C로 시작하는 것은 마치 최신형 전기차를 구매하면서 구형 가솔린 엔진을 장착하는 것과 같습니다. 당장은 작동하겠지만, 미래의 기술 발전, 성능, 유지보수, 그리고 개발자 경험 측면에서 큰 손해를 보게 됩니다. 따라서 현대적인 앱 개발의 표준인 Kotlin과 Swift를 선택하는 것은 선택이 아닌 필수입니다.

2. 실전! Kotlin/Swift 기반 Flutter 프로젝트 생성하기

그렇다면 어떻게 Kotlin과 Swift를 기본 언어로 사용하는 Flutter 프로젝트를 생성할 수 있을까요? 답은 flutter create 명령어에 몇 가지 옵션을 추가하는 것만으로 충분합니다.

기본 명령어와 옵션

터미널 또는 명령 프롬프트를 열고 다음 명령어를 입력해 보세요. app_name 부분은 원하는 프로젝트 이름으로 변경하면 됩니다.

flutter create -i swift -a kotlin your_awesome_app

이 명령어에 포함된 각 옵션의 의미는 다음과 같습니다.

  • -i swift: iOS 플랫폼의 기본 언어를 Swift로 지정합니다. -i--ios-language의 축약형입니다.
  • -a kotlin: Android 플랫폼의 기본 언어를 Kotlin으로 지정합니다. -a--android-language의 축약형입니다.
flutter create command with kotlin and swift options

터미널에서 Kotlin/Swift 옵션을 사용하여 Flutter 프로젝트를 생성하는 모습

생성 결과 확인하기

명령어를 실행한 후, 생성된 프로젝트 폴더의 구조를 살펴보면 기본 설정과의 차이점을 명확하게 확인할 수 있습니다.

Android 플랫폼 확인

VS Code, Android Studio 또는 다른 파일 탐색기에서 프로젝트 폴더를 열고 다음 경로로 이동해 보세요.

your_awesome_app/android/app/src/main/

기본값(Java)으로 생성된 프로젝트는 이 경로 아래에 java 폴더가 있지만, Kotlin으로 생성한 프로젝트는 kotlin 폴더가 생성된 것을 볼 수 있습니다. 메인 액티비티 파일의 위치와 확장자도 다릅니다.

  • Java (기본값): android/app/src/main/java/com/example/app_name/MainActivity.java
  • Kotlin (옵션 적용): android/app/src/main/kotlin/com/example/app_name/MainActivity.kt

MainActivity.kt 파일을 열어보면 간결한 Kotlin 코드로 작성된 것을 확인할 수 있습니다.

package com.example.your_awesome_app

import io.flutter.embedding.android.FlutterActivity

class MainActivity: FlutterActivity() {
}

iOS 플랫폼 확인

iOS의 경우, your_awesome_app/ios/Runner/ 폴더 내부를 살펴보면 차이를 알 수 있습니다.

  • Objective-C (기본값): AppDelegate.hAppDelegate.m 파일이 생성됩니다.
  • Swift (옵션 적용): AppDelegate.swift 파일 하나만 생성됩니다.

AppDelegate.swift 파일의 내용은 다음과 같습니다.

import UIKit
import Flutter

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}

이처럼 간단한 옵션 추가만으로 프로젝트의 네이티브 기반을 최신 기술 스택으로 설정할 수 있습니다. 이는 향후 네이티브 기능 연동이나 유지보수 시점에서 엄청난 생산성 차이를 만들어낼 것입니다.

3. 앱의 고유 식별자 설정: --org 옵션 활용법

앱을 개발하여 구글 플레이 스토어나 애플 앱스토어에 출시하기 위해서는 앱마다 고유한 식별자가 필요합니다. 안드로이드에서는 이를 '패키지 이름(Package Name)' 또는 'Application ID'라고 부르고, iOS에서는 '번들 식별자(Bundle Identifier)'라고 합니다. 이 식별자는 보통 '역순 도메인(reverse domain name)' 형식을 따릅니다. 예를 들어, 여러분의 회사 도메인이 mycompany.com이고 앱 이름이 my_app이라면, 식별자는 com.mycompany.my_app이 됩니다.

flutter create 명령어 실행 시 이 식별자를 미리 지정하지 않으면 기본값인 com.example.app_name으로 설정됩니다. 'example' 도메인은 실제 출시용으로 사용할 수 없으므로 나중에 반드시 수정해야 하는 번거로움이 발생합니다. 이 과정을 처음부터 간단하게 처리할 수 있는 옵션이 바로 --org입니다.

Kotlin/Swift 옵션과 --org 옵션을 함께 사용하여 완벽한 프로젝트를 생성하는 명령어는 다음과 같습니다.

flutter create --org com.mycompany -i swift -a kotlin my_app_name
Command to create flutter project with package name and using kotlin and swift

조직(org) 옵션까지 포함하여 프로젝트를 생성하는 전체 명령어

패키지 이름/번들 식별자 확인하기

--org 옵션이 잘 적용되었는지 확인하는 방법은 다음과 같습니다.

Android (Application ID)

my_app_name/android/app/build.gradle 파일을 열어 defaultConfig 블록을 찾아보세요. applicationId가 우리가 지정한 값으로 설정된 것을 확인할 수 있습니다.

android {
    ...
    defaultConfig {
        // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
        applicationId "com.mycompany.my_app_name" // 이 부분 확인!
        minSdkVersion flutter.minSdkVersion
        targetSdkVersion flutter.targetSdkVersion
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
    }
    ...
}

iOS (Bundle Identifier)

iOS의 번들 식별자는 Xcode에서 확인하는 것이 가장 직관적입니다. 터미널에서 다음 명령어를 실행하여 Xcode로 iOS 프로젝트를 여세요.

open my_app_name/ios/Runner.xcworkspace

Xcode가 열리면 왼쪽 네비게이터에서 최상단에 있는 Runner 프로젝트를 클릭한 후, 중앙 화면에서 TARGETS 아래의 Runner를 선택하고 General 탭을 확인하세요. Identity 섹션에 있는 Bundle Identifiercom.mycompany.myAppName과 같이 올바르게 설정된 것을 볼 수 있습니다.

이처럼 프로젝트 생성 단계에서 단 몇 개의 옵션을 추가하는 것만으로, 나중에 발생할 수 있는 수많은 설정 변경 작업을 예방하고 처음부터 깔끔하고 전문적인 프로젝트 구조를 갖출 수 있습니다.

4. `flutter create` 명령어, 더 깊이 파헤치기

flutter create 명령어는 우리가 살펴본 언어 및 조직 설정 외에도 수많은 유용한 옵션을 제공합니다. 이 옵션들을 알아두면 다양한 상황에 맞춰 최적화된 프로젝트를 생성할 수 있습니다. 터미널에서 flutter create --help를 입력하면 전체 옵션 목록을 볼 수 있습니다. 여기서는 특히 유용한 몇 가지 옵션을 더 소개합니다.

옵션 설명 사용 예시
--description 프로젝트의 pubspec.yaml 파일에 들어갈 설명을 지정합니다. flutter create --description "My awesome new app" my_app
--template 생성할 프로젝트의 템플릿을 지정합니다. (app, package, plugin, skeleton 등) flutter create --template=package my_package
--platforms 프로젝트가 지원할 플랫폼을 지정합니다. 지정하지 않으면 사용 가능한 모든 플랫폼이 포함됩니다. flutter create --platforms=android,ios,web my_app
--[no-]pub 프로젝트 생성 후 자동으로 flutter pub get을 실행할지 여부를 결정합니다. (기본값: 실행) flutter create --no-pub my_app
--[no-]overwrite 이미 존재하는 폴더에 프로젝트를 생성할 때 파일을 덮어쓸지 여부를 결정합니다. flutter create --overwrite .

특히 --template 옵션은 매우 강력합니다. 일반적인 앱을 만들 때는 app (기본값)을 사용하지만, 다른 프로젝트에서 재사용할 Dart 코드를 작성할 때는 package를, 네이티브 코드와 연동되는 기능을 모듈화할 때는 plugin을 선택하여 처음부터 목적에 맞는 구조로 프로젝트를 시작할 수 있습니다. --template=skeleton은 간단한 리스트-상세 화면 구조를 가진 샘플 앱을 생성해주어, 앱 구조 설계에 대한 좋은 참고 자료가 될 수 있습니다.

5. 이미 늦었나요? 기존 Java/Objective-C 프로젝트를 마이그레이션하는 방법

"이 글을 너무 늦게 봤습니다. 이미 Java와 Objective-C로 프로젝트를 한참 진행했는데 어떡하죠?"

걱정하지 마세요. 다소 번거롭지만 기존 프로젝트의 네이티브 언어를 Kotlin과 Swift로 전환할 수 있는 방법이 있습니다. 아쉽게도 Flutter는 이를 위한 자동화된 명령어를 제공하지 않으므로, 각 플랫폼의 개발 도구를 사용하여 수동으로 마이그레이션해야 합니다.

Android: Java에서 Kotlin으로 마이그레이션하기

안드로이드의 경우, Android Studio의 강력한 변환 기능 덕분에 비교적 쉽게 마이그레이션을 진행할 수 있습니다.

  1. Android Studio로 프로젝트 열기: Flutter 프로젝트의 /android 폴더를 Android Studio로 엽니다. (Flutter 프로젝트 전체를 열지 말고, android 폴더만 여는 것이 중요합니다.)
  2. 자바 파일을 코틀린으로 변환: 왼쪽 Project 창에서 app/src/main/java/your/package/name/MainActivity.java 파일을 찾습니다.
  3. 해당 파일을 우클릭하거나, 파일을 연 상태에서 상단 메뉴의 Code -> Convert Java File to Kotlin File을 선택합니다. (단축키: Ctrl+Alt+Shift+K 또는 Cmd+Option+Shift+K)
  4. Kotlin 플러그인 설정: 변환을 시도하면 Android Studio가 프로젝트에 Kotlin이 설정되어 있지 않다며 설정을 제안하는 창을 띄울 수 있습니다. 모든 모듈에 대해 Kotlin을 설정하도록 허용합니다. 이 과정에서 build.gradle 파일이 자동으로 수정됩니다.
  5. 동기화 및 확인: Gradle 동기화가 완료되면 MainActivity.javaMainActivity.kt로 변경되고, 코드도 Kotlin으로 변환된 것을 확인할 수 있습니다.

이 과정을 통해 프로젝트의 주요 액티비티를 Kotlin으로 전환할 수 있습니다. 프로젝트에 다른 자바 파일이 있다면 동일한 방법으로 모두 변환해주는 것이 좋습니다.

iOS: Objective-C에서 Swift로 마이그레이션하기

iOS의 마이그레이션은 안드로이드보다 조금 더 복잡하며 신중한 접근이 필요합니다. 핵심은 Objective-C와 Swift 코드가 공존할 수 있도록 해주는 '브리징 헤더(Bridging Header)'를 생성하는 것입니다.

  1. Xcode로 프로젝트 열기: 터미널에서 open your_app/ios/Runner.xcworkspace를 실행하여 프로젝트를 엽니다.
  2. 새 Swift 파일 추가: Xcode의 Project Navigator에서 Runner 폴더를 우클릭하고 New File...을 선택합니다. 템플릿 선택 창에서 Swift File을 선택하고 다음을 클릭합니다. 파일 이름은 AppDelegate.swift로 지정합니다.
  3. 브리징 헤더 생성: Swift 파일을 추가하는 순간, Xcode는 "Would you like to configure an Objective-C bridging header?"라는 메시지를 표시합니다. 여기서 Create Bridging Header 버튼을 반드시 클릭해야 합니다. 그러면 Runner-Bridging-Header.h라는 파일이 생성됩니다. 이 파일은 Swift 코드에서 기존 Objective-C 코드를, Objective-C 코드에서 새로운 Swift 코드를 참조할 수 있게 해주는 다리 역할을 합니다.
  4. 코드 이전: 기존 AppDelegate.m 파일의 내용을 새로운 AppDelegate.swift 파일로 옮겨옵니다. 문법이 다르므로 단순히 복사-붙여넣기가 아니라, Swift 문법에 맞게 코드를 다시 작성해야 합니다. 보통 Flutter 기본 템플릿의 내용은 위에서 보여드린 Swift 코드 예시와 거의 동일합니다.
  5. 기존 파일 삭제: AppDelegate.swift 작성이 완료되었다면, 더 이상 필요 없는 AppDelegate.h, AppDelegate.m, 그리고 main.m 파일을 프로젝트에서 삭제합니다.
  6. (중요) Info.plist 수정: main.m을 삭제했다면, Info.plist 파일에서 "Main storyboard file base name" (UIMainStoryboardFile) 항목을 찾아 삭제해야 할 수 있습니다. Swift 기반 앱에서는 스토리보드를 사용하지 않기 때문입니다.

이 과정은 프로젝트의 복잡성에 따라 난이도가 달라질 수 있습니다. 중요한 네이티브 코드가 많다면 마이그레이션 전에 반드시 프로젝트 전체를 백업하고, 단계별로 신중하게 진행해야 합니다.

결론: 현명한 첫걸음이 성공적인 프로젝트를 만든다

Flutter 개발의 여정은 flutter create 명령어 한 줄로 시작됩니다. 이때 무심코 엔터 키를 누르는 대신, -i swift, -a kotlin, --org 옵션을 추가하는 작은 습관이 여러분의 프로젝트를 더욱 견고하고, 현대적이며, 미래지향적으로 만들어 줄 것입니다.

Kotlin과 Swift는 단순히 최신 유행이 아닙니다. 각 플랫폼의 제조사인 구글과 애플이 직접 이끌어가는 개발의 표준이자 미래입니다. 이 언어들이 제공하는 안정성, 생산성, 그리고 성능의 이점을 적극적으로 활용함으로써, 우리는 Flutter의 장점을 극대화하고 더 나은 품질의 애플리케이션을 더 효율적으로 만들어낼 수 있습니다. 오늘부터 시작하는 모든 Flutter 프로젝트는 반드시 Kotlin과 Swift 기반 위에서 첫 삽을 뜨시기를 강력히 권장합니다.


0 개의 댓글:

Post a Comment