SlideShare a Scribd company logo
1 of 38
Flutter로 앱 개발 입문하기
양수장
GDG Songdo Organizer (2020~ )
Flutter Songdo Organizer (2022 ~ )
Tech Lead @bluefrog (2020 ~ )
- Android
- Flutter
- Back-end + DevOps
I’m an App Developer.
Bio
https://github.com/yangster-chief
yangsterchief@duck.com
양수장 (Bruce)
본 발표는 Flutter 환경설정 같은 기초적인 내용부터 앱 개발에 필요한 Android, iOS
기초지식을 30분에 걸쳐 다룹니다.
시간 관계상 많은 내용이 생략될 수 있으나, 관련 내용을 추후 찾아보실수 있도록
링크를 첨부하겠습니다.
이 발표로 앱 개발에 많은 도움이 되었으면 좋겠습니다.
Intro
Flutter가 몸에 좋은 이유
Flutter가 몸에 좋은 이유
Flutter Korea
Flutter Seoul (서울, 한국(대한민국)) | Meetup
Flutter Songdo (인천, 한국(대한민국)) | Meetup
Flutter Daegu - 플러터 대구 (대구, 한국(대한민국)) | Meetup
Flutter Forward
Flutter at Google I/O 2022
Flutter Update: Windows
Flutter가 몸에 좋은 이유
Flutter가 몸에 좋은 이유
아니 진짜 이렇게까지하는데
아직도 플러터 안하는
사람은 없겠죠 진짜 이젠
찍먹해야 되는거 아니냐고요
Flutter is …
Flutter is an open source framework by Google
for building beautiful, natively compiled,
multi-platform applications from single codebase.
- Framework
- UI 구성요소 및 위젯
- Engine
- 렌더링 엔진
- Embedder
- 엔진을 구동하기 위한 네이티브 코드
Flutter Architectural Layers
- Flutter 설치 및 환경설정 ( 링크 )
- Android 시뮬레이터 설치 ( 링크 )
- iOS 시뮬레이터 설치 ( 링크 )
- Android Studio IDE 환경설정 ( 링크 )
- Visual Studio Code IDE 환경설정 ( 링크 )
Setting up Development Environment
Flutter Project Overview
...
<dict>
...
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
...
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>sms</string>
<string>tel</string>
<string>mailto</string>
</array>
...
<key>NSCameraUsageDescription</key>
<string>카메라에 접근하도록 허용합니다.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>위치 접근 권한이 필요합니다.</string>
...
</dict>
</plist>
/ios/Runner/Info.plist
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example">
<uses-permission
android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission
android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<queries>
<!-- If your app checks for SMS support -->
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="sms" />
</intent>
...
</queries>
<application
android:label="@string/app_name"
android:name="${applicationName}"
android:icon="@mipmap/launcher_icon">
<activity
android:name=".MainActivity"
android:exported="true"
...
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
...
</activity>
...
</application>
</manifest>
/Android/app/src/main/AndroidManifest.xml
// Configuration settings file format documentation can be found at:
// https://help.apple.com/xcode/#/dev745c5c974
BUNDLE_IDENTIFIER=com.example
FLUTTER_TARGET=lib/src/config/env/env_develop.dart
DISPLAY_NAME=flutter_example
GOOGLE_SERVICE_INFO_PLIST=Develop/GoogleService-Dev-Info.plist
FIREBASE_APP_ID_FILE=firebase_app_id_file_dev.json
/ios/Flutter/Develop.xcconfig
...
android {
...
defaultConfig {
applicationId "com.example"
minSdkVersion 23
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
dimension "build-type"
}
signingConfigs {
release {
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
storePassword keystoreProperties['storePassword']
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
}
}
...
flavorDimensions "build-type"
productFlavors {
...
}
}
flutter {
source '../..'
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}
/Android/app/build.gradle
name: flutter_example
...
environment:
sdk: ">=2.17.3 <3.0.0"
dependencies:
flutter:
sdk: flutter
cupertino_icons: "^1.0.2"
device_preview: "^1.1.0"
...
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: "^2.0.1"
...
flutter:
uses-material-design: true
assets:
- assets/icons/
- assets/placeholder/
- assets/images/
...
/pubspec.yaml
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugins.GeneratedPluginRegistrant
class MainActivity: FlutterActivity() {
private val openIntent: String = "openIntentChannel"
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine)
MethodChannel(flutterEngine.dartExecutor,
openIntent).setMethodCallHandler(
IndentHandler(activity)
)
}
}
/Android/app/src/main/kotlin/MainActivity.kt
import UIKit
import Flutter
import FirebaseCore
@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)
}
private func setupFirebase() {
...
}
}
/ios/Runner/AppDelegate.swift
- Flutter에서는 모든 것이 위젯입니다.
- Stateless Widget & Stateful Widget
- Layout Widget ( 링크 )
- Scaffold Widget ( 링크 )
Flutter Widgets
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
/lib/main.dart
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(widget.title)),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('You have pushed the button this many times:'),
Text('$_counter', style: Theme.of(context).textTheme.headlineMedium),
])),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
));
}
}
/lib/main.dart
- Flutter에서 실행할 수 없는 코드를 네이티브에서 실행
- Method Channel
- Event Channel
Platform Channel
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class _MyHomePageState extends State<MyHomePage> {
static const platform = MethodChannel('samples.flutter.dev/battery');
// Get battery level.
String _batteryLevel = 'Unknown battery level.';
Future<void> _getBatteryLevel() async {
String batteryLevel;
try {
final int result = await platform.invokeMethod('getBatteryLevel');
batteryLevel = 'Battery level at $result % .';
} on PlatformException catch (e) {
batteryLevel = "Failed to get battery level: '${e.message}'.";
}
...
import androidx.annotation.NonNull
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
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 {
// This method is invoked on the main thread.
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()
}
}
}
}
@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)
}
}
Platform Channel
Packages and Plugins (The Boring Flutter Development Show, Ep. 6)
Tips & Best Practices
[Flutter Festival GDG Songdo] GetX, provider, bloc 패턴 비교 분석 - 유병욱
Tips & Best Practices
[Flutter Festival GDG Songdo] Flutter에 Clean Architecture를 얹어보자 - 양수장
Tips & Best Practices
[Flutter Festival GDG Songdo] Flutter 상용화 앱 프로젝트 적용기 - 손민재
Tips & Best Practices
DevFest Songdo 2022 - Flutter Theme 디자이너와 호감작하기
Tips & Best Practices
Github Actions를 활용한 Flutter 배포 자동화하기 - 양수장(GDG Songdo) I 모두콘 2022
Tips & Best Practices
Flutter로 앱, 스토어 정보, 스크린샷 모두를 90개 언어로 자동 번역할 수 있다? - 이준규(GDG Songdo) I
모두콘 2022
Tips & Best Practices
Flutter 앱에서 머신러닝 활용 방법 - 박제창(Flutter Seoul) I 모두콘 2022
Tips & Best Practices
Flutter, 어떻게 해야 더 잘 쓸까? - 유병욱(Flutter Seoul) I 모두콘 2022
THANK YOU!
https://github.com/yangster-chief
yangsterchief@duck.com
양수장 (Bruce)

More Related Content

Similar to Flutter Forward EXTENDED - Flutter로 앱 개발 입문하기

How to code to code less
How to code to code lessHow to code to code less
How to code to code lessAnton Novikau
 
fb-researchの舞台裏No.2~技術編~(HatchUp主催 渋谷Facebookアプリ勉強会)
fb-researchの舞台裏No.2~技術編~(HatchUp主催 渋谷Facebookアプリ勉強会)fb-researchの舞台裏No.2~技術編~(HatchUp主催 渋谷Facebookアプリ勉強会)
fb-researchの舞台裏No.2~技術編~(HatchUp主催 渋谷Facebookアプリ勉強会)modeelf
 
Android Best Practices
Android Best PracticesAndroid Best Practices
Android Best PracticesYekmer Simsek
 
A gently introduction to AngularJS
A gently introduction to AngularJSA gently introduction to AngularJS
A gently introduction to AngularJSGregor Woiwode
 
Android Survival Guide - Two years of software development
Android Survival Guide - Two years of software developmentAndroid Survival Guide - Two years of software development
Android Survival Guide - Two years of software developmentAlfredo Morresi
 
What's New In Laravel 5
What's New In Laravel 5What's New In Laravel 5
What's New In Laravel 5Darren Craig
 
Developing cross platform apps in Flutter (Android, iOS, and Web)
Developing cross platform apps in Flutter (Android, iOS, and Web)Developing cross platform apps in Flutter (Android, iOS, and Web)
Developing cross platform apps in Flutter (Android, iOS, and Web)Priyanka Tyagi
 
