Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Flutterでstaging/production環境を切替える
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
FURUKI Eiji
April 18, 2018
Programming
4.2k
3
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Flutterでstaging/production環境を切替える
Flutter Meetup Tokyo #1 のLT資料です
FURUKI Eiji
April 18, 2018
Other Decks in Programming
See All in Programming
FreeBSDでZabbixを動かす
kenkino
0
340
iOSDC2026登壇資料.pdf
riofujimon
0
200
SONY CISC-NEWS NWS-1750 + NWB-225 フレームバッファの NetBSD/news68k ドライバ実装 / OSC2026Hiroshima
tsutsui
0
160
Vue Fes Japan 2026 タイムテーブル徹底解説
448jp
1
580
Go × SIMDで高速化するベクトル検索 ~ルーフラインモデルでSIMDが効く境界を探れ! ~
po3rin
1
5.6k
巨大モノリシックアプリ モダン化大作戦
ktcryomm
1
1.2k
iOSDC Japan 2026 - Swiftで作って学ぼう!データベース自作入門
kaseken
2
420
仕様駆動開発による爆速プロダクト開発 / Bakusoku Spec Driven Development
kobakei
0
150
Everything will be SERVERLESS — 信じて運用した10年の経験値 / Everything Will be Serverless — Lessons Learned from 10 Years of Operational Experience
seike460
PRO
1
650
Streamlitで実現する自然言語データアプリ開発
ayumu_yamaguchi
1
330
手動確認はもう限界 〜XCUITestでCustom URL Schemeの遷移を起動種別ごとに自動テストする〜 / Testing Custom URL Schemes with XCUITest
otouto
0
370
更なる可用性を求めて、5年間運用したKotlinのアプリケーションをGoでリプレイスする話
ken_tunc
0
420
Featured
See All Featured
The AI Revolution Will Not Be Monopolized: How open-source beats economies of scale, even for LLMs
inesmontani
PRO
3
3.7k
Ethics towards AI in product and experience design
skipperchong
2
400
Technical Leadership for Architectural Decision Making
baasie
3
590
Bioeconomy Workshop: Dr. Julius Ecuru, Opportunities for a Bioeconomy in West Africa
akademiya2063
PRO
1
380
Heart Work Chapter 1 - Part 1
lfama
PRO
10
36k
技術選定の審美眼(2025年版) / Understanding the Spiral of Technologies 2025 edition
twada
PRO
120
120k
Art, The Web, and Tiny UX
lynnandtonic
304
22k
Testing 201, or: Great Expectations
jmmastey
46
8.3k
The World Runs on Bad Software
bkeepers
PRO
72
12k
Stop Working from a Prison Cell
hatefulcrawdad
274
21k
Optimizing for Happiness
mojombo
378
71k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.9k
Transcript
Flavor Of Flutter Flutter Meetup Tokyo #1 FlutterͰstaging/productionڥͷସ
ࣗݾհ • @fullfool / FURUKI Eiji • iOS / Android
ΤϯδχΞ • ϞΠגࣜձࣾ • Flutterྺɹࡢ8݄த०͔Β • ࠷ۙFlutter৮ͬͯͳ͍
agenda
agenda • Flavorͱ • DartͰFlavorΛऔಘ͢Δ • AndroidStudio, XcodeͰFlavorΛࢦఆ͢Δ • PlatformຖͷFlavorͷఆٛ
• Firebase, FastlaneͱFlavor
agenda • Flavorͱ • DartͰFlavorΛऔಘ͢Δ • AndroidStudio, XcodeͰFlavorΛࢦఆ͢Δ • PlatformຖͷFlavorͷఆٛ
• Firebase, FastlaneͱFlavor
Flavorͱʁ
Flavorͱʁ • ҰͭͷϓϩδΣΫτͰdemo൛ʗfull൛ɺࣾ ςετ༻ʗετΞ༻ͳͲͷෳͷڥΛఆٛ ͢ΔΈ • AndroidͰ ProductFlavor • iOSͰ
Scheme
FlavorΛࢦఆͯ͠ΞϓϦΛ࣮ߦ $ flutter run --flavor staging $ flutter run --flavor
production `--flavor` ΦϓγϣϯͰFlavorΛࢦఆ͢Δ flavorʹࢦఆ͢ΔPlatformଆ(Android/iOS)ͰઃఆࡁΈͷ͕ࢦఆͰ ͖·͢ ͦΕͧΕͷPlatformͰͷFlavorͷఆٛεϥΠυඌʹ
DartͰFlavorΛऔಘ͢Δํ๏
DartͰFlavorΛऔಘ void main() { const String flavor = const String.fromEnvironment('flavor');
configure(flavor); runApp(new MyApp()); } const bool isReleaseMode = const bool.fromEnvironment('dart.vm.product'); ىಈ࣌ʹFlavorΛऔಘ͍ͨ͠ releaseϞʔυΛऔಘ͢Δ࣌
DartͰFlavorΛऔಘ void main() { const String flavor = const String.fromEnvironment('flavor');
configure(flavor); runApp(new MyApp()); } const bool isReleaseMode = const bool.fromEnvironment('dart.vm.product'); ىಈ࣌ʹFlavorΛऔಘ͍ͨ͠ releaseϞʔυΛऔಘ͢Δ࣌
DartͰFlavorຖͷॲཧΛߦ͏ ̎ͭͷํ๏ • Flavor औಘ༻ͷ MethodChannel Λ࡞Δ • Flavor ຖʹ
Dart Entry-Point Λมߋ͢Δ
MethodChannelͱ • Platform(Obj-C/Java)Ͱఆٛͨؔ͠Λඇಉظ ݺͼग़͢͠ΔͨΊͷΫϥε • ىಈ࣌ʹPlatformଆͰMethodChannelΛొ • DartଆͰMethodChannelΛ༻͢Δ͜ͱͰɺ PlatformͰͷॲཧ݁ՌΛऔಘͰ͖Δ
MethodChannelͷొ(Android) new MethodChannel(getFlutterView(), "flavor") .setMethodCallHandler(new MethodChannel.MethodCallHandler() { @Override public void
onMethodCall(MethodCall methodCall, MethodChannel.Result result) { result.success(BuildConfig.FLAVOR); } }); ΞϓϦىಈ࣌ʹMethodChannelΛొ͢Δ ʢ͜ͷchannelFlavorऔಘઐ༻ͷͨΊMethodCallࢀর͠ͳ͍ʣ
MethodChannelͷొ(Android) new MethodChannel(getFlutterView(), "flavor") .setMethodCallHandler(new MethodChannel.MethodCallHandler() { @Override public void
onMethodCall(MethodCall methodCall, MethodChannel.Result result) { result.success(BuildConfig.FLAVOR); } }); ProductFlavor(BuildConfig.FLAVOR)Λฦ͢
MethodChannelͷొ(iOS) FlutterViewController* controller = (FlutterViewController*)self.window.rootViewController; FlutterMethodChannel* flavorChannel = [FlutterMethodChannel methodChannelWithName:@"flavor"
binaryMessenger:controller]; [flavorChannel setMethodCallHandler:^(FlutterMethodCall *call, FlutterResult result) { NSString* flavor = (NSString*)[[NSBundle mainBundle] .infoDictionary valueForKey:@"Flavor"]; result(flavor); }]; Bundleʹఆٛ͢ΔSchemeʹؔ࿈͚ͨFlavorΛฦ͢
MethodChannelͰFlavorऔಘ void main() { _run(); } Future _run() async {
var flavor = await MethodChannel('flavor').invokeMethod('getFlavor'); configure(flavor); runApp(new MyApp()); } main.dartͰFlavorΛऔಘͯ͠ɺઃఆΛॳظԽ
Dart Entry-Pointͱ • ҙͷdartϑΝΠϧΛࢦఆ͢Δ • ࢦఆͨ͠dartϑΝΠϧͷmain()͔ؔΒ࢝·Δ $ flutter run --flavor
staging -t lib/main_staging.dart
FlavorຖͷEntry-Point • main.dart "production"ͰઃఆॳظԽ void main() { configure("staging"); runApp(new MyApp());
} void main() { configure("production"); runApp(new MyApp()); } • main_staging.dart "staging"ͰઃఆॳظԽ
FlavorΛѻ͏߹ MethodCallͱEntry-Point Ͳͬͪ͑ʁ
MethodCallͱEntry-Point • MethodChannel • Obj-C, Java(Swift, Kotlin)༻ҙ͢Δ • Pluginͱಉ͡ͳͷͰɺ׳Ε͓ͯ͘ͱPlugin࡞Γ͍͢ •
Entry-Point • Dart͚ͩͰ݁͢ΔͷͰ͓खܰ • XcodeͰͷڥସϛε͋Γͦ͏
࣮ߦ࣌ͷFlavorࢦఆ
࣮ߦ࣌ͷFlavorࢦఆ(CLI) • CLIͰ࣮ߦ͢Δ߹ɺ͜ͷίϚϯυ • AndroidStudio, XcodeͰ࣮ߦ͢Δ࣌ʹFlavor(Entry-Point)Λࢦఆ͢ Δʹʁ $ flutter run
--flavor staging -t lib/main_staging.dart
࣮ߦ࣌ͷFlavorࢦఆ (AndroidStudio Flutter Plugin) Menu > Run > Edit Configurations...
ʹͯ "Build flavor"ͱ "Dart entrypoint" Λࢦఆ͢Δ
࣮ߦ࣌ͷFlavorࢦఆ(Xcode) • Xcode͔ΒFlutterΞϓϦΛ࣮ߦ͢Δ߹ʹ `build` ίϚϯυͰม ߋͰ͖Δ • ίϚϯυ࣮ߦޙɺXcodeͰSchemeΛมߋ͢Δ $ flutter
build ios --flavor staging -t lib/main_staging.dart
·ͱΊ
·ͱΊ • DartͰFlavorΛѻ͏ʹɺ̎ͭͷํ๏͕͋Δ • XcodeͰ࣮ߦ͢Δ࣌ɺFastlaneCIͰ `flutter build` ͰڥΛସ͑Δ͜ͱʹཹҙ͢ ΔɻͦΕҎ֎ࠓ·ͰͦΕͧΕͷPlatformͰ ͍ͬͯͨํ๏Ͱɻ
PlatformͰͷFlavorఆٛ
PlatformͰͷFlavorఆٛ(Android) android { ... defaultConfig {...} buildTypes {...} flavorDimensions "api"
productFlavors { staging { dimension "api" applicationIdSuffix ".staging" manifestPlaceholders = [appName: "Casmo dev"] } production { dimension "api" manifestPlaceholders = [appName: "Casmo"] } } } ௨ৗͷAndroidΞϓϦͷProductFlavorsͱಉ༷
PlatformͰͷFlavorఆٛ(iOS) • SchemeΛઃఆ • ConfigurationΛઃఆ • Build SettingsͷPRODUCT_BUNDLE_IDENTIFIERΛมߋ • Build
SettingsͷUser-Defined ValueΛՃ • info.plistʹFlavorͷkey-valueΛՃ
PlatformͰͷFlavorఆٛ(iOS) • SchemeΛઃఆ
PlatformͰͷFlavorఆٛ(iOS) • ConfigurationΛઃఆ
PlatformͰͷFlavorఆٛ(iOS) • Build SettingsͷPRODUCT_BUNDLE_IDENTIFIERΛมߋ
PlatformͰͷFlavorఆٛ(iOS) • Build SettingsͷUser-Defined ValueΛՃ ($PRODUCT_FLAVOR)
PlatformͰͷFlavorఆٛ(iOS) • info.plistʹFlavorͷkey-value ($Flavor ) ΛՃ
Firebaseͷସ
Firebaseͷସ(Android) src/$flavor ຖʹ google-services.json Λஔ
Firebaseͷସ(iOS) GoogleService-Info-$flavor.plist Λىಈ࣌ʹಡ Έସ͑Δ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSString *flavor = (NSString*)[[NSBundle mainBundle] .infoDictionary valueForKey:@"Flavor"]; NSString *firebaseInfo = [NSString stringWithFormat: @"GoogleService-Info-%@", flavor]; NSString *path = [[NSBundle mainBundle] pathForResource:firebaseInfo ofType:@"plist"]; FIROptions* firOptions = [[FIROptions alloc] initWithContentsOfFile:path]; if (firOptions == nil) { assert("Couldn't load config file"); } [FIRApp configureWithOptions:firOptions];
Fastlane+Beta
Fastlane+Beta(Android) lane :beta do |options| flavor = (options[:prod] ? "production"
: "staging") entry_dart = (options[:prod] ? "lib/main.dart" : "lib/main_staging.dart") sh("cd ../.. && flutter build apk --flavor #{flavor} -t #{entry_dart} --release && cd -") changelog_from_git_commits # upload to Beta crashlytics( ... ) slack( ... ) end flutter buildͰڥΛΓସ͑ͯϏϧυ͢Δ
Fastlane+Beta(iOS) lane :beta do |options| scheme = (options[:prod] ? "Production"
: "Staging") flavor = (options[:prod] ? "production" : "staging") entry_dart = (options[:prod] ? "lib/main.dart" : "lib/main_staging.dart") sh("cd ../.. && flutter build ios --flavor #{flavor} -t #{entry_dart} --release && cd -") gym( scheme: scheme, configuration: "Release #{scheme}", export_method: "ad-hoc" ) changelog_from_git_commits # upload to Beta crashlytics( ... ) slack( ... ) end flutter buildͰڥΛΓସ͑ͯϏϧυ͢Δ