Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Flutterでstaging/production環境を切替える
Search
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
FURUKI Eiji
April 18, 2018
Programming
3
4.2k
Flutterでstaging/production環境を切替える
Flutter Meetup Tokyo #1 のLT資料です
FURUKI Eiji
April 18, 2018
Tweet
Share
Other Decks in Programming
See All in Programming
Feature Toggle は捨てやすく使おう
gennei
0
370
CSC307 Lecture 15
javiergs
PRO
0
270
The Past, Present, and Future of Enterprise Java
ivargrimstad
0
1.1k
S3ストレージクラスの「見える」「ある」「使える」は全部違う ─ 体験から見た、仕様の深淵を覗く
ya_ma23
0
1.2k
Agentic AI: Evolution oder Revolution
mobilelarson
PRO
0
200
RailsのValidatesをSwift Macrosで再現してみた
hokuron
0
140
ベクトル検索のフィルタを用いた機械学習モデルとの統合 / python-meetup-fukuoka-06-vector-attr
monochromegane
2
560
[PHPerKaigi 2026]PHPerKaigi2025の企画CodeGolfが最高すぎて社内で内製して半年運営して得た内製と運営の知見
ikezoemakoto
0
290
最初からAWS CDKで技術検証してもいいんじゃない?
akihisaikeda
4
180
守る「だけ」の優しいEMを抜けて、 事業とチームを両方見る視点を身につけた話
maroon8021
3
1.5k
モダンOBSプラグイン開発
umireon
0
180
Geminiをパートナーに神社DXシステムを個人開発した話(いなめぐDX 開発振り返り)
fujiba
0
120
Featured
See All Featured
Docker and Python
trallard
47
3.8k
A Soul's Torment
seathinner
5
2.5k
Learning to Love Humans: Emotional Interface Design
aarron
275
41k
Stop Working from a Prison Cell
hatefulcrawdad
274
21k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
16
1.9k
Building Experiences: Design Systems, User Experience, and Full Site Editing
marktimemedia
0
460
The Straight Up "How To Draw Better" Workshop
denniskardys
239
140k
Connecting the Dots Between Site Speed, User Experience & Your Business [WebExpo 2025]
tammyeverts
11
860
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
128
55k
What's in a price? How to price your products and services
michaelherold
247
13k
The Limits of Empathy - UXLibs8
cassininazir
1
270
Testing 201, or: Great Expectations
jmmastey
46
8.1k
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ͰڥΛΓସ͑ͯϏϧυ͢Δ