Ane for 9ria_cn
Ane for 9ria_cnAne for 9ria_cn
Ane for 9ria_cnsonicxs
 
Non Conventional Android Programming (English)
Non Conventional Android Programming (English)Non Conventional Android Programming (English)
Non Conventional Android Programming (English)Davide Cerbo
 
Non Conventional Android Programming En
Non Conventional Android Programming EnNon Conventional Android Programming En
Non Conventional Android Programming Enguest9bcef2f
 
Introduction to Zend framework
Introduction to Zend framework Introduction to Zend framework
Introduction to Zend framework Matteo Magni
 
Jeff English: Demystifying Module Development - How to Extend Titanium
Jeff English: Demystifying Module Development - How to Extend TitaniumJeff English: Demystifying Module Development - How to Extend Titanium
Jeff English: Demystifying Module Development - How to Extend TitaniumAxway Appcelerator
 
AIR2.5 Hands On - Flash on the Beach 2010
AIR2.5 Hands On - Flash on the Beach 2010AIR2.5 Hands On - Flash on the Beach 2010
AIR2.5 Hands On - Flash on the Beach 2010Mark Doherty
 
New Symfony Tips & Tricks (SymfonyCon Paris 2015)
New Symfony Tips & Tricks (SymfonyCon Paris 2015)New Symfony Tips & Tricks (SymfonyCon Paris 2015)
New Symfony Tips & Tricks (SymfonyCon Paris 2015)Javier Eguiluz
 
Android training in mumbai
Android training in mumbaiAndroid training in mumbai
Android training in mumbaiCIBIL
 

Similar to Flutter Forward EXTENDED - Flutter로 앱 개발 입문하기 (20)

How to code to code less
How to code to code lessHow to code to code less
How to code to code less
 
Flutter Intro
Flutter IntroFlutter Intro
Flutter Intro
 
fb-researchの舞台裏No.2~技術編~(HatchUp主催 渋谷Facebookアプリ勉強会)
fb-researchの舞台裏No.2~技術編~(HatchUp主催 渋谷Facebookアプリ勉強会)fb-researchの舞台裏No.2~技術編~(HatchUp主催 渋谷Facebookアプリ勉強会)
fb-researchの舞台裏No.2~技術編~(HatchUp主催 渋谷Facebookアプリ勉強会)
 
Android Best Practices
Android Best PracticesAndroid Best Practices
Android Best Practices
 
A gently introduction to AngularJS
A gently introduction to AngularJSA gently introduction to AngularJS
A gently introduction to AngularJS
 
Android Survival Guide - Two years of software development
Android Survival Guide - Two years of software developmentAndroid Survival Guide - Two years of software development
Android Survival Guide - Two years of software development
 
What's New In Laravel 5
What's New In Laravel 5What's New In Laravel 5
What's New In Laravel 5
 
Developing cross platform apps in Flutter (Android, iOS, and Web)
Developing cross platform apps in Flutter (Android, iOS, and Web)Developing cross platform apps in Flutter (Android, iOS, and Web)
Developing cross platform apps in Flutter (Android, iOS, and Web)
 
Ane for 9ria_cn
Ane for 9ria_cnAne for 9ria_cn
Ane for 9ria_cn
 
Ruby conf2012
Ruby conf2012Ruby conf2012
Ruby conf2012
 
Non Conventional Android Programming (English)
Non Conventional Android Programming (English)Non Conventional Android Programming (English)
Non Conventional Android Programming (English)
 
Non Conventional Android Programming En
Non Conventional Android Programming EnNon Conventional Android Programming En
Non Conventional Android Programming En
 
Introduction to Zend framework
Introduction to Zend framework Introduction to Zend framework
Introduction to Zend framework
 
從零開始學 Android
從零開始學 Android從零開始學 Android
從零開始學 Android
 
Griffon Presentation
Griffon PresentationGriffon Presentation
Griffon Presentation
 
Jeff English: Demystifying Module Development - How to Extend Titanium
Jeff English: Demystifying Module Development - How to Extend TitaniumJeff English: Demystifying Module Development - How to Extend Titanium
Jeff English: Demystifying Module Development - How to Extend Titanium
 
