SlideShare a Scribd company logo
FLUTTER HEROES – TURIN – 12 March 2025
A JOURNEY TO
CONTINUOUS DELIVERY
WITH FLUTTER ⚡🚀🙂
Adrien Body
François Nollen
FLUTTER HEROES – TURIN – 12 March 2025 2
Adrien BODY
Staff Engineer
François NOLLEN
Staff Engineer
AGENDA
FLUTTER HEROES – TURIN – 12 March 2025 3
01 Continuous Delivery
02 Iterating Faster with Flutter
03 Dealing with Stores
04 Going Beta
05 Instant Updates with Shorebird
06 Feature Flags & Progressive Delivery
4
CONTINUOUS
DELIVERY (FOR MOBILE)
CHAP. 1/6
5
Good Old Waterfall
Releasing every year since the 1970s 😉
Source
:
https://unsplash.com/fr/photos/cascades-ziwmVy1Q1zk
FLUTTER HEROES – TURIN – 12 March 2025
6
« 10+ DEPLOYS PER DAY » @ VELOCITY 2009
Source
:
https://www.youtube.com/watch?v=LdOe18KhtT4
FLUTTER HEROES – TURIN – 12 March 2025
7
A DECADE WITH « DORA »
• 10 years of collecting data
about technology-driven teams
and organizations (39.000+)
• The annual State of DevOps
Report reveals the practices
that separate high and low
performers
FLUTTER HEROES – TURIN – 12 March 2025
8
THE FOUR HORSEMEN KEYS
Source
:
https://dora.dev/research/2024/dora-report/
FLUTTER HEROES – TURIN – 12 March 2025
9
R U L33T?
Source
:
https://dora.dev/research/2024/dora-report/
FLUTTER HEROES – TURIN – 12 March 2025
10
CONTINUOUS CODING?
FLUTTER HEROES – TURIN – 12 March 2025
while (alive)
{
eat();
sleep();
code();
repeat();
}
(function repeat() {
eat();
sleep();
coffeeLoader();
code();
repeat();
})();
while (!dead)
{
eat();
//sleep();
code();
}
11
« CONTINUOUS DELIVERY » FOR MOBILE?
Sources
:
https://blog.cellenza.com/cloud-2/strategie-de-ci-cd-sur-kubernetes/
FLUTTER HEROES – TURIN – 12 March 2025
Hot Reload? ❤
App Bundles?
Firebase?
App Stores?
Reviews?
E2E?
Compiler?
Linter?
Golden?
12
ITERATING FASTER
WITH FLUTTER
DRY (Don’t Repeat Yourself)
Pipelines
Testing
CHAP. 2/6
13
The new and improved SNCF
Connect app launched on time.
As a result, 90% of mobile code
is cross-platform, the team makes
one major release every week
with no delay between iOS and
Android features, and spends less
time monitoring multiple stacks.
https://flutter.dev/showcase/sncf-connect
FLUTTER HEROES – TURIN – 12 March 2025
14
SNCF CONNECT SHOWCASE
https://flutter.dev
/showcase
/sncf-connect
FLUTTER HEROES – TURIN – 12 March 2025
15
Source
:
https://unsplash.com/fr/photos/cascades-ziwmVy1Q1zk
Building Pipelines
FLUTTER HEROES – TURIN – 12 March 2025
16
MOBILE PIPELINE
Lint +
Compile
Unit-Test
Generate
Code
More
Tests
Even
More
Tests
Deploy
FLUTTER HEROES – TURIN – 12 March 2025
17
GITHUB (AND OTHERS)
• Flutter Github actions
• Lint
• Analyse
• Test
• Build
• Sign
• Release
• Codecov
• runs-on: macos-latest
• runs-on: ubuntu-latest
FLUTTER HEROES – TURIN – 12 March 2025
18
OUR FLUTTER PACKAGES BUILT WITH GITHUB
FLUTTER HEROES – TURIN – 12 March 2025
19
GITLAB
Lint Compile Unit Tests
Generate
code
Golden Tests Widget
Performance
Security
Footprint
Deploy to
stores
FLUTTER HEROES – TURIN – 12 March 2025
20
ARG JDK_VERSION=17
USER root
ARG FLUTTER_VERSION
ARG SONAR_SCANNER_VERSION
ARG VERY_GOOD_VERSION
ENV FLUTTER_HOME "/opt/flutter"
ENV SONAR_SCANNER_HOME=/opt/sonar-scanner
ENV LCOV_COBERTURA_HOME=/opt/lcov-cobertura
ENV PUB_CACHE="$HOME/.pub-cache"
ENV PATH="${FLUTTER_HOME}/bin:${FLUTTER_HOME}/bin/cache/dart-
sdk/bin:${SONAR_SCANNER_HOME}/bin:${LCOV_COBERTURA_HOME}/bin:${PUB_CACHE}/bin:${PATH}"
RUN apk add --update --no-cache 
unzip 
git
git-lfs
&& 
apk add --update --no-cache 
--repository=http://dl-cdn.alpinelinux.org/alpine/edge/community 
lcov
RUN git lfs install
RUN curl https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-
${SONAR_SCANNER_VERSION}.zip --output sonar-scanner-cli.zip 
&& unzip sonar-scanner-cli.zip 
&& rm sonar-scanner-cli.zip 
&& mv sonar-scanner-${SONAR_SCANNER_VERSION} ${SONAR_SCANNER_HOME}
RUN git clone --branch ${FLUTTER_VERSION} https://github.com/flutter/flutter.git
${FLUTTER_HOME} --depth 1 && 
flutter --suppress-analytics config --no-analytics && 
flutter --suppress-analytics precache && 
flutter doctor
RUN dart --disable-analytics 
&& dart pub global activate junitreport 
&& dart pub global activate very_good_cli ${VERY_GOOD_VERSION} 
&& curl -O https://raw.githubusercontent.com/eriwen/lcov-to-cobertura-
xml/master/lcov_cobertura/lcov_cobertura.py 
&& mkdir -p ${LCOV_COBERTURA_HOME}/bin 
&& mv lcov_cobertura.py ${LCOV_COBERTURA_HOME}/bin 
&& chmod +x ${LCOV_COBERTURA_HOME}/bin/lcov_cobertura.py 
&& dart --version 
&& very_good --version
• Flutter only | Android?
• openjdk-alpine (185 MB ⚠)
• alpine-android (lighter)
• Alternatives
• docker-images-flutter
• flutter-docker-image
DOCKER IMAGE
ON KUBERNETES
FLUTTER HEROES – TURIN – 12 March 2025
21
variable "image_name" {
type = string
}
variable "vm_cpu_number" {
type = number
}
variable "flutter_version" {
type = string
}
variable "cocoapod_version" {
type = string
}
variable "vm_builder_prefix" {
type = string
default = "ci-shorebird-image-vm-builder"
}
source "macstadium-orka" "image" {
source_image = "${var.base_image}"
image_name = "${var.image_name}"
orka_endpoint = "${var.endpoint}"
orka_user = "${var.orka_user}"
orka_password = "${var.orka_password}"
ssh_username = "${var.vm_ssh_username}"
ssh_password = "${var.vm_ssh_password}"
orka_vm_cpu_core = "${var.vm_cpu_number}"
orka_vm_builder_prefix = "${var.vm_builder_prefix}"
}
build {
sources = [
"macstadium-orka.image"
]
provisioner "shell" {
environment_vars = [
"FLUTTER_VERSION=${var.flutter_version}",
"COCOAPODS_VERSION=${var.cocoapod_version}",
"VM_SSH_PASSWORD=${var.vm_ssh_password}",
]
script = "bin/install-macstadium-shorebird"
}
}
• https://github.com/sncf-connect-
tech/shorebird-
macstadium/blob/main/packer-
shorebird-ios.pkr.hcl
PACKAGE IMAGE
ON MACSTADIUM
FLUTTER HEROES – TURIN – 12 March 2025
22
CODE GENERATION
• OpenAPI Generator
• CLI
• Dart
• Gradle
• Auto_route / Go Router builder
• Intl I18n
• Custom
• Eg. extract theme from Figma
FLUTTER HEROES – TURIN – 12 March 2025
23
DART ANALYSIS & LINT
dart format --fix --line-length 120 .
flutter analyze --no-pub --fatal-infos --fatal-warnings
We want 0 infos / warns to avoid technical debt
Takes 5mns to run in monorepo in CI with more than 250k LoC
Leverage Git Hooks locally :
https://pub.dev/packages/husky
https://rushjs.io/
https://evilmartians.com/opensource/lefthook
FLUTTER HEROES – TURIN – 12 March 2025
24
BUILD SPEED & SIZE
Gradle techniques:
• Share build cache between jobs (also great for pub cache)
• Tune android.enableJetifier
Remove dart const in serializer ⚠ built_value bug
• dart -Dglobal.type.flow.print.timings=true
Use –offline on pub
Remove abis:
• ndk abiFilters 'armeabi-v7a', 'arm64-v8a'
• --target-platform=android-arm,android-arm64
Use webP format for images
FLUTTER HEROES – TURIN – 12 March 2025
25
BUILD SPEED & SIZE
• Build AAB and APK (not universal) and check size:
AAB_SIZE=$(ls -l --block-size=1M "build/app/outputs/bundle/release/app-release.aab"
| awk '{print $5}')
if [[ "${AAB_SIZE}" -gt "${MAX_AAB_SIZE}" ]]; then
log_error "aab size has increazed to ${AAB_SIZE} Mo (max ${MAX_AAB_SIZE} Mo),
check with an app referent this new size"
exit 1
fi
bundletool build-apks --bundle=build/app/outputs/bundle/release/app-release.aab
--output=build/app/outputs/bundle/release/app-release.apks
https://github.com/capyvara/fastlane-plugin-store_sizer
FLUTTER HEROES – TURIN – 12 March 2025
26
FLUTTER HEROES – TURIN – 12 March 2025
INTERNAL DELIVERY
Sources
:
https://fr.goodbarber.com/blog/comment-tester-mon-application-avec-testflight-a782/
AppCenter shutdown: March 2025 🚨
Alternatives:
• Applivery
• Saucelabs TestFairy
• Firebase Distribution
App and
Certificates Storage
with Access Control
External
testing team
B2B Client
Feature
Branch
E2E Testing
27
Source
:
https://unsplash.com/fr/photos/cascades-ziwmVy1Q1zk
Testing everything
(Automating tests too)
FLUTTER HEROES – TURIN – 12 March 2025
28
GOOD OLD TEST PYRAMID
Golden Tests
Widget Tests (basic)
Unit Tests (BLoC)
Appium E2E Tests (regular UC)
E2E Tests
Golden Tests
Widget Tests
Unit Tests
à Datasets from fixtures
à Datasets from real or mocked data
FLUTTER HEROES – TURIN – 12 March 2025
29
GOLDEN FOR LAYOUT ISSUES
Something got wrong here!
FLUTTER HEROES – TURIN – 12 March 2025
30
GOLDEN FOR THEMES & SIZES
FLUTTER HEROES – TURIN – 12 March 2025
31
GOLDEN FOR ACCESSIBILITY
Golden & manual tests in accessibility mode
(enableSemanticDebugger)
FLUTTER HEROES – TURIN – 12 March 2025
Golden to test old devices 🌱
(+ foldable devices)
32
END-TO-END TESTS
FLUTTER HEROES – TURIN – 12 March 2025
(Hot reload!
❤
)
33
SONAR, DCM, FLUTTER PLUGIN, CHECKMARX
FLUTTER HEROES – TURIN – 12 March 2025
34
2025 SNAPSHOT 📸
FLUTTER HEROES – TURIN – 12 March 2025
Acceptable compilation time, IDE always reactive ✅
Build 22 minutes
Build 21 minutes
Acceptable build time on CI ⚠
Including 3k Golden
Cut out in 5 jobs
Run in ~15m by job
(<10m local run)
Now 10k Flutter Tests 🚀
35
STORES
Where good features go and meet their users 😍
CHAP. 3/6
https://unsplash.com/fr/photos/batiment-de-quatre-etages-avec-escaliers-j-0olYcaihg
36
STORES
Sources
:
https://galadrim.fr/_astro/Image-blog_copy_2J9mH.webp
FLUTTER HEROES – TURIN – 12 March 2025
37
• 2008: birth of the App Stores
• Apple App Store: 500 apps
• Android Market (now Google Play Store)
• 2009-2012: early growth and expansion
• 2013-2016: in-app purchases and subscriptions
• 2015: Google Play staff-reviewed app submissions
and age-based ratings
• 2015: Google Play introduces A/B test experiments
A SHORT HISTORY OF STORES
Sources
:
https://galadrim.fr/_astro/Image-blog_copy_2J9mH.webp
FLUTTER HEROES – TURIN – 12 March 2025
Source
:
https://appradar.com/blog/app-stores-history
38
A SHORT HISTORY OF STORES
Sources
:
https://galadrim.fr/_astro/Image-blog_copy_2J9mH.webp
• 2017-2020: App Store Optimization
• 2017: Apple publishes new rules for the App Store
• 2018: Apple tightens requirements for app publication,
particularly for VPN applications and user data protection
• 2019: Google introduces new policies to improve app
quality and security
• 2020: Google introduces new policies to enhance app transparency
• 2021: Apple introduces App Tracking Transparency (ATT) with iOS 14.5
• Google announced new policies to improve app quality.
• Google enforced new policies policy aimed to improve the quality
and relevance of app listings. App titles got limited to 30 characters
and the use of popular keywords got prohibited
• Google introduced custom store listings, enabling developers to create tailored content for different user segments
FLUTTER HEROES – TURIN – 12 March 2025
Source
:
https://appradar.com/blog/app-stores-history
39
A SHORT HISTORY OF STORES
Sources
:
https://galadrim.fr/_astro/Image-blog_copy_2J9mH.webp
• 2022:
• Apple blocked 1.7 million applications from being published
on the App Store due to privacy, security, and content standards violations
• Google launches the Data Safety section
• Google introduced up to 50 Custom Store Listings to create
personalized pages for different audience segments
• 2023:
• Apple announces new guidelines for app submissions
• Google introduces new policies to enhance app security
• Google improved custom store listings, allowing developers
to create tailored content for different user segments
• 2024:
• Apple allowed third-party app stores on iPhones and iPads for the first time
FLUTTER HEROES – TURIN – 12 March 2025
Source
:
https://appradar.com/blog/app-stores-history
40
App stores have become huge
marketplaces with more and
more personalization and
rules, with changes happening
almost on a weekly basis.
FLUTTER HEROES – TURIN – 12 March 2025
Sources
:
https://unsplash.com/fr/photos/cables-electriques-assortis-l090uFWoPaI
41
REVIEWS & VALIDATIONS
Sources
:
https://galadrim.fr/_astro/Image-blog_copy_2J9mH.webp
FLUTTER HEROES – TURIN – 12 March 2025
43
REVIEWS & VALIDATIONS
Sources
:
https://galadrim.fr/_astro/Image-blog_copy_2J9mH.webp
FLUTTER HEROES – TURIN – 12 March 2025
44
ROLLOUT STRATEGIES
Sources
:
https://galadrim.fr/_astro/Image-blog_copy_2J9mH.webp
Deployment increment options (Android):
• Per 1%
• Per 20%
• 100% (99% = halt still possible!)
FLUTTER HEROES – TURIN – 12 March 2025
45
APP STORE & TESTFLIGHT
Sources
:
https://fr.goodbarber.com/blog/comment-tester-mon-application-avec-testflight-a782/
FLUTTER HEROES – TURIN – 12 March 2025
46
OTHER PARAMETERS
Sources
:
https://galadrim.fr/_astro/Image-blog_copy_2J9mH.webp
Forced update, or flexible update with custom modal, or Play Store-managed (but try keep access to vitals)
Code Freeze for Commercial Events
Low risked VS high risked
Analysis in working hours ! (« Prod’ Captain » role)
FLUTTER HEROES – TURIN – 12 March 2025
47
STORES SIGNATURES MODES: ANDROID
Sources
:
https://fr.goodbarber.com/blog/comment-tester-mon-application-avec-testflight-a782/
FLUTTER HEROES – TURIN – 12 March 2025
48
STORES SIGNATURES MODES: IOS
Sources
:
https://fr.goodbarber.com/blog/comment-tester-mon-application-avec-testflight-a782/
Apple Pay
FLUTTER HEROES – TURIN – 12 March 2025
49
STORES ADDITIONAL SECURITIES
Play Integrity API: provides info about request/origin
Auto-protection: prevents from modified APK
App signature options
Play Store visibility: hide Play Store from malicious devices
FLUTTER HEROES – TURIN – 12 March 2025
50
FLUTTER HEROES – TURIN – 12 March 2025
https://docs.flutter.dev/deployment/cd
51
FLUTTER HEROES – TURIN – 12 March 2025
desc "Submit a new Store Build to PlayStore"
lane :upload_to_playstore do |options|
aab_path = "../build/app/outputs/bundle/#{options[:build_mode]}/app-#{options[:build_mode]}.aab"
upload_to_play_store(
aab: aab_path,
track: 'alpha’ | 'rollout’,
rollout: ‘0.5’
)
end
desc "Submit a new Store Build to Testflight"
lane :upload_to_appstore do |options|
ipa_name = options[:ipa_name]
ipa_path = "../build/ios/ipa/#{ipa_name}.ipa"
testflight(
api_key: get_api_key,
skip_submission: true,
ipa: ipa_path
)
end
52
Source
:
https://unsplash.com/fr/photos/conteneurs-intermodaux-classes-de-couleurs-assorties-tjX_sniNzgQ
Store
is the limit?
FLUTTER HEROES – TURIN – 12 March 2025
53
GOING
BETA
Progressive release or rollout
to specific user groups
Photo : https://unsplash.com/fr/photos/les-pieds-dune-personne-sur-une-surface-en-bois-avec-un-signe-XS_o-Iuf9Go
CHAP. 4/6
54
ALPHA, BETA RELEASE AND BETA MODE
Android Channels
FLUTTER HEROES – TURIN – 12 March 2025
55
ALPHA, BETA RELEASE AND BETA MODE
iOS
FLUTTER HEROES – TURIN – 12 March 2025
56
CUSTOM BETA MODE (FEATURES FOR BETA TESTERS ONLY)
Database
AWS DynamoDB:
• Global FT Value
• Beta override
Client ID Value
Back-For-Front
BFF Rules:
• isBetaClient
• ftEnabled
• ftOverrides
Flutter App
Dart SDK:
• Features loaded
from BFF
• Features stored
locally for
session
(consistency)
FLUTTER HEROES – TURIN – 12 March 2025
Exclusive « beta » mode, available only for community users:
• Community program at https://www.vous.sncf-connect.com/
• Direct feedback from beta testers
57
SHOREBIRD
CodePush instant updates for Flutter
Photo : https://unsplash.com/fr/photos/un-petit-oiseau-assis-au-sommet-dune-plante-pres-de-locean-w3m0oRA0UNA
CHAP. 5/6
58
WHY SHOREBIRD?
FLUTTER HEROES – TURIN – 12 March 2025
59
SHOREBIRD: CODEPUSH FOR FLUTTER
FLUTTER HEROES – TURIN – 12 March 2025
Photo
:
https://medium.com/@mabud_alam/code-push-for-flutter-update-your-app-without-a-new-release-using-shorebird-b6f4de672481
60
A FLUTTER FORK FOR COMPLIANCE
FLUTTER HEROES – TURIN – 12 March 2025
61
HOW IT WORKS
SHOREBIRD
SERVER
MOBILE APP
Original
Dart Bundle
Shorebird
Dart Bundle
Patch ?
DOWNLOAD
CUSTOM
BOOT
SHOREBIRD
UPDATER
FLUTTER HEROES – TURIN – 12 March 2025
62
BUILD, (STAGE,) PUBLISH, PROMOTE
FLUTTER HEROES – TURIN – 12 March 2025
63
FLUTTER
MOBILE APP
PLAY STORY
IN-APP UPGRADE
SHOREBIRD
PATCH
FLUTTER HEROES – TURIN – 12 March 2025
🤔
INTERACTION WITH OTHER UPDATES
64
Android open source docker image
https://github.com/sncf-connect-tech/shorebird-docker/blob/main/Dockerfile-shorebird-android
iOS open source MacStadium
https://github.com/sncf-connect-tech/shorebird-macstadium
FLUTTER HEROES – TURIN – 12 March 2025
SHOREBIRD IN GITLAB-CI
65
GREAT TOOL FOR YOU?
FLUTTER HEROES – TURIN – 12 March 2025
Push patches instantly 😍
way faster than deploying to Stores
instant fixes make users happy!
Size overhead 🕵
our measure for our full APK:
Without Shorebird
108.1MB
Shorebird
without the package
shorebird_code_push
114MB
Complexity overhead 🧐
mix Shorebird with other mecanisms?
complexity OK for you / Ops?
Fork of Flutter
Costs 💰
Store compliance? ⚠
Can’t patch native code
66
FEATURE FLAGS
And « Progressive Delivery »
Photo : https://unsplash.com/fr/photos/feux-de-circulation-a-cote-des-arbres-OcpN5K0TwKo
CHAP. 6/6
67
EARLY 2024…
• A major release (50-100 stories)
deployed to stores each week
• 1-day branching to test the
release in isolation
• 3-day regression testing
before deploying to production
• Android/iOS stores
rollout from 24h to 1w
• Mobile vs. Web
different release times
FLUTTER HEROES – TURIN – 12 March 2025
68
We need Speed
to release more than once a week
Source
:
https://unsplash.com/fr/photos/time-lapse-des-lampadaires--Vqn2WrfxTQ
FLUTTER HEROES – TURIN – 12 March 2025
69
We need Safety
to go faster to production
Source
:
https://unsplash.com/fr/photos/photographie-en-accelere-des-lumieres-de-la-ville-la-nuit-SUi9mYSVTyc
FLUTTER HEROES – TURIN – 12 March 2025
70
Regular Toggles
Long-lived toggles acting as
circuit breakers to disable a major
feature or partner integration in
case of emergency.
Activation Toggles A/B Testing Variants
A NEW KIND OF TOGGLES
Short-lived toggles enabling or
disabling a recent change of
code. Always deployed as
disabled. Recycled as soon as
production has proven stable.
Values and String variants used to
perform temporary product
experiments with various
segments of users.
FLUTTER HEROES – TURIN – 12 March 2025
💡
71
ACTIVATION TOGGLES
• Introducing Activation Toggles
for every (eligible) change
being a feature or a fix!
• Any change is tested enabled and
disabled, and goes disabled to
production
• Activation is decoupled
from deployment
• After some time in production, the
toggle is cleaned up
FLUTTER HEROES – TURIN – 12 March 2025
Source
:
https://unsplash.com/fr/photos/un-panneau-dextincteur-rouge-et-blanc-sur-un-mur-de-beton-kPoSgf_cjTk
class FeatureToggleGuard extends AutoRouteGuard
72
CUSTOM IMPLEMENTATION
FT SDK API
Local
storage
FT Cubit
FT Guard
FLUTTER HEROES – TURIN – 12 March 2025
73
CUSTOM IMPLEMENTATION
class FeatureToggleCubit extends Cubit<FeatureToggleV2State> {
static const _initializationTimeout = Duration(seconds: 5);
final FeatureToggleSdk _featuresSdk;
late final StreamSubscription<Map<String, String>?> _featuresSubscription;
FeatureToggleCubit({FeatureToggleSdk? providedSdk})
: _featuresSdk = providedSdk ?? locator<Sdk>().featureToggle,
super(const InitState()) {
_featuresSubscription = _featuresSdk.featuresStreamV2.listen(
(features) {
emit(BuiltMap<String, String>.from(features).toState());
},
);
}
FLUTTER HEROES – TURIN – 12 March 2025
74
CUSTOM IMPLEMENTATION
/// Returns true if the feature toggle is explicitly set to [FeatureState.enabled]
bool isFeatureEnabled(String feature) =>
state.withValue((value) =>
value[feature] == FeatureState.enabled ||
(defaultTargetPlatform == TargetPlatform.iOS && value[feature] == FeatureState.iOsOnly) ||
(defaultTargetPlatform == TargetPlatform.android && value[feature] == FeatureState.androidOnly)) ??
false;
void updateStatus({bool withCache = true}) {
_featuresSdk.loadFeatureToggleStatuses(withCache: withCache);
}
Future<bool> isFeatureEnabledAsync(String feature) async {
try {
await waitEndFetching(includeActual: true).timeout(_initializationTimeout);
return isFeatureEnabled(feature);
} on TimeoutException {
FLUTTER HEROES – TURIN – 12 March 2025
75
CUSTOM TOOLS
FLUTTER HEROES – TURIN – 12 March 2025
76
OUTCOMES
• 100s of temporary activation FTs
currently in production
• In 2024 we moved from 1 to 3+ deploys
per week (Web, Backend, Infra)
• Some stories take 2 days from to prod
• Still 1 Stores publish per week… but
features are released more continuously
• ⚠ First seen as a burden for devs…
…even if less rollbacks in production and
many incidents solved instantly
FLUTTER HEROES – TURIN – 12 March 2025
77
We need Tools!
to manage 100s of Feature Flags
Source
:
https://unsplash.com/fr/photos/un-groupe-de-cles-disposees-en-cercle-iuuJC_pjLU0
FLUTTER HEROES – TURIN – 12 March 2025
78
FIREBASE
• Firebase Remote Config
• Release Info
• Custom Keys Limit ⚠
FLUTTER HEROES – TURIN – 12 March 2025
79
FEATURE MANAGEMENT TOOLS
FLUTTER HEROES – TURIN – 12 March 2025
80
A STANDARD FOR FEATURE FLAGS
https://openfeature.dev/
FLUTTER HEROES – TURIN – 12 March 2025
81
LAUNCHDARKLY
• Feature Management platform,
handling booleans/toggles
as well as variations (String)
• User Interface to create, configure
and monitor Feature Flags
• SDK implementations to integrate Flags
with various languages and platforms
• + API + CLI + Intellij + VSCode + Copilot
FLUTTER HEROES – TURIN – 12 March 2025
Source
:
https://launchdarkly.com/blog/new-and-improved-launchdarkly-platform-experience/
82
POLYGLOT SDK (OPENFEATURE + CUSTOM)
Future<void> init() async {
final correlationId = await _storageSdk.getCorrelationId() ?? 'Unknown';
final config = LDConfig(
CredentialSource.fromEnvironment(),
AutoEnvAttributes.enabled,
);
final context = LDContextBuilder().kind("correlationId", correlationId).build();
client = LDClient(config, context);
await client!.start().timeout(const Duration(seconds: 1));
}
Future<bool> isFeatureEnabled(String feature) async {
final featureState = await client?.boolVariation(feature, false) ?? false;
DatadogSdk.instance.rum?.addFeatureFlagEvaluation(feature, featureState);
return featureState;
}
FLUTTER HEROES – TURIN – 12 March 2025
83
MANAGE FLAGS BY ENVIRONMENTS
FLUTTER HEROES – TURIN – 12 March 2025
Source
:
https://launchdarkly.com/blog/new-and-improved-launchdarkly-platform-experience/
84
DEFINE RULES, WORKFLOWS & PIPELINES
FLUTTER HEROES – TURIN – 12 March 2025
Source
:
https://launchdarkly.com/docs/home/releases/release-pipelines-create
85
DEMO
86
INTEGRATING WITH MONITORING
FLUTTER HEROES – TURIN – 12 March 2025
87
AUTOMATIC ROLLOUT (LEVERAGING METRICS)
FLUTTER HEROES – TURIN – 12 March 2025
Source
:
https://launchdarkly.com/docs/home/releases/releasing
88
AUTOMATIC ROLLOUT (LEVERAGING METRICS)
FLUTTER HEROES – TURIN – 12 March 2025
Source
:
https://launchdarkly.com/docs/home/releases/releasing
89
Further with Feature Flags
From Continuous to Progressive Delivery
Source
:
https://unsplash.com/fr/photos/une-voie-ferree-avec-le-soleil-couchant-en-arriere-plan-orossXHCgtE
FLUTTER HEROES – TURIN – 12 March 2025
90
PERSONALIZATION++
Serving features by…
• Environments
• App versions
• Device types
• User segments or individuals
• User context / profile / preferences?
• Region? Weather? Anything…?
• (ML / AI?... 🤖)
FLUTTER HEROES – TURIN – 12 March 2025
92
« PROGRESSIVE DELIVERY »
Continuous Delivery Progressive Delivery
Focused on deployments Focused on features
Releasing bundles Releasing features
Emphasis on target environments Emphasis on users
« All-or-nothing » rollout or rollback Features decoupled from each other
Business and DevOps teams work
together to deploy to production at the
ideal time (for the teams / for the users)
DevOps teams push code to production
(continuously), while the business can
decide on when to release each feature
to each group of users
FLUTTER HEROES – TURIN – 12 March 2025
Source
:
https://launchdarkly.com/blog/new-and-improved-launchdarkly-platform-experience/
93
Best time to
push an update?
(Best time for who?)
Source
:
https://unsplash.com/fr/photos/homme-en-veste-bleue-et-pantalon-noir-roulant-sur-un-velo-noir-sur-une-route-en-beton-gris-pendant-bj_9ArBKtRM
FLUTTER HEROES – TURIN – 12 March 2025
94
Would you push
changes to the UI now?
What « bad timing » means
depends on your use case)
Source
:
https://unsplash.com/fr/photos/une-voie-ferree-avec-le-soleil-couchant-en-arriere-plan-orossXHCgtE
FLUTTER HEROES – TURIN – 12 March 2025
95
A better time to release
your brand-new feature?
Knowing your users remains essential
Source
:
https://unsplash.com/fr/photos/une-femme-assise-sur-un-canape-dans-un-salon-KkXVoSECjCM
FLUTTER HEROES – TURIN – 12 March 2025
96
CONCLUSION
« It’s a Wrap » 😉
Photo : https://unsplash.com/fr/photos/un-groupe-de-pieces-dans-une-tasse-yA9guldcm54
97
FLUTTER HEROES – TURIN – 12 March 2025
⚡ CD & DORA: faster & safer
👷 Automate everything
🚀 Lots of available options to release
Stores options, beta channels, rollout strategies,
CodePush, Feature Flags & more
😍 Beyond code deploys: Progressive Delivery
A JOURNEY TO CONTINUOUS DELIVERY (FOR MOBILE)
98
FLUTTER HEROES – TURIN – 12 March 2025
E2E Testing with Flutter
Widget Testing with Flutter Accessibility Testing with Flutter
Devoxx France
Flutter Heroes
Flutter Connection
99
FLUTTER HEROES – TURIN – 12 March 2025

More Related Content

PDF
A Journey to Continuous Delivery with Flutter ⚡️🚀🙂 (@Flutter_Connect 2025)
PDF
Docker and Your Path to a Better Staging Environment - webinar by Gil Tayar
PPTX
Global Azure Bootcamp 2016 - Lyon : Keynote Quantum : Concepts explained & Li...
PDF
He stopped using for/while loops, you won't believe what happened next!
PDF
ADRecon - Detection CHCON 2018
PDF
Beyond open data: empowering citizens to understand their cities
PDF
Enabling Microservice @ Orbitz - GOTO Chicago 2016
PDF
DevOpSec_DockerNPodMan-20230220.pdf
A Journey to Continuous Delivery with Flutter ⚡️🚀🙂 (@Flutter_Connect 2025)
Docker and Your Path to a Better Staging Environment - webinar by Gil Tayar
Global Azure Bootcamp 2016 - Lyon : Keynote Quantum : Concepts explained & Li...
He stopped using for/while loops, you won't believe what happened next!
ADRecon - Detection CHCON 2018
Beyond open data: empowering citizens to understand their cities
Enabling Microservice @ Orbitz - GOTO Chicago 2016
DevOpSec_DockerNPodMan-20230220.pdf

Similar to A Journey to Continuous Delivery with Flutter ⚡️🚀🙂 (@FlutterHeroes 2025) (20)

PDF
Deis, a PaaS built with Docker, Docker Meetup Sao Paulo #3 @Wayra
PDF
Complementing Docker with Puppet
PDF
Shaping Clouds with Terraform
PDF
Integrating multiple CDN providers at Etsy - Velocity Europe (London) 2013
PPTX
Ansible - From Zero to Hero.pptx
PDF
Threat Modelling - It's not just for developers
PDF
Beyond the Query – Bringing Complex Access Patterns to NoSQL with DataStax - ...
PDF
botsádfasdfsdádfsasdasdfsdfsadfsdffsadf.pdf
PDF
Beyond the Query: A Cassandra + Solr + Spark Love Triangle Using Datastax Ent...
PDF
Why we don’t use the Term DevOps: the Journey to a Product Mindset - Destinat...
PDF
End-to-end pipeline agility - Berlin Buzzwords 2024
PDF
Using Android Things to Detect & Exterminate Reptilians
PDF
Testing Java Microservices Workshop
PDF
Exploring Phantom Traffic Jams in Your Data Flows
PPTX
CNCF Québec Meetup du 16 Novembre 2023
PDF
Cassandra Meetup: Real-time Analytics using Cassandra, Spark and Shark at Ooyala
PDF
Microservices, la risposta che (forse) cercavi!
PPTX
Serverless Data Architecture at scale on Google Cloud Platform - Lorenzo Ridi...
PDF
Hopping in clouds - phpuk 17
Deis, a PaaS built with Docker, Docker Meetup Sao Paulo #3 @Wayra
Complementing Docker with Puppet
Shaping Clouds with Terraform
Integrating multiple CDN providers at Etsy - Velocity Europe (London) 2013
Ansible - From Zero to Hero.pptx
Threat Modelling - It's not just for developers
Beyond the Query – Bringing Complex Access Patterns to NoSQL with DataStax - ...
botsádfasdfsdádfsasdasdfsdfsadfsdffsadf.pdf
Beyond the Query: A Cassandra + Solr + Spark Love Triangle Using Datastax Ent...
Why we don’t use the Term DevOps: the Journey to a Product Mindset - Destinat...
End-to-end pipeline agility - Berlin Buzzwords 2024
Using Android Things to Detect & Exterminate Reptilians
Testing Java Microservices Workshop
Exploring Phantom Traffic Jams in Your Data Flows
CNCF Québec Meetup du 16 Novembre 2023
Cassandra Meetup: Real-time Analytics using Cassandra, Spark and Shark at Ooyala
Microservices, la risposta che (forse) cercavi!
Serverless Data Architecture at scale on Google Cloud Platform - Lorenzo Ridi...
Hopping in clouds - phpuk 17
Ad

More from François (18)

PDF
A la recherche du RAG perdu 🤠🧭🤖 (@DevoxxFR 2025)
PDF
B.O.F. communauté InnerSource (@DevoxxFR 2025)
PDF
TOSIT.fr grandes organisations & open source (@OSXP_Paris 2024)
PDF
RAG against the Machine 😎🤖 (@DevFestNantes 2024)
PDF
C'est une bonne situation ça, Staff Engineer ? 😉 (@DevoxxFR 2024)
PDF
Mind your App Footprint 🐾⚡️🌱 (@FlutterHeroes 2024)
PDF
Monorepo & Monomythe (@Volcamp 2023)
PDF
Collecte unifiée Server-to-Server - Tealium SNCF Connect (@EBG 2023)
PDF
The Story of SNCF Connect - biggest Flutter app in Europe (@FlutterHeroes 2023)
PDF
REX Flutter SNCF Connect (@VivaTech 2022).pdf
PDF
OpenSource & InnerSource pour accélérer les développements
PDF
Dans le Monorepo vous n'êtes jamais seul, le Park est ouvert... 🦖🦕🐢 (@BreizhC...
PDF
Mind your App Footprint 🐾⚡️🌱 (@FlutterConn 2023)
PDF
Tock & Mélusine REX IA Open Source #AIParis 2020
PDF
Conversational AI & Open Source #OSSPARIS19
PPTX
TOCK (The Open Conversation Kit) @ Meetup Open Transport
PDF
Monitoring une recette DevOps
PDF
DevOps et tendances Monitoring
A la recherche du RAG perdu 🤠🧭🤖 (@DevoxxFR 2025)
B.O.F. communauté InnerSource (@DevoxxFR 2025)
TOSIT.fr grandes organisations & open source (@OSXP_Paris 2024)
RAG against the Machine 😎🤖 (@DevFestNantes 2024)
C'est une bonne situation ça, Staff Engineer ? 😉 (@DevoxxFR 2024)
Mind your App Footprint 🐾⚡️🌱 (@FlutterHeroes 2024)
Monorepo & Monomythe (@Volcamp 2023)
Collecte unifiée Server-to-Server - Tealium SNCF Connect (@EBG 2023)
The Story of SNCF Connect - biggest Flutter app in Europe (@FlutterHeroes 2023)
REX Flutter SNCF Connect (@VivaTech 2022).pdf
OpenSource & InnerSource pour accélérer les développements
Dans le Monorepo vous n'êtes jamais seul, le Park est ouvert... 🦖🦕🐢 (@BreizhC...
Mind your App Footprint 🐾⚡️🌱 (@FlutterConn 2023)
Tock & Mélusine REX IA Open Source #AIParis 2020
Conversational AI & Open Source #OSSPARIS19
TOCK (The Open Conversation Kit) @ Meetup Open Transport
Monitoring une recette DevOps
DevOps et tendances Monitoring
Ad

Recently uploaded (20)

PPTX
Big Data Technologies - Introduction.pptx
PPTX
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
PDF
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
PPTX
20250228 LYD VKU AI Blended-Learning.pptx
PPTX
Programs and apps: productivity, graphics, security and other tools
PDF
Encapsulation theory and applications.pdf
PPTX
Cloud computing and distributed systems.
PDF
Agricultural_Statistics_at_a_Glance_2022_0.pdf
PDF
NewMind AI Weekly Chronicles - August'25-Week II
PDF
Reach Out and Touch Someone: Haptics and Empathic Computing
PDF
cuic standard and advanced reporting.pdf
PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
PDF
Building Integrated photovoltaic BIPV_UPV.pdf
PDF
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
PDF
Spectral efficient network and resource selection model in 5G networks
PDF
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
PDF
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
DOCX
The AUB Centre for AI in Media Proposal.docx
PDF
Encapsulation_ Review paper, used for researhc scholars
PDF
The Rise and Fall of 3GPP – Time for a Sabbatical?
Big Data Technologies - Introduction.pptx
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
20250228 LYD VKU AI Blended-Learning.pptx
Programs and apps: productivity, graphics, security and other tools
Encapsulation theory and applications.pdf
Cloud computing and distributed systems.
Agricultural_Statistics_at_a_Glance_2022_0.pdf
NewMind AI Weekly Chronicles - August'25-Week II
Reach Out and Touch Someone: Haptics and Empathic Computing
cuic standard and advanced reporting.pdf
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
Building Integrated photovoltaic BIPV_UPV.pdf
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
Spectral efficient network and resource selection model in 5G networks
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
The AUB Centre for AI in Media Proposal.docx
Encapsulation_ Review paper, used for researhc scholars
The Rise and Fall of 3GPP – Time for a Sabbatical?

A Journey to Continuous Delivery with Flutter ⚡️🚀🙂 (@FlutterHeroes 2025)

  • 1. FLUTTER HEROES – TURIN – 12 March 2025 A JOURNEY TO CONTINUOUS DELIVERY WITH FLUTTER ⚡🚀🙂 Adrien Body François Nollen
  • 2. FLUTTER HEROES – TURIN – 12 March 2025 2 Adrien BODY Staff Engineer François NOLLEN Staff Engineer
  • 3. AGENDA FLUTTER HEROES – TURIN – 12 March 2025 3 01 Continuous Delivery 02 Iterating Faster with Flutter 03 Dealing with Stores 04 Going Beta 05 Instant Updates with Shorebird 06 Feature Flags & Progressive Delivery
  • 5. 5 Good Old Waterfall Releasing every year since the 1970s 😉 Source : https://unsplash.com/fr/photos/cascades-ziwmVy1Q1zk FLUTTER HEROES – TURIN – 12 March 2025
  • 6. 6 « 10+ DEPLOYS PER DAY » @ VELOCITY 2009 Source : https://www.youtube.com/watch?v=LdOe18KhtT4 FLUTTER HEROES – TURIN – 12 March 2025
  • 7. 7 A DECADE WITH « DORA » • 10 years of collecting data about technology-driven teams and organizations (39.000+) • The annual State of DevOps Report reveals the practices that separate high and low performers FLUTTER HEROES – TURIN – 12 March 2025
  • 8. 8 THE FOUR HORSEMEN KEYS Source : https://dora.dev/research/2024/dora-report/ FLUTTER HEROES – TURIN – 12 March 2025
  • 10. 10 CONTINUOUS CODING? FLUTTER HEROES – TURIN – 12 March 2025 while (alive) { eat(); sleep(); code(); repeat(); } (function repeat() { eat(); sleep(); coffeeLoader(); code(); repeat(); })(); while (!dead) { eat(); //sleep(); code(); }
  • 11. 11 « CONTINUOUS DELIVERY » FOR MOBILE? Sources : https://blog.cellenza.com/cloud-2/strategie-de-ci-cd-sur-kubernetes/ FLUTTER HEROES – TURIN – 12 March 2025 Hot Reload? ❤ App Bundles? Firebase? App Stores? Reviews? E2E? Compiler? Linter? Golden?
  • 12. 12 ITERATING FASTER WITH FLUTTER DRY (Don’t Repeat Yourself) Pipelines Testing CHAP. 2/6
  • 13. 13 The new and improved SNCF Connect app launched on time. As a result, 90% of mobile code is cross-platform, the team makes one major release every week with no delay between iOS and Android features, and spends less time monitoring multiple stacks. https://flutter.dev/showcase/sncf-connect FLUTTER HEROES – TURIN – 12 March 2025
  • 17. 17 GITHUB (AND OTHERS) • Flutter Github actions • Lint • Analyse • Test • Build • Sign • Release • Codecov • runs-on: macos-latest • runs-on: ubuntu-latest FLUTTER HEROES – TURIN – 12 March 2025
  • 18. 18 OUR FLUTTER PACKAGES BUILT WITH GITHUB FLUTTER HEROES – TURIN – 12 March 2025
  • 19. 19 GITLAB Lint Compile Unit Tests Generate code Golden Tests Widget Performance Security Footprint Deploy to stores FLUTTER HEROES – TURIN – 12 March 2025
  • 20. 20 ARG JDK_VERSION=17 USER root ARG FLUTTER_VERSION ARG SONAR_SCANNER_VERSION ARG VERY_GOOD_VERSION ENV FLUTTER_HOME "/opt/flutter" ENV SONAR_SCANNER_HOME=/opt/sonar-scanner ENV LCOV_COBERTURA_HOME=/opt/lcov-cobertura ENV PUB_CACHE="$HOME/.pub-cache" ENV PATH="${FLUTTER_HOME}/bin:${FLUTTER_HOME}/bin/cache/dart- sdk/bin:${SONAR_SCANNER_HOME}/bin:${LCOV_COBERTURA_HOME}/bin:${PUB_CACHE}/bin:${PATH}" RUN apk add --update --no-cache unzip git git-lfs && apk add --update --no-cache --repository=http://dl-cdn.alpinelinux.org/alpine/edge/community lcov RUN git lfs install RUN curl https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli- ${SONAR_SCANNER_VERSION}.zip --output sonar-scanner-cli.zip && unzip sonar-scanner-cli.zip && rm sonar-scanner-cli.zip && mv sonar-scanner-${SONAR_SCANNER_VERSION} ${SONAR_SCANNER_HOME} RUN git clone --branch ${FLUTTER_VERSION} https://github.com/flutter/flutter.git ${FLUTTER_HOME} --depth 1 && flutter --suppress-analytics config --no-analytics && flutter --suppress-analytics precache && flutter doctor RUN dart --disable-analytics && dart pub global activate junitreport && dart pub global activate very_good_cli ${VERY_GOOD_VERSION} && curl -O https://raw.githubusercontent.com/eriwen/lcov-to-cobertura- xml/master/lcov_cobertura/lcov_cobertura.py && mkdir -p ${LCOV_COBERTURA_HOME}/bin && mv lcov_cobertura.py ${LCOV_COBERTURA_HOME}/bin && chmod +x ${LCOV_COBERTURA_HOME}/bin/lcov_cobertura.py && dart --version && very_good --version • Flutter only | Android? • openjdk-alpine (185 MB ⚠) • alpine-android (lighter) • Alternatives • docker-images-flutter • flutter-docker-image DOCKER IMAGE ON KUBERNETES FLUTTER HEROES – TURIN – 12 March 2025
  • 21. 21 variable "image_name" { type = string } variable "vm_cpu_number" { type = number } variable "flutter_version" { type = string } variable "cocoapod_version" { type = string } variable "vm_builder_prefix" { type = string default = "ci-shorebird-image-vm-builder" } source "macstadium-orka" "image" { source_image = "${var.base_image}" image_name = "${var.image_name}" orka_endpoint = "${var.endpoint}" orka_user = "${var.orka_user}" orka_password = "${var.orka_password}" ssh_username = "${var.vm_ssh_username}" ssh_password = "${var.vm_ssh_password}" orka_vm_cpu_core = "${var.vm_cpu_number}" orka_vm_builder_prefix = "${var.vm_builder_prefix}" } build { sources = [ "macstadium-orka.image" ] provisioner "shell" { environment_vars = [ "FLUTTER_VERSION=${var.flutter_version}", "COCOAPODS_VERSION=${var.cocoapod_version}", "VM_SSH_PASSWORD=${var.vm_ssh_password}", ] script = "bin/install-macstadium-shorebird" } } • https://github.com/sncf-connect- tech/shorebird- macstadium/blob/main/packer- shorebird-ios.pkr.hcl PACKAGE IMAGE ON MACSTADIUM FLUTTER HEROES – TURIN – 12 March 2025
  • 22. 22 CODE GENERATION • OpenAPI Generator • CLI • Dart • Gradle • Auto_route / Go Router builder • Intl I18n • Custom • Eg. extract theme from Figma FLUTTER HEROES – TURIN – 12 March 2025
  • 23. 23 DART ANALYSIS & LINT dart format --fix --line-length 120 . flutter analyze --no-pub --fatal-infos --fatal-warnings We want 0 infos / warns to avoid technical debt Takes 5mns to run in monorepo in CI with more than 250k LoC Leverage Git Hooks locally : https://pub.dev/packages/husky https://rushjs.io/ https://evilmartians.com/opensource/lefthook FLUTTER HEROES – TURIN – 12 March 2025
  • 24. 24 BUILD SPEED & SIZE Gradle techniques: • Share build cache between jobs (also great for pub cache) • Tune android.enableJetifier Remove dart const in serializer ⚠ built_value bug • dart -Dglobal.type.flow.print.timings=true Use –offline on pub Remove abis: • ndk abiFilters 'armeabi-v7a', 'arm64-v8a' • --target-platform=android-arm,android-arm64 Use webP format for images FLUTTER HEROES – TURIN – 12 March 2025
  • 25. 25 BUILD SPEED & SIZE • Build AAB and APK (not universal) and check size: AAB_SIZE=$(ls -l --block-size=1M "build/app/outputs/bundle/release/app-release.aab" | awk '{print $5}') if [[ "${AAB_SIZE}" -gt "${MAX_AAB_SIZE}" ]]; then log_error "aab size has increazed to ${AAB_SIZE} Mo (max ${MAX_AAB_SIZE} Mo), check with an app referent this new size" exit 1 fi bundletool build-apks --bundle=build/app/outputs/bundle/release/app-release.aab --output=build/app/outputs/bundle/release/app-release.apks https://github.com/capyvara/fastlane-plugin-store_sizer FLUTTER HEROES – TURIN – 12 March 2025
  • 26. 26 FLUTTER HEROES – TURIN – 12 March 2025 INTERNAL DELIVERY Sources : https://fr.goodbarber.com/blog/comment-tester-mon-application-avec-testflight-a782/ AppCenter shutdown: March 2025 🚨 Alternatives: • Applivery • Saucelabs TestFairy • Firebase Distribution App and Certificates Storage with Access Control External testing team B2B Client Feature Branch E2E Testing
  • 28. 28 GOOD OLD TEST PYRAMID Golden Tests Widget Tests (basic) Unit Tests (BLoC) Appium E2E Tests (regular UC) E2E Tests Golden Tests Widget Tests Unit Tests à Datasets from fixtures à Datasets from real or mocked data FLUTTER HEROES – TURIN – 12 March 2025
  • 29. 29 GOLDEN FOR LAYOUT ISSUES Something got wrong here! FLUTTER HEROES – TURIN – 12 March 2025
  • 30. 30 GOLDEN FOR THEMES & SIZES FLUTTER HEROES – TURIN – 12 March 2025
  • 31. 31 GOLDEN FOR ACCESSIBILITY Golden & manual tests in accessibility mode (enableSemanticDebugger) FLUTTER HEROES – TURIN – 12 March 2025 Golden to test old devices 🌱 (+ foldable devices)
  • 32. 32 END-TO-END TESTS FLUTTER HEROES – TURIN – 12 March 2025 (Hot reload! ❤ )
  • 33. 33 SONAR, DCM, FLUTTER PLUGIN, CHECKMARX FLUTTER HEROES – TURIN – 12 March 2025
  • 34. 34 2025 SNAPSHOT 📸 FLUTTER HEROES – TURIN – 12 March 2025 Acceptable compilation time, IDE always reactive ✅ Build 22 minutes Build 21 minutes Acceptable build time on CI ⚠ Including 3k Golden Cut out in 5 jobs Run in ~15m by job (<10m local run) Now 10k Flutter Tests 🚀
  • 35. 35 STORES Where good features go and meet their users 😍 CHAP. 3/6 https://unsplash.com/fr/photos/batiment-de-quatre-etages-avec-escaliers-j-0olYcaihg
  • 37. 37 • 2008: birth of the App Stores • Apple App Store: 500 apps • Android Market (now Google Play Store) • 2009-2012: early growth and expansion • 2013-2016: in-app purchases and subscriptions • 2015: Google Play staff-reviewed app submissions and age-based ratings • 2015: Google Play introduces A/B test experiments A SHORT HISTORY OF STORES Sources : https://galadrim.fr/_astro/Image-blog_copy_2J9mH.webp FLUTTER HEROES – TURIN – 12 March 2025 Source : https://appradar.com/blog/app-stores-history
  • 38. 38 A SHORT HISTORY OF STORES Sources : https://galadrim.fr/_astro/Image-blog_copy_2J9mH.webp • 2017-2020: App Store Optimization • 2017: Apple publishes new rules for the App Store • 2018: Apple tightens requirements for app publication, particularly for VPN applications and user data protection • 2019: Google introduces new policies to improve app quality and security • 2020: Google introduces new policies to enhance app transparency • 2021: Apple introduces App Tracking Transparency (ATT) with iOS 14.5 • Google announced new policies to improve app quality. • Google enforced new policies policy aimed to improve the quality and relevance of app listings. App titles got limited to 30 characters and the use of popular keywords got prohibited • Google introduced custom store listings, enabling developers to create tailored content for different user segments FLUTTER HEROES – TURIN – 12 March 2025 Source : https://appradar.com/blog/app-stores-history
  • 39. 39 A SHORT HISTORY OF STORES Sources : https://galadrim.fr/_astro/Image-blog_copy_2J9mH.webp • 2022: • Apple blocked 1.7 million applications from being published on the App Store due to privacy, security, and content standards violations • Google launches the Data Safety section • Google introduced up to 50 Custom Store Listings to create personalized pages for different audience segments • 2023: • Apple announces new guidelines for app submissions • Google introduces new policies to enhance app security • Google improved custom store listings, allowing developers to create tailored content for different user segments • 2024: • Apple allowed third-party app stores on iPhones and iPads for the first time FLUTTER HEROES – TURIN – 12 March 2025 Source : https://appradar.com/blog/app-stores-history
  • 40. 40 App stores have become huge marketplaces with more and more personalization and rules, with changes happening almost on a weekly basis. FLUTTER HEROES – TURIN – 12 March 2025 Sources : https://unsplash.com/fr/photos/cables-electriques-assortis-l090uFWoPaI
  • 43. 44 ROLLOUT STRATEGIES Sources : https://galadrim.fr/_astro/Image-blog_copy_2J9mH.webp Deployment increment options (Android): • Per 1% • Per 20% • 100% (99% = halt still possible!) FLUTTER HEROES – TURIN – 12 March 2025
  • 44. 45 APP STORE & TESTFLIGHT Sources : https://fr.goodbarber.com/blog/comment-tester-mon-application-avec-testflight-a782/ FLUTTER HEROES – TURIN – 12 March 2025
  • 45. 46 OTHER PARAMETERS Sources : https://galadrim.fr/_astro/Image-blog_copy_2J9mH.webp Forced update, or flexible update with custom modal, or Play Store-managed (but try keep access to vitals) Code Freeze for Commercial Events Low risked VS high risked Analysis in working hours ! (« Prod’ Captain » role) FLUTTER HEROES – TURIN – 12 March 2025
  • 46. 47 STORES SIGNATURES MODES: ANDROID Sources : https://fr.goodbarber.com/blog/comment-tester-mon-application-avec-testflight-a782/ FLUTTER HEROES – TURIN – 12 March 2025
  • 47. 48 STORES SIGNATURES MODES: IOS Sources : https://fr.goodbarber.com/blog/comment-tester-mon-application-avec-testflight-a782/ Apple Pay FLUTTER HEROES – TURIN – 12 March 2025
  • 48. 49 STORES ADDITIONAL SECURITIES Play Integrity API: provides info about request/origin Auto-protection: prevents from modified APK App signature options Play Store visibility: hide Play Store from malicious devices FLUTTER HEROES – TURIN – 12 March 2025
  • 49. 50 FLUTTER HEROES – TURIN – 12 March 2025 https://docs.flutter.dev/deployment/cd
  • 50. 51 FLUTTER HEROES – TURIN – 12 March 2025 desc "Submit a new Store Build to PlayStore" lane :upload_to_playstore do |options| aab_path = "../build/app/outputs/bundle/#{options[:build_mode]}/app-#{options[:build_mode]}.aab" upload_to_play_store( aab: aab_path, track: 'alpha’ | 'rollout’, rollout: ‘0.5’ ) end desc "Submit a new Store Build to Testflight" lane :upload_to_appstore do |options| ipa_name = options[:ipa_name] ipa_path = "../build/ios/ipa/#{ipa_name}.ipa" testflight( api_key: get_api_key, skip_submission: true, ipa: ipa_path ) end
  • 52. 53 GOING BETA Progressive release or rollout to specific user groups Photo : https://unsplash.com/fr/photos/les-pieds-dune-personne-sur-une-surface-en-bois-avec-un-signe-XS_o-Iuf9Go CHAP. 4/6
  • 53. 54 ALPHA, BETA RELEASE AND BETA MODE Android Channels FLUTTER HEROES – TURIN – 12 March 2025
  • 54. 55 ALPHA, BETA RELEASE AND BETA MODE iOS FLUTTER HEROES – TURIN – 12 March 2025
  • 55. 56 CUSTOM BETA MODE (FEATURES FOR BETA TESTERS ONLY) Database AWS DynamoDB: • Global FT Value • Beta override Client ID Value Back-For-Front BFF Rules: • isBetaClient • ftEnabled • ftOverrides Flutter App Dart SDK: • Features loaded from BFF • Features stored locally for session (consistency) FLUTTER HEROES – TURIN – 12 March 2025 Exclusive « beta » mode, available only for community users: • Community program at https://www.vous.sncf-connect.com/ • Direct feedback from beta testers
  • 56. 57 SHOREBIRD CodePush instant updates for Flutter Photo : https://unsplash.com/fr/photos/un-petit-oiseau-assis-au-sommet-dune-plante-pres-de-locean-w3m0oRA0UNA CHAP. 5/6
  • 57. 58 WHY SHOREBIRD? FLUTTER HEROES – TURIN – 12 March 2025
  • 58. 59 SHOREBIRD: CODEPUSH FOR FLUTTER FLUTTER HEROES – TURIN – 12 March 2025 Photo : https://medium.com/@mabud_alam/code-push-for-flutter-update-your-app-without-a-new-release-using-shorebird-b6f4de672481
  • 59. 60 A FLUTTER FORK FOR COMPLIANCE FLUTTER HEROES – TURIN – 12 March 2025
  • 60. 61 HOW IT WORKS SHOREBIRD SERVER MOBILE APP Original Dart Bundle Shorebird Dart Bundle Patch ? DOWNLOAD CUSTOM BOOT SHOREBIRD UPDATER FLUTTER HEROES – TURIN – 12 March 2025
  • 61. 62 BUILD, (STAGE,) PUBLISH, PROMOTE FLUTTER HEROES – TURIN – 12 March 2025
  • 62. 63 FLUTTER MOBILE APP PLAY STORY IN-APP UPGRADE SHOREBIRD PATCH FLUTTER HEROES – TURIN – 12 March 2025 🤔 INTERACTION WITH OTHER UPDATES
  • 63. 64 Android open source docker image https://github.com/sncf-connect-tech/shorebird-docker/blob/main/Dockerfile-shorebird-android iOS open source MacStadium https://github.com/sncf-connect-tech/shorebird-macstadium FLUTTER HEROES – TURIN – 12 March 2025 SHOREBIRD IN GITLAB-CI
  • 64. 65 GREAT TOOL FOR YOU? FLUTTER HEROES – TURIN – 12 March 2025 Push patches instantly 😍 way faster than deploying to Stores instant fixes make users happy! Size overhead 🕵 our measure for our full APK: Without Shorebird 108.1MB Shorebird without the package shorebird_code_push 114MB Complexity overhead 🧐 mix Shorebird with other mecanisms? complexity OK for you / Ops? Fork of Flutter Costs 💰 Store compliance? ⚠ Can’t patch native code
  • 65. 66 FEATURE FLAGS And « Progressive Delivery » Photo : https://unsplash.com/fr/photos/feux-de-circulation-a-cote-des-arbres-OcpN5K0TwKo CHAP. 6/6
  • 66. 67 EARLY 2024… • A major release (50-100 stories) deployed to stores each week • 1-day branching to test the release in isolation • 3-day regression testing before deploying to production • Android/iOS stores rollout from 24h to 1w • Mobile vs. Web different release times FLUTTER HEROES – TURIN – 12 March 2025
  • 67. 68 We need Speed to release more than once a week Source : https://unsplash.com/fr/photos/time-lapse-des-lampadaires--Vqn2WrfxTQ FLUTTER HEROES – TURIN – 12 March 2025
  • 68. 69 We need Safety to go faster to production Source : https://unsplash.com/fr/photos/photographie-en-accelere-des-lumieres-de-la-ville-la-nuit-SUi9mYSVTyc FLUTTER HEROES – TURIN – 12 March 2025
  • 69. 70 Regular Toggles Long-lived toggles acting as circuit breakers to disable a major feature or partner integration in case of emergency. Activation Toggles A/B Testing Variants A NEW KIND OF TOGGLES Short-lived toggles enabling or disabling a recent change of code. Always deployed as disabled. Recycled as soon as production has proven stable. Values and String variants used to perform temporary product experiments with various segments of users. FLUTTER HEROES – TURIN – 12 March 2025 💡
  • 70. 71 ACTIVATION TOGGLES • Introducing Activation Toggles for every (eligible) change being a feature or a fix! • Any change is tested enabled and disabled, and goes disabled to production • Activation is decoupled from deployment • After some time in production, the toggle is cleaned up FLUTTER HEROES – TURIN – 12 March 2025 Source : https://unsplash.com/fr/photos/un-panneau-dextincteur-rouge-et-blanc-sur-un-mur-de-beton-kPoSgf_cjTk
  • 71. class FeatureToggleGuard extends AutoRouteGuard 72 CUSTOM IMPLEMENTATION FT SDK API Local storage FT Cubit FT Guard FLUTTER HEROES – TURIN – 12 March 2025
  • 72. 73 CUSTOM IMPLEMENTATION class FeatureToggleCubit extends Cubit<FeatureToggleV2State> { static const _initializationTimeout = Duration(seconds: 5); final FeatureToggleSdk _featuresSdk; late final StreamSubscription<Map<String, String>?> _featuresSubscription; FeatureToggleCubit({FeatureToggleSdk? providedSdk}) : _featuresSdk = providedSdk ?? locator<Sdk>().featureToggle, super(const InitState()) { _featuresSubscription = _featuresSdk.featuresStreamV2.listen( (features) { emit(BuiltMap<String, String>.from(features).toState()); }, ); } FLUTTER HEROES – TURIN – 12 March 2025
  • 73. 74 CUSTOM IMPLEMENTATION /// Returns true if the feature toggle is explicitly set to [FeatureState.enabled] bool isFeatureEnabled(String feature) => state.withValue((value) => value[feature] == FeatureState.enabled || (defaultTargetPlatform == TargetPlatform.iOS && value[feature] == FeatureState.iOsOnly) || (defaultTargetPlatform == TargetPlatform.android && value[feature] == FeatureState.androidOnly)) ?? false; void updateStatus({bool withCache = true}) { _featuresSdk.loadFeatureToggleStatuses(withCache: withCache); } Future<bool> isFeatureEnabledAsync(String feature) async { try { await waitEndFetching(includeActual: true).timeout(_initializationTimeout); return isFeatureEnabled(feature); } on TimeoutException { FLUTTER HEROES – TURIN – 12 March 2025
  • 74. 75 CUSTOM TOOLS FLUTTER HEROES – TURIN – 12 March 2025
  • 75. 76 OUTCOMES • 100s of temporary activation FTs currently in production • In 2024 we moved from 1 to 3+ deploys per week (Web, Backend, Infra) • Some stories take 2 days from to prod • Still 1 Stores publish per week… but features are released more continuously • ⚠ First seen as a burden for devs… …even if less rollbacks in production and many incidents solved instantly FLUTTER HEROES – TURIN – 12 March 2025
  • 76. 77 We need Tools! to manage 100s of Feature Flags Source : https://unsplash.com/fr/photos/un-groupe-de-cles-disposees-en-cercle-iuuJC_pjLU0 FLUTTER HEROES – TURIN – 12 March 2025
  • 77. 78 FIREBASE • Firebase Remote Config • Release Info • Custom Keys Limit ⚠ FLUTTER HEROES – TURIN – 12 March 2025
  • 78. 79 FEATURE MANAGEMENT TOOLS FLUTTER HEROES – TURIN – 12 March 2025
  • 79. 80 A STANDARD FOR FEATURE FLAGS https://openfeature.dev/ FLUTTER HEROES – TURIN – 12 March 2025
  • 80. 81 LAUNCHDARKLY • Feature Management platform, handling booleans/toggles as well as variations (String) • User Interface to create, configure and monitor Feature Flags • SDK implementations to integrate Flags with various languages and platforms • + API + CLI + Intellij + VSCode + Copilot FLUTTER HEROES – TURIN – 12 March 2025 Source : https://launchdarkly.com/blog/new-and-improved-launchdarkly-platform-experience/
  • 81. 82 POLYGLOT SDK (OPENFEATURE + CUSTOM) Future<void> init() async { final correlationId = await _storageSdk.getCorrelationId() ?? 'Unknown'; final config = LDConfig( CredentialSource.fromEnvironment(), AutoEnvAttributes.enabled, ); final context = LDContextBuilder().kind("correlationId", correlationId).build(); client = LDClient(config, context); await client!.start().timeout(const Duration(seconds: 1)); } Future<bool> isFeatureEnabled(String feature) async { final featureState = await client?.boolVariation(feature, false) ?? false; DatadogSdk.instance.rum?.addFeatureFlagEvaluation(feature, featureState); return featureState; } FLUTTER HEROES – TURIN – 12 March 2025
  • 82. 83 MANAGE FLAGS BY ENVIRONMENTS FLUTTER HEROES – TURIN – 12 March 2025 Source : https://launchdarkly.com/blog/new-and-improved-launchdarkly-platform-experience/
  • 83. 84 DEFINE RULES, WORKFLOWS & PIPELINES FLUTTER HEROES – TURIN – 12 March 2025 Source : https://launchdarkly.com/docs/home/releases/release-pipelines-create
  • 85. 86 INTEGRATING WITH MONITORING FLUTTER HEROES – TURIN – 12 March 2025
  • 86. 87 AUTOMATIC ROLLOUT (LEVERAGING METRICS) FLUTTER HEROES – TURIN – 12 March 2025 Source : https://launchdarkly.com/docs/home/releases/releasing
  • 87. 88 AUTOMATIC ROLLOUT (LEVERAGING METRICS) FLUTTER HEROES – TURIN – 12 March 2025 Source : https://launchdarkly.com/docs/home/releases/releasing
  • 88. 89 Further with Feature Flags From Continuous to Progressive Delivery Source : https://unsplash.com/fr/photos/une-voie-ferree-avec-le-soleil-couchant-en-arriere-plan-orossXHCgtE FLUTTER HEROES – TURIN – 12 March 2025
  • 89. 90 PERSONALIZATION++ Serving features by… • Environments • App versions • Device types • User segments or individuals • User context / profile / preferences? • Region? Weather? Anything…? • (ML / AI?... 🤖) FLUTTER HEROES – TURIN – 12 March 2025
  • 90. 92 « PROGRESSIVE DELIVERY » Continuous Delivery Progressive Delivery Focused on deployments Focused on features Releasing bundles Releasing features Emphasis on target environments Emphasis on users « All-or-nothing » rollout or rollback Features decoupled from each other Business and DevOps teams work together to deploy to production at the ideal time (for the teams / for the users) DevOps teams push code to production (continuously), while the business can decide on when to release each feature to each group of users FLUTTER HEROES – TURIN – 12 March 2025 Source : https://launchdarkly.com/blog/new-and-improved-launchdarkly-platform-experience/
  • 91. 93 Best time to push an update? (Best time for who?) Source : https://unsplash.com/fr/photos/homme-en-veste-bleue-et-pantalon-noir-roulant-sur-un-velo-noir-sur-une-route-en-beton-gris-pendant-bj_9ArBKtRM FLUTTER HEROES – TURIN – 12 March 2025
  • 92. 94 Would you push changes to the UI now? What « bad timing » means depends on your use case) Source : https://unsplash.com/fr/photos/une-voie-ferree-avec-le-soleil-couchant-en-arriere-plan-orossXHCgtE FLUTTER HEROES – TURIN – 12 March 2025
  • 93. 95 A better time to release your brand-new feature? Knowing your users remains essential Source : https://unsplash.com/fr/photos/une-femme-assise-sur-un-canape-dans-un-salon-KkXVoSECjCM FLUTTER HEROES – TURIN – 12 March 2025
  • 94. 96 CONCLUSION « It’s a Wrap » 😉 Photo : https://unsplash.com/fr/photos/un-groupe-de-pieces-dans-une-tasse-yA9guldcm54
  • 95. 97 FLUTTER HEROES – TURIN – 12 March 2025 ⚡ CD & DORA: faster & safer 👷 Automate everything 🚀 Lots of available options to release Stores options, beta channels, rollout strategies, CodePush, Feature Flags & more 😍 Beyond code deploys: Progressive Delivery A JOURNEY TO CONTINUOUS DELIVERY (FOR MOBILE)
  • 96. 98 FLUTTER HEROES – TURIN – 12 March 2025 E2E Testing with Flutter Widget Testing with Flutter Accessibility Testing with Flutter Devoxx France Flutter Heroes Flutter Connection
  • 97. 99 FLUTTER HEROES – TURIN – 12 March 2025