AIR2.5 Hands On - Flash on the Beach 2010
AIR2.5 Hands On - Flash on the Beach 2010AIR2.5 Hands On - Flash on the Beach 2010
AIR2.5 Hands On - Flash on the Beach 2010
 
Introduction to flutter
Introduction to flutterIntroduction to flutter
Introduction to flutter
 
New Symfony Tips & Tricks (SymfonyCon Paris 2015)
New Symfony Tips & Tricks (SymfonyCon Paris 2015)New Symfony Tips & Tricks (SymfonyCon Paris 2015)
New Symfony Tips & Tricks (SymfonyCon Paris 2015)
 
Android training in mumbai
Android training in mumbaiAndroid training in mumbai
Android training in mumbai
 

Recently uploaded

Model Call Girl in Shalimar Bagh Delhi reach out to us at 🔝8264348440🔝
Model Call Girl in Shalimar Bagh Delhi reach out to us at 🔝8264348440🔝Model Call Girl in Shalimar Bagh Delhi reach out to us at 🔝8264348440🔝
Model Call Girl in Shalimar Bagh Delhi reach out to us at 🔝8264348440🔝soniya singh
 
CALL ON ➥8923113531 🔝Call Girls Gomti Nagar Lucknow best Night Fun service
CALL ON ➥8923113531 🔝Call Girls Gomti Nagar Lucknow best Night Fun serviceCALL ON ➥8923113531 🔝Call Girls Gomti Nagar Lucknow best Night Fun service
CALL ON ➥8923113531 🔝Call Girls Gomti Nagar Lucknow best Night Fun serviceanilsa9823
 
哪里有卖的《俄亥俄大学学历证书+俄亥俄大学文凭证书+俄亥俄大学学位证书》Q微信741003700《俄亥俄大学学位证书复制》办理俄亥俄大学毕业证成绩单|购买...
哪里有卖的《俄亥俄大学学历证书+俄亥俄大学文凭证书+俄亥俄大学学位证书》Q微信741003700《俄亥俄大学学位证书复制》办理俄亥俄大学毕业证成绩单|购买...哪里有卖的《俄亥俄大学学历证书+俄亥俄大学文凭证书+俄亥俄大学学位证书》Q微信741003700《俄亥俄大学学位证书复制》办理俄亥俄大学毕业证成绩单|购买...
哪里有卖的《俄亥俄大学学历证书+俄亥俄大学文凭证书+俄亥俄大学学位证书》Q微信741003700《俄亥俄大学学位证书复制》办理俄亥俄大学毕业证成绩单|购买...wyqazy
 
Call US Pooja 9892124323 ✓Call Girls In Mira Road ( Mumbai ) secure service,
Call US Pooja 9892124323 ✓Call Girls In Mira Road ( Mumbai ) secure service,Call US Pooja 9892124323 ✓Call Girls In Mira Road ( Mumbai ) secure service,
Call US Pooja 9892124323 ✓Call Girls In Mira Road ( Mumbai ) secure service,Pooja Nehwal
 
Powerful Love Spells in Arkansas, AR (310) 882-6330 Bring Back Lost Lover
Powerful Love Spells in Arkansas, AR (310) 882-6330 Bring Back Lost LoverPowerful Love Spells in Arkansas, AR (310) 882-6330 Bring Back Lost Lover
Powerful Love Spells in Arkansas, AR (310) 882-6330 Bring Back Lost LoverPsychicRuben LoveSpells
 
Chandigarh Call Girls Service ❤️🍑 9115573837 👄🫦Independent Escort Service Cha...
Chandigarh Call Girls Service ❤️🍑 9115573837 👄🫦Independent Escort Service Cha...Chandigarh Call Girls Service ❤️🍑 9115573837 👄🫦Independent Escort Service Cha...
Chandigarh Call Girls Service ❤️🍑 9115573837 👄🫦Independent Escort Service Cha...Niamh verma
 
9892124323 | Book Call Girls in Juhu and escort services 24x7
9892124323 | Book Call Girls in Juhu and escort services 24x79892124323 | Book Call Girls in Juhu and escort services 24x7
9892124323 | Book Call Girls in Juhu and escort services 24x7Pooja Nehwal
 
CALL ON ➥8923113531 🔝Call Girls Saharaganj Lucknow best sexual service
CALL ON ➥8923113531 🔝Call Girls Saharaganj Lucknow best sexual serviceCALL ON ➥8923113531 🔝Call Girls Saharaganj Lucknow best sexual service
CALL ON ➥8923113531 🔝Call Girls Saharaganj Lucknow best sexual serviceanilsa9823
 
Night 7k to 12k Top Call Girls Ahmedabad 👉 BOOK NOW 8617697112 👈 ♀️ night gir...
Night 7k to 12k Top Call Girls Ahmedabad 👉 BOOK NOW 8617697112 👈 ♀️ night gir...Night 7k to 12k Top Call Girls Ahmedabad 👉 BOOK NOW 8617697112 👈 ♀️ night gir...
Night 7k to 12k Top Call Girls Ahmedabad 👉 BOOK NOW 8617697112 👈 ♀️ night gir...Call girls in Ahmedabad High profile
 

Recently uploaded (9)

Model Call Girl in Shalimar Bagh Delhi reach out to us at 🔝8264348440🔝
Model Call Girl in Shalimar Bagh Delhi reach out to us at 🔝8264348440🔝Model Call Girl in Shalimar Bagh Delhi reach out to us at 🔝8264348440🔝
Model Call Girl in Shalimar Bagh Delhi reach out to us at 🔝8264348440🔝
 
CALL ON ➥8923113531 🔝Call Girls Gomti Nagar Lucknow best Night Fun service
CALL ON ➥8923113531 🔝Call Girls Gomti Nagar Lucknow best Night Fun serviceCALL ON ➥8923113531 🔝Call Girls Gomti Nagar Lucknow best Night Fun service
CALL ON ➥8923113531 🔝Call Girls Gomti Nagar Lucknow best Night Fun service
 
哪里有卖的《俄亥俄大学学历证书+俄亥俄大学文凭证书+俄亥俄大学学位证书》Q微信741003700《俄亥俄大学学位证书复制》办理俄亥俄大学毕业证成绩单|购买...
哪里有卖的《俄亥俄大学学历证书+俄亥俄大学文凭证书+俄亥俄大学学位证书》Q微信741003700《俄亥俄大学学位证书复制》办理俄亥俄大学毕业证成绩单|购买...哪里有卖的《俄亥俄大学学历证书+俄亥俄大学文凭证书+俄亥俄大学学位证书》Q微信741003700《俄亥俄大学学位证书复制》办理俄亥俄大学毕业证成绩单|购买...
哪里有卖的《俄亥俄大学学历证书+俄亥俄大学文凭证书+俄亥俄大学学位证书》Q微信741003700《俄亥俄大学学位证书复制》办理俄亥俄大学毕业证成绩单|购买...
 
Call US Pooja 9892124323 ✓Call Girls In Mira Road ( Mumbai ) secure service,
Call US Pooja 9892124323 ✓Call Girls In Mira Road ( Mumbai ) secure service,Call US Pooja 9892124323 ✓Call Girls In Mira Road ( Mumbai ) secure service,
Call US Pooja 9892124323 ✓Call Girls In Mira Road ( Mumbai ) secure service,
 
Powerful Love Spells in Arkansas, AR (310) 882-6330 Bring Back Lost Lover
Powerful Love Spells in Arkansas, AR (310) 882-6330 Bring Back Lost LoverPowerful Love Spells in Arkansas, AR (310) 882-6330 Bring Back Lost Lover
Powerful Love Spells in Arkansas, AR (310) 882-6330 Bring Back Lost Lover
 
Chandigarh Call Girls Service ❤️🍑 9115573837 👄🫦Independent Escort Service Cha...
Chandigarh Call Girls Service ❤️🍑 9115573837 👄🫦Independent Escort Service Cha...Chandigarh Call Girls Service ❤️🍑 9115573837 👄🫦Independent Escort Service Cha...
Chandigarh Call Girls Service ❤️🍑 9115573837 👄🫦Independent Escort Service Cha...
 
9892124323 | Book Call Girls in Juhu and escort services 24x7
9892124323 | Book Call Girls in Juhu and escort services 24x79892124323 | Book Call Girls in Juhu and escort services 24x7
9892124323 | Book Call Girls in Juhu and escort services 24x7
 
CALL ON ➥8923113531 🔝Call Girls Saharaganj Lucknow best sexual service
CALL ON ➥8923113531 🔝Call Girls Saharaganj Lucknow best sexual serviceCALL ON ➥8923113531 🔝Call Girls Saharaganj Lucknow best sexual service
CALL ON ➥8923113531 🔝Call Girls Saharaganj Lucknow best sexual service
 
Night 7k to 12k Top Call Girls Ahmedabad 👉 BOOK NOW 8617697112 👈 ♀️ night gir...
Night 7k to 12k Top Call Girls Ahmedabad 👉 BOOK NOW 8617697112 👈 ♀️ night gir...Night 7k to 12k Top Call Girls Ahmedabad 👉 BOOK NOW 8617697112 👈 ♀️ night gir...
Night 7k to 12k Top Call Girls Ahmedabad 👉 BOOK NOW 8617697112 👈 ♀️ night gir...
 

Flutter Forward EXTENDED - Flutter로 앱 개발 입문하기

  • 1. Flutter로 앱 개발 입문하기 양수장
  • 2. GDG Songdo Organizer (2020~ ) Flutter Songdo Organizer (2022 ~ ) Tech Lead @bluefrog (2020 ~ ) - Android - Flutter - Back-end + DevOps I’m an App Developer. Bio https://github.com/yangster-chief yangsterchief@duck.com 양수장 (Bruce)
  • 3. 본 발표는 Flutter 환경설정 같은 기초적인 내용부터 앱 개발에 필요한 Android, iOS 기초지식을 30분에 걸쳐 다룹니다. 시간 관계상 많은 내용이 생략될 수 있으나, 관련 내용을 추후 찾아보실수 있도록 링크를 첨부하겠습니다. 이 발표로 앱 개발에 많은 도움이 되었으면 좋겠습니다. Intro
  • 6.
  • 7. Flutter Korea Flutter Seoul (서울, 한국(대한민국)) | Meetup Flutter Songdo (인천, 한국(대한민국)) | Meetup Flutter Daegu - 플러터 대구 (대구, 한국(대한민국)) | Meetup
  • 8. Flutter Forward Flutter at Google I/O 2022 Flutter Update: Windows Flutter가 몸에 좋은 이유
  • 10. 아니 진짜 이렇게까지하는데 아직도 플러터 안하는 사람은 없겠죠 진짜 이젠 찍먹해야 되는거 아니냐고요
  • 11. Flutter is … Flutter is an open source framework by Google for building beautiful, natively compiled, multi-platform applications from single codebase.
  • 12. - Framework - UI 구성요소 및 위젯 - Engine - 렌더링 엔진 - Embedder - 엔진을 구동하기 위한 네이티브 코드 Flutter Architectural Layers
  • 13. - Flutter 설치 및 환경설정 ( 링크 ) - Android 시뮬레이터 설치 ( 링크 ) - iOS 시뮬레이터 설치 ( 링크 ) - Android Studio IDE 환경설정 ( 링크 ) - Visual Studio Code IDE 환경설정 ( 링크 ) Setting up Development Environment
  • 16. <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example"> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <queries> <!-- If your app checks for SMS support --> <intent> <action android:name="android.intent.action.VIEW" /> <data android:scheme="sms" /> </intent> ... </queries> <application android:label="@string/app_name" android:name="${applicationName}" android:icon="@mipmap/launcher_icon"> <activity android:name=".MainActivity" android:exported="true" ... android:windowSoftInputMode="adjustResize"> <!-- Specifies an Android theme to apply to this Activity as soon as the Android process has started. This theme is visible to the user while the Flutter UI initializes. After that, this theme continues to determine the Window background behind the Flutter UI. --> ... </activity> ... </application> </manifest> /Android/app/src/main/AndroidManifest.xml
  • 17. // Configuration settings file format documentation can be found at: // https://help.apple.com/xcode/#/dev745c5c974 BUNDLE_IDENTIFIER=com.example FLUTTER_TARGET=lib/src/config/env/env_develop.dart DISPLAY_NAME=flutter_example GOOGLE_SERVICE_INFO_PLIST=Develop/GoogleService-Dev-Info.plist FIREBASE_APP_ID_FILE=firebase_app_id_file_dev.json /ios/Flutter/Develop.xcconfig
  • 18. ... android { ... defaultConfig { applicationId "com.example" minSdkVersion 23 targetSdkVersion flutter.targetSdkVersion versionCode flutterVersionCode.toInteger() versionName flutterVersionName dimension "build-type" } signingConfigs { release { storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null storePassword keystoreProperties['storePassword'] keyAlias keystoreProperties['keyAlias'] keyPassword keystoreProperties['keyPassword'] } } ... flavorDimensions "build-type" productFlavors { ... } } flutter { source '../..' } dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" } /Android/app/build.gradle
  • 19. name: flutter_example ... environment: sdk: ">=2.17.3 <3.0.0" dependencies: flutter: sdk: flutter cupertino_icons: "^1.0.2" device_preview: "^1.1.0" ... dev_dependencies: flutter_test: sdk: flutter flutter_lints: "^2.0.1" ... flutter: uses-material-design: true assets: - assets/icons/ - assets/placeholder/ - assets/images/ ... /pubspec.yaml
  • 20. import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugin.common.MethodChannel import io.flutter.plugins.GeneratedPluginRegistrant class MainActivity: FlutterActivity() { private val openIntent: String = "openIntentChannel" override fun configureFlutterEngine(flutterEngine: FlutterEngine) { GeneratedPluginRegistrant.registerWith(flutterEngine) MethodChannel(flutterEngine.dartExecutor, openIntent).setMethodCallHandler( IndentHandler(activity) ) } } /Android/app/src/main/kotlin/MainActivity.kt
  • 21. import UIKit import Flutter import FirebaseCore @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) } private func setupFirebase() { ... } } /ios/Runner/AppDelegate.swift
  • 22. - Flutter에서는 모든 것이 위젯입니다. - Stateless Widget & Stateful Widget - Layout Widget ( 링크 ) - Scaffold Widget ( 링크 ) Flutter Widgets
  • 23. import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: const MyHomePage(title: 'Flutter Demo Home Page'), ); } } /lib/main.dart
  • 24. class MyHomePage extends StatefulWidget { const MyHomePage({super.key, required this.title}); final String title; @override State<MyHomePage> createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { int _counter = 0; void _incrementCounter() { setState(() { _counter++; }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text(widget.title)), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ const Text('You have pushed the button this many times:'), Text('$_counter', style: Theme.of(context).textTheme.headlineMedium), ])), floatingActionButton: FloatingActionButton( onPressed: _incrementCounter, tooltip: 'Increment', child: const Icon(Icons.add), )); } } /lib/main.dart
  • 25. - Flutter에서 실행할 수 없는 코드를 네이티브에서 실행 - Method Channel - Event Channel Platform Channel
  • 26. import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; class _MyHomePageState extends State<MyHomePage> { static const platform = MethodChannel('samples.flutter.dev/battery'); // Get battery level. String _batteryLevel = 'Unknown battery level.'; Future<void> _getBatteryLevel() async { String batteryLevel; try { final int result = await platform.invokeMethod('getBatteryLevel'); batteryLevel = 'Battery level at $result % .'; } on PlatformException catch (e) { batteryLevel = "Failed to get battery level: '${e.message}'."; } ...
  • 27. import androidx.annotation.NonNull import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugin.common.MethodChannel 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 { // This method is invoked on the main thread. 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() } } } }
  • 28. @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) } }
  • 29. Platform Channel Packages and Plugins (The Boring Flutter Development Show, Ep. 6)
  • 30. Tips & Best Practices [Flutter Festival GDG Songdo] GetX, provider, bloc 패턴 비교 분석 - 유병욱
  • 31. Tips & Best Practices [Flutter Festival GDG Songdo] Flutter에 Clean Architecture를 얹어보자 - 양수장
  • 32. Tips & Best Practices [Flutter Festival GDG Songdo] Flutter 상용화 앱 프로젝트 적용기 - 손민재
  • 33. Tips & Best Practices DevFest Songdo 2022 - Flutter Theme 디자이너와 호감작하기
  • 34. Tips & Best Practices Github Actions를 활용한 Flutter 배포 자동화하기 - 양수장(GDG Songdo) I 모두콘 2022
  • 35. Tips & Best Practices Flutter로 앱, 스토어 정보, 스크린샷 모두를 90개 언어로 자동 번역할 수 있다? - 이준규(GDG Songdo) I 모두콘 2022
  • 36. Tips & Best Practices Flutter 앱에서 머신러닝 활용 방법 - 박제창(Flutter Seoul) I 모두콘 2022
  • 37. Tips & Best Practices Flutter, 어떻게 해야 더 잘 쓸까? - 유병욱(Flutter Seoul) I 모두콘 2022