From ed3fbe903840cf4fcda50a7956686be16d113a2b Mon Sep 17 00:00:00 2001 From: dawn-ducky Date: Fri, 6 Feb 2026 09:21:54 -0600 Subject: [PATCH 1/3] docs: Create Flutter for Beginners tutorial with Shorebird Add a comprehensive guide for beginners to create their first Flutter app using Shorebird, covering installation, project structure, and OTA updates. --- .../flutter-for-beginners.mdx | 300 ++++++++++++++++++ 1 file changed, 300 insertions(+) create mode 100644 src/content/docs/flutter-concepts/flutter-for-beginners.mdx diff --git a/src/content/docs/flutter-concepts/flutter-for-beginners.mdx b/src/content/docs/flutter-concepts/flutter-for-beginners.mdx new file mode 100644 index 00000000..56ace452 --- /dev/null +++ b/src/content/docs/flutter-concepts/flutter-for-beginners.mdx @@ -0,0 +1,300 @@ +--- +title: Flutter for Beginners +description: Your First App in 30 Minutes +sidebar: + order: 3 +--- +import { Image } from 'astro:assets'; +import patches from '~/assets/patches.png'; +import rollback from '~/assets/rollback.png'; + +The traditional Flutter development workflow has a significant gap: you build an app, ship it to the app stores, and then wait days or weeks for approval whenever you need to push a fix. Shorebird eliminates this friction by enabling over-the-air (OTA) [code push updates](https://docs.shorebird.dev/code-push/) for Flutter apps. + +With the `shorebird create` command, you can now scaffold production-ready Flutter projects that support instant updates from the very first line of code. This tutorial walks you through the entire workflow, from installation to your first release, while covering Flutter fundamentals along the way. + +## Prerequisite: Installing the Shorebird CLI + +Before creating your first project, you'll need the Shorebird command-line interface. The installation process differs slightly by operating system, but remains straightforward on all platforms. + +**For macOS and Linux**, open your terminal and run: + +```bash +curl --proto '=https' --tlsv1.2 https://raw.githubusercontent.com/shorebirdtech/install/main/install.sh -sSf | bash +``` + +**For Windows**, open PowerShell and execute: + +```powershell +Set-ExecutionPolicy RemoteSigned -scope CurrentUser +iwr -UseBasicParsing 'https://raw.githubusercontent.com/shorebirdtech/install/main/install.ps1'|iex +``` + +These commands download Shorebird to `~/.shorebird/bin`, including a modified [Flutter engine](https://github.com/shorebirdtech/flutter/tree/shorebird/dev/engine) that enables code push capabilities. This modified Flutter lives inside Shorebird's cache and won't interfere with your existing Flutter installation. You continue using your normal [Flutter SDK](https://docs.flutter.dev/get-started/install) for development. + +After installation, you can verify everything works by running `shorebird --version` and then authenticate with `shorebird login`. This opens your browser to create a free Shorebird account or sign into an existing one. + +## Step 1: Creating your first OTA-enabled Flutter app + +Here's where [`shorebird create`](https://docs.shorebird.dev/code-push/create/) shines. Instead of running `flutter create` and manually configuring Shorebird later, this single command handles everything: + +```bash +shorebird create my_flutter_app +``` + +Under the hood, `shorebird create` performs two operations automatically. First, it runs `flutter create` to scaffold a standard Flutter project with the familiar counter app template. Second, it runs [`shorebird init`](https://docs.shorebird.dev/code-push/initialize/) to configure your project for OTA updates and register it with Shorebird's cloud infrastructure. + +> You might be prompted to log in using `shorebird login` if you are running the Shorebird CLI for the first time. + +The command generates a unique `app_id` (like `8c846e87-1461-4b09-8708-170d78331aca`) that identifies your app in Shorebird's system. This ID determines which patches get delivered to which apps. You can think of it as your app's fingerprint in the Shorebird ecosystem. [The `app_id` is not secret](https://docs.shorebird.dev/code-push/faq/#do-i-need-to-keep-my-app_id-secret) and should be committed to version control. + +Beyond the standard Flutter files, `shorebird create` adds or modifies these files: +* **shorebird.yaml**: A new configuration file in your project root containing your `app_id` +* **pubspec.yaml**: Updated to include `shorebird.yaml` in the assets section +* **AndroidManifest.xml**: Updated to include INTERNET permission (required for downloading patches) + +## Step 2: Understanding your Flutter project structure + +Whether you use `shorebird create` or `flutter create`, the resulting project follows Flutter's standard directory layout. Understanding this structure is essential for productive development. + +The **lib/** folder contains all your [Dart](https://dart.dev/) code. The entry point is **lib/main.dart**, which houses the `main()` function that calls `runApp()` with your root widget. As your app grows, you'll organize screens, widgets, and business logic into subdirectories within **lib/**. + +The **android/** folder holds Android-specific configuration, including Gradle build files and **AndroidManifest.xml**. Unless you're integrating native Android code or configuring platform-specific settings, you'll rarely need to edit files here directly. + +The **ios/** folder mirrors this for Apple mobile platforms, containing the Xcode workspace and iOS project files. Platform-specific configuration like `Info.plist` lives here, and you'll visit this directory when configuring iOS-specific capabilities or signing certificates. + +The **pubspec.yaml** file at the project root is arguably the most important configuration file. It defines your app's name, version, dependencies, and assets. When Shorebird creates or initializes a project, it adds **shorebird.yaml** to the assets list here, ensuring the configuration file gets bundled with your app: + +```yaml +flutter: + uses-material-design: true + assets: + - shorebird.yaml +``` + +## Step 3: Understanding Flutter's widget tree + +Flutter builds user interfaces through a hierarchical tree of widgets; everything is a widget. You compose simple widgets into complex UIs by nesting them as children of other widgets. A typical app structure uses four fundamental widgets that form the visual backbone: +* **Scaffold** provides the [Material Design](https://m3.material.io/) layout structure, acting as a container for your app's major visual elements. It exposes properties for the app bar, body content, floating action buttons, drawers, and bottom navigation. +* **AppBar** creates the top navigation bar. It typically displays a title, optional leading widget (like a menu icon), and trailing action buttons (like search or settings icons). +* **Center** is a layout widget that positions its single child in the middle of the available space. It's commonly used to center content within the Scaffold's body. +* **Text** displays styled text on screen. It's one of the simplest widgets, but one you'll use constantly. + +Here's how these widgets nest together to form a tree: + +```dart +Scaffold( + appBar: AppBar( + title: const Text('My First App'), + ), + body: const Center( + child: Text('Hello, world!'), + ), +) +``` + +This hierarchy, `Scaffold` containing `AppBar` and `Center`, with `Text` nested inside `Center`, demonstrates how Flutter builds UIs through composition rather than inheritance. + +### Stateless widgets versus stateful widgets + +Flutter distinguishes between widgets that never change and widgets that can update dynamically. By treating some widgets as immutable, Flutter can rebuild the UI more efficiently. + + +`StatelessWidget` represents UI that doesn't change based on user interaction. These widgets receive their configuration from parent widgets, store values in `final` variables, and render the same output given the same inputs. You should use `StatelessWidget` for static content like labels, icons, or logos that display the same way regardless of app state. + +Also, when in doubt, start with a `StatelessWidget`. You can always switch to a `StatefulWidget` later if the widget needs to manage its own state or respond to user interaction. + +```dart +class Greeting extends StatelessWidget { + const Greeting({super.key}); + + @override + Widget build(BuildContext context) { + return const Text('Welcome to Flutter!'); + } +} +``` + +`StatefulWidget` manages mutable state. When something needs to change, a counter incrementing, a form field updating, or data loading from an API, you need a StatefulWidget. It creates a companion `State` object that persists across rebuilds and holds the mutable data. + +```dart +class Counter extends StatefulWidget { + const Counter({super.key}); + + @override + State createState() => _CounterState(); +} + +class _CounterState extends State { + int _count = 0; + + void _increment() { + setState(() { + _count++; + }); + } + + @override + Widget build(BuildContext context) { + return ElevatedButton( + onPressed: _increment, + child: Text('Count: \$_count'), + ); + } +} +``` + +The key mechanism is `setState()`. Calling it notifies Flutter that the state has changed and triggers a rebuild of the widget, updating the UI to reflect the new values. + +### Hot reload accelerates your development workflow + +One of Flutter's most celebrated features is *hot reload*, which injects updated code into the running [Dart VM](https://dart.dev/tools/dart-vm) without restarting your app. When you save a file, Flutter recompiles only the changed libraries, sends them to the device, and rebuilds the widget tree, typically in under one second. + +The magic of hot reload is state preservation. Your app remains at the same screen, with the same data loaded, while UI changes appear instantly. You don't need to re-navigate to a deeply nested screen or re-enter form data after every code change. + +To trigger hot reload, simply save your file in VS Code or Android Studio (the IDEs auto-reload by default), or press `r` in the terminal if running via `flutter run`. For changes that affect initialization logic, like modifications to `main()` or `initState()`, use hot restart (press `R`), which restarts the app from scratch while still being faster than a full rebuild. + +Hot reload only works in debug mode. Release builds compile Dart to native code and don't support this feature, which is precisely why Shorebird's code push capability is so valuable for production apps. + +## Step 4: Making your First Change + +At this point, you have a fully working Flutter app with OTA updates wired in. You can try it out by running the following command: + +```bash +flutter run +``` + +Here's what the app will look like on an Android device: + +![Initial app UI on Android](https://i.postimg.cc/x1ZmgsSj/Whats-App-Image-2026-01-21-at-14-29-22.jpg) + +Before shipping anything, let’s make a small but visible change so you can see how Flutter’s UI responds to code edits. We’ll tweak the app’s theme color and update some on-screen text. + +Open **lib/main.dart** in your editor. Near the top of the file, you’ll find the `MaterialApp` widget. This is where global application settings live, including theming. + +Look for the `theme` property. By default, it will look something like this: + +```dart +theme: ThemeData( + colorScheme: .fromSeed(seedColor: Colors.deepPurple), +), +``` + +Change the `primarySwatch` to a different color, for example, `Colors.deepPurple`: + +```dart +theme: ThemeData( + colorScheme: .fromSeed(seedColor: Colors.blue), +), +``` + +This single change updates the color used by Material components such as the app bar, buttons, and highlights across the entire app. Flutter’s theming system works top-down, so modifying the theme here affects every widget below it in the tree. + +Next, scroll down to the widget that renders text on the screen. In the default counter app, you’ll see a `Text` widget inside the `body` of a `Scaffold`. It might look similar to this: + +```dart +const Text( + 'You have pushed the button this many times:', +), +``` + +Replace the string with something custom: + +```dart +const Text( + 'Welcome to my first OTA-enabled Flutter app!', +), +``` + +Save the file and run the app using: + +```bash +flutter run +``` + +Within seconds, you should see the updated theme color and new text reflected in the UI: + +![Updated app UI on Android](https://i.postimg.cc/RZYtGPzv/Whats-App-Image-2026-01-21-at-14-29-22-(1).jpg) + +This fast feedback loop is one of Flutter’s biggest strengths. You edit Dart code, the framework rebuilds the widget tree, and the changes appear immediately. + +In the next step, we’ll take this simple customization further by preparing the app for its first Shorebird-powered release, setting the stage for OTA updates that go beyond local development. + +## Step 5: From development to release with Shorebird + +Once your app is ready for users, Shorebird provides commands to build, preview, and distribute your releases. + +**Creating a release** captures a snapshot of your compiled code that Shorebird stores in the cloud. This becomes the baseline for future patches: +```bash +shorebird release android # Creates an Android release (.aab) +shorebird release ios # Creates an iOS release (.ipa) +``` + +The [`shorebird release`](https://docs.shorebird.dev/code-push/release/) command builds your app using Shorebird's modified Flutter engine, uploads the compiled Dart code to Shorebird's servers, and outputs the artifacts you'll submit to the app stores. For Android, you get an `.aab` file for the [Play Store](https://docs.shorebird.dev/code-push/guides/stores/play-store/); for iOS, an `.ipa` for [App Store Connect](https://docs.shorebird.dev/code-push/guides/stores/app-store/). + +**Previewing a release** lets you test the exact build that will ship to users: +```bash +➜ my_flutter_app shorebird preview +✓ Fetching releases (0.5s) +✓ Fetching releases (0.5s) +Which release would you like to preview? 1.0.0+1 +✓ Fetching aab artifact (0.4s) +✓ Using stable track (0.7s) +✓ Extracting metadata (1.0s) +✓ Built apks: /Users//.shorebird/bin/cache/previews/dbad83ad-92fd-4228-af9a-014800f6efd7/android_1.0.0+1_1966896.apks (2.9s) +✓ Installing apks (6.0s) +✓ Starting app (1.8s) + +``` + +The [`shorebird preview`](https://docs.shorebird.dev/code-push/preview/) command downloads the release artifacts from Shorebird's cloud and installs them on a connected device or emulator. It's particularly useful for verifying releases built on [CI/CD servers](https://docs.shorebird.dev/code-push/ci/github/) before distributing them to end users. + +After your initial release is live in the stores, you can push instant updates with [`shorebird patch`](https://docs.shorebird.dev/code-push/patch/) whenever you fix bugs or add features, no app store review required. + +For instance, update the theme of the app to use the following: + +``` +theme: ThemeData( + colorScheme: .fromSeed(seedColor: Colors.deepPurple), +), +``` + +Then, run `shorebird patch android`. Once the command completes running, try closing and restarting an installed release of the app. The theme of the app should get updated on a fresh run: + +![Releasing a patch](https://i.postimg.cc/0y393fhD/patch.gif) + +Also, you will be able to view the patch on your Shorebird Console: + +Screenshot of the Shorebird release and patches + + +If needed, you can rollback your patches easily from here: + +Screenshot of rolling back a patch + + +## Conclusion + +Starting a Flutter project with `shorebird create` rather than `flutter create` costs you nothing in terms of development workflow; you still get the same project structure, the same hot reload experience, and the same widget-based UI development. What you gain is the ability to push critical fixes to users in minutes instead of waiting days for app store approval. + +The combination of Shorebird's OTA infrastructure with Flutter's widget composition model and hot reload creates a development experience optimized for rapid iteration at every stage, from first prototype to production maintenance. For any Flutter project that will eventually ship to real users, building in code push capability from day one is simply the pragmatic choice. + +## Next Steps + +Now that you've created your first Shorebird-enabled Flutter project, here are some recommended next steps to deepen your understanding and optimize your workflow: + +**Establish a robust development workflow**: Learn how to integrate Shorebird into your team's development process with the [Development Workflow guide](https://docs.shorebird.dev/code-push/guides/development-workflow/). This covers best practices for testing patches locally, staging updates before production, and coordinating releases across team members. + +**Test patches before releasing to users**: Before pushing updates to production, you should verify they work correctly using the [Testing Patches guide](https://docs.shorebird.dev/code-push/guides/testing-patches/). Learn how to test patches on physical devices, emulators, and with different release versions to catch issues early. + +**Implement staged rollouts for safety**: Minimize risk by gradually rolling out patches to a percentage of users first. The [Percentage-Based Rollouts guide](https://docs.shorebird.dev/code-push/guides/percentage-based-rollouts/) shows you how to deploy patches to 10% of your user base, monitor for issues, and then expand to 100% once you're confident. + +**Integrate with your CI/CD pipeline**: Automate your patch delivery process by integrating Shorebird into your continuous integration system. Whether you use [GitHub Actions](https://docs.shorebird.dev/code-push/ci/github/), [Codemagic](https://docs.shorebird.dev/code-push/ci/codemagic/), or another platform, these guides show you how to automatically create and deploy patches on every merge to main. + +**Understand patch performance characteristics**: Learn how Shorebird optimizes patch delivery and what performance characteristics to expect in the [Patch Performance documentation](https://docs.shorebird.dev/code-push/performance/). This covers patch download sizes, update timing, and strategies to minimize impact on user experience. + From 8af36ab110a075c3b9b4251032b562604b7bcfb8 Mon Sep 17 00:00:00 2001 From: Tom Arra Date: Fri, 6 Feb 2026 09:33:14 -0600 Subject: [PATCH 2/3] formatting --- .../flutter-for-beginners.mdx | 292 +++++++++++++----- 1 file changed, 218 insertions(+), 74 deletions(-) diff --git a/src/content/docs/flutter-concepts/flutter-for-beginners.mdx b/src/content/docs/flutter-concepts/flutter-for-beginners.mdx index 56ace452..c55b7a07 100644 --- a/src/content/docs/flutter-concepts/flutter-for-beginners.mdx +++ b/src/content/docs/flutter-concepts/flutter-for-beginners.mdx @@ -4,17 +4,27 @@ description: Your First App in 30 Minutes sidebar: order: 3 --- + import { Image } from 'astro:assets'; import patches from '~/assets/patches.png'; import rollback from '~/assets/rollback.png'; -The traditional Flutter development workflow has a significant gap: you build an app, ship it to the app stores, and then wait days or weeks for approval whenever you need to push a fix. Shorebird eliminates this friction by enabling over-the-air (OTA) [code push updates](https://docs.shorebird.dev/code-push/) for Flutter apps. +The traditional Flutter development workflow has a significant gap: you build an +app, ship it to the app stores, and then wait days or weeks for approval +whenever you need to push a fix. Shorebird eliminates this friction by enabling +over-the-air (OTA) [code push updates](https://docs.shorebird.dev/code-push/) +for Flutter apps. -With the `shorebird create` command, you can now scaffold production-ready Flutter projects that support instant updates from the very first line of code. This tutorial walks you through the entire workflow, from installation to your first release, while covering Flutter fundamentals along the way. +With the `shorebird create` command, you can now scaffold production-ready +Flutter projects that support instant updates from the very first line of code. +This tutorial walks you through the entire workflow, from installation to your +first release, while covering Flutter fundamentals along the way. ## Prerequisite: Installing the Shorebird CLI -Before creating your first project, you'll need the Shorebird command-line interface. The installation process differs slightly by operating system, but remains straightforward on all platforms. +Before creating your first project, you'll need the Shorebird command-line +interface. The installation process differs slightly by operating system, but +remains straightforward on all platforms. **For macOS and Linux**, open your terminal and run: @@ -29,40 +39,79 @@ Set-ExecutionPolicy RemoteSigned -scope CurrentUser iwr -UseBasicParsing 'https://raw.githubusercontent.com/shorebirdtech/install/main/install.ps1'|iex ``` -These commands download Shorebird to `~/.shorebird/bin`, including a modified [Flutter engine](https://github.com/shorebirdtech/flutter/tree/shorebird/dev/engine) that enables code push capabilities. This modified Flutter lives inside Shorebird's cache and won't interfere with your existing Flutter installation. You continue using your normal [Flutter SDK](https://docs.flutter.dev/get-started/install) for development. +These commands download Shorebird to `~/.shorebird/bin`, including a modified +[Flutter engine](https://github.com/shorebirdtech/flutter/tree/shorebird/dev/engine) +that enables code push capabilities. This modified Flutter lives inside +Shorebird's cache and won't interfere with your existing Flutter installation. +You continue using your normal +[Flutter SDK](https://docs.flutter.dev/get-started/install) for development. -After installation, you can verify everything works by running `shorebird --version` and then authenticate with `shorebird login`. This opens your browser to create a free Shorebird account or sign into an existing one. +After installation, you can verify everything works by running +`shorebird --version` and then authenticate with `shorebird login`. This opens +your browser to create a free Shorebird account or sign into an existing one. ## Step 1: Creating your first OTA-enabled Flutter app -Here's where [`shorebird create`](https://docs.shorebird.dev/code-push/create/) shines. Instead of running `flutter create` and manually configuring Shorebird later, this single command handles everything: +Here's where [`shorebird create`](https://docs.shorebird.dev/code-push/create/) +shines. Instead of running `flutter create` and manually configuring Shorebird +later, this single command handles everything: ```bash shorebird create my_flutter_app ``` -Under the hood, `shorebird create` performs two operations automatically. First, it runs `flutter create` to scaffold a standard Flutter project with the familiar counter app template. Second, it runs [`shorebird init`](https://docs.shorebird.dev/code-push/initialize/) to configure your project for OTA updates and register it with Shorebird's cloud infrastructure. +Under the hood, `shorebird create` performs two operations automatically. First, +it runs `flutter create` to scaffold a standard Flutter project with the +familiar counter app template. Second, it runs +[`shorebird init`](https://docs.shorebird.dev/code-push/initialize/) to +configure your project for OTA updates and register it with Shorebird's cloud +infrastructure. + +> You might be prompted to log in using `shorebird login` if you are running the +> Shorebird CLI for the first time. -> You might be prompted to log in using `shorebird login` if you are running the Shorebird CLI for the first time. +The command generates a unique `app_id` (like +`8c846e87-1461-4b09-8708-170d78331aca`) that identifies your app in Shorebird's +system. This ID determines which patches get delivered to which apps. You can +think of it as your app's fingerprint in the Shorebird ecosystem. +[The `app_id` is not secret](https://docs.shorebird.dev/code-push/faq/#do-i-need-to-keep-my-app_id-secret) +and should be committed to version control. -The command generates a unique `app_id` (like `8c846e87-1461-4b09-8708-170d78331aca`) that identifies your app in Shorebird's system. This ID determines which patches get delivered to which apps. You can think of it as your app's fingerprint in the Shorebird ecosystem. [The `app_id` is not secret](https://docs.shorebird.dev/code-push/faq/#do-i-need-to-keep-my-app_id-secret) and should be committed to version control. +Beyond the standard Flutter files, `shorebird create` adds or modifies these +files: -Beyond the standard Flutter files, `shorebird create` adds or modifies these files: -* **shorebird.yaml**: A new configuration file in your project root containing your `app_id` -* **pubspec.yaml**: Updated to include `shorebird.yaml` in the assets section -* **AndroidManifest.xml**: Updated to include INTERNET permission (required for downloading patches) +- **shorebird.yaml**: A new configuration file in your project root containing + your `app_id` +- **pubspec.yaml**: Updated to include `shorebird.yaml` in the assets section +- **AndroidManifest.xml**: Updated to include INTERNET permission (required for + downloading patches) ## Step 2: Understanding your Flutter project structure -Whether you use `shorebird create` or `flutter create`, the resulting project follows Flutter's standard directory layout. Understanding this structure is essential for productive development. +Whether you use `shorebird create` or `flutter create`, the resulting project +follows Flutter's standard directory layout. Understanding this structure is +essential for productive development. -The **lib/** folder contains all your [Dart](https://dart.dev/) code. The entry point is **lib/main.dart**, which houses the `main()` function that calls `runApp()` with your root widget. As your app grows, you'll organize screens, widgets, and business logic into subdirectories within **lib/**. +The **lib/** folder contains all your [Dart](https://dart.dev/) code. The entry +point is **lib/main.dart**, which houses the `main()` function that calls +`runApp()` with your root widget. As your app grows, you'll organize screens, +widgets, and business logic into subdirectories within **lib/**. -The **android/** folder holds Android-specific configuration, including Gradle build files and **AndroidManifest.xml**. Unless you're integrating native Android code or configuring platform-specific settings, you'll rarely need to edit files here directly. +The **android/** folder holds Android-specific configuration, including Gradle +build files and **AndroidManifest.xml**. Unless you're integrating native +Android code or configuring platform-specific settings, you'll rarely need to +edit files here directly. -The **ios/** folder mirrors this for Apple mobile platforms, containing the Xcode workspace and iOS project files. Platform-specific configuration like `Info.plist` lives here, and you'll visit this directory when configuring iOS-specific capabilities or signing certificates. +The **ios/** folder mirrors this for Apple mobile platforms, containing the +Xcode workspace and iOS project files. Platform-specific configuration like +`Info.plist` lives here, and you'll visit this directory when configuring +iOS-specific capabilities or signing certificates. -The **pubspec.yaml** file at the project root is arguably the most important configuration file. It defines your app's name, version, dependencies, and assets. When Shorebird creates or initializes a project, it adds **shorebird.yaml** to the assets list here, ensuring the configuration file gets bundled with your app: +The **pubspec.yaml** file at the project root is arguably the most important +configuration file. It defines your app's name, version, dependencies, and +assets. When Shorebird creates or initializes a project, it adds +**shorebird.yaml** to the assets list here, ensuring the configuration file gets +bundled with your app: ```yaml flutter: @@ -73,11 +122,23 @@ flutter: ## Step 3: Understanding Flutter's widget tree -Flutter builds user interfaces through a hierarchical tree of widgets; everything is a widget. You compose simple widgets into complex UIs by nesting them as children of other widgets. A typical app structure uses four fundamental widgets that form the visual backbone: -* **Scaffold** provides the [Material Design](https://m3.material.io/) layout structure, acting as a container for your app's major visual elements. It exposes properties for the app bar, body content, floating action buttons, drawers, and bottom navigation. -* **AppBar** creates the top navigation bar. It typically displays a title, optional leading widget (like a menu icon), and trailing action buttons (like search or settings icons). -* **Center** is a layout widget that positions its single child in the middle of the available space. It's commonly used to center content within the Scaffold's body. -* **Text** displays styled text on screen. It's one of the simplest widgets, but one you'll use constantly. +Flutter builds user interfaces through a hierarchical tree of widgets; +everything is a widget. You compose simple widgets into complex UIs by nesting +them as children of other widgets. A typical app structure uses four fundamental +widgets that form the visual backbone: + +- **Scaffold** provides the [Material Design](https://m3.material.io/) layout + structure, acting as a container for your app's major visual elements. It + exposes properties for the app bar, body content, floating action buttons, + drawers, and bottom navigation. +- **AppBar** creates the top navigation bar. It typically displays a title, + optional leading widget (like a menu icon), and trailing action buttons (like + search or settings icons). +- **Center** is a layout widget that positions its single child in the middle of + the available space. It's commonly used to center content within the + Scaffold's body. +- **Text** displays styled text on screen. It's one of the simplest widgets, but + one you'll use constantly. Here's how these widgets nest together to form a tree: @@ -92,16 +153,25 @@ Scaffold( ) ``` -This hierarchy, `Scaffold` containing `AppBar` and `Center`, with `Text` nested inside `Center`, demonstrates how Flutter builds UIs through composition rather than inheritance. +This hierarchy, `Scaffold` containing `AppBar` and `Center`, with `Text` nested +inside `Center`, demonstrates how Flutter builds UIs through composition rather +than inheritance. ### Stateless widgets versus stateful widgets -Flutter distinguishes between widgets that never change and widgets that can update dynamically. By treating some widgets as immutable, Flutter can rebuild the UI more efficiently. +Flutter distinguishes between widgets that never change and widgets that can +update dynamically. By treating some widgets as immutable, Flutter can rebuild +the UI more efficiently. +`StatelessWidget` represents UI that doesn't change based on user interaction. +These widgets receive their configuration from parent widgets, store values in +`final` variables, and render the same output given the same inputs. You should +use `StatelessWidget` for static content like labels, icons, or logos that +display the same way regardless of app state. -`StatelessWidget` represents UI that doesn't change based on user interaction. These widgets receive their configuration from parent widgets, store values in `final` variables, and render the same output given the same inputs. You should use `StatelessWidget` for static content like labels, icons, or logos that display the same way regardless of app state. - -Also, when in doubt, start with a `StatelessWidget`. You can always switch to a `StatefulWidget` later if the widget needs to manage its own state or respond to user interaction. +Also, when in doubt, start with a `StatelessWidget`. You can always switch to a +`StatefulWidget` later if the widget needs to manage its own state or respond to +user interaction. ```dart class Greeting extends StatelessWidget { @@ -114,7 +184,10 @@ class Greeting extends StatelessWidget { } ``` -`StatefulWidget` manages mutable state. When something needs to change, a counter incrementing, a form field updating, or data loading from an API, you need a StatefulWidget. It creates a companion `State` object that persists across rebuilds and holds the mutable data. +`StatefulWidget` manages mutable state. When something needs to change, a +counter incrementing, a form field updating, or data loading from an API, you +need a StatefulWidget. It creates a companion `State` object that persists +across rebuilds and holds the mutable data. ```dart class Counter extends StatefulWidget { @@ -143,21 +216,37 @@ class _CounterState extends State { } ``` -The key mechanism is `setState()`. Calling it notifies Flutter that the state has changed and triggers a rebuild of the widget, updating the UI to reflect the new values. +The key mechanism is `setState()`. Calling it notifies Flutter that the state +has changed and triggers a rebuild of the widget, updating the UI to reflect the +new values. ### Hot reload accelerates your development workflow -One of Flutter's most celebrated features is *hot reload*, which injects updated code into the running [Dart VM](https://dart.dev/tools/dart-vm) without restarting your app. When you save a file, Flutter recompiles only the changed libraries, sends them to the device, and rebuilds the widget tree, typically in under one second. +One of Flutter's most celebrated features is _hot reload_, which injects updated +code into the running [Dart VM](https://dart.dev/tools/dart-vm) without +restarting your app. When you save a file, Flutter recompiles only the changed +libraries, sends them to the device, and rebuilds the widget tree, typically in +under one second. -The magic of hot reload is state preservation. Your app remains at the same screen, with the same data loaded, while UI changes appear instantly. You don't need to re-navigate to a deeply nested screen or re-enter form data after every code change. +The magic of hot reload is state preservation. Your app remains at the same +screen, with the same data loaded, while UI changes appear instantly. You don't +need to re-navigate to a deeply nested screen or re-enter form data after every +code change. -To trigger hot reload, simply save your file in VS Code or Android Studio (the IDEs auto-reload by default), or press `r` in the terminal if running via `flutter run`. For changes that affect initialization logic, like modifications to `main()` or `initState()`, use hot restart (press `R`), which restarts the app from scratch while still being faster than a full rebuild. +To trigger hot reload, simply save your file in VS Code or Android Studio (the +IDEs auto-reload by default), or press `r` in the terminal if running via +`flutter run`. For changes that affect initialization logic, like modifications +to `main()` or `initState()`, use hot restart (press `R`), which restarts the +app from scratch while still being faster than a full rebuild. -Hot reload only works in debug mode. Release builds compile Dart to native code and don't support this feature, which is precisely why Shorebird's code push capability is so valuable for production apps. +Hot reload only works in debug mode. Release builds compile Dart to native code +and don't support this feature, which is precisely why Shorebird's code push +capability is so valuable for production apps. ## Step 4: Making your First Change -At this point, you have a fully working Flutter app with OTA updates wired in. You can try it out by running the following command: +At this point, you have a fully working Flutter app with OTA updates wired in. +You can try it out by running the following command: ```bash flutter run @@ -167,9 +256,13 @@ Here's what the app will look like on an Android device: ![Initial app UI on Android](https://i.postimg.cc/x1ZmgsSj/Whats-App-Image-2026-01-21-at-14-29-22.jpg) -Before shipping anything, let’s make a small but visible change so you can see how Flutter’s UI responds to code edits. We’ll tweak the app’s theme color and update some on-screen text. +Before shipping anything, let’s make a small but visible change so you can see +how Flutter’s UI responds to code edits. We’ll tweak the app’s theme color and +update some on-screen text. -Open **lib/main.dart** in your editor. Near the top of the file, you’ll find the `MaterialApp` widget. This is where global application settings live, including theming. +Open **lib/main.dart** in your editor. Near the top of the file, you’ll find the +`MaterialApp` widget. This is where global application settings live, including +theming. Look for the `theme` property. By default, it will look something like this: @@ -179,7 +272,8 @@ theme: ThemeData( ), ``` -Change the `primarySwatch` to a different color, for example, `Colors.deepPurple`: +Change the `primarySwatch` to a different color, for example, +`Colors.deepPurple`: ```dart theme: ThemeData( @@ -187,9 +281,14 @@ theme: ThemeData( ), ``` -This single change updates the color used by Material components such as the app bar, buttons, and highlights across the entire app. Flutter’s theming system works top-down, so modifying the theme here affects every widget below it in the tree. +This single change updates the color used by Material components such as the app +bar, buttons, and highlights across the entire app. Flutter’s theming system +works top-down, so modifying the theme here affects every widget below it in the +tree. -Next, scroll down to the widget that renders text on the screen. In the default counter app, you’ll see a `Text` widget inside the `body` of a `Scaffold`. It might look similar to this: +Next, scroll down to the widget that renders text on the screen. In the default +counter app, you’ll see a `Text` widget inside the `body` of a `Scaffold`. It +might look similar to this: ```dart const Text( @@ -211,27 +310,42 @@ Save the file and run the app using: flutter run ``` -Within seconds, you should see the updated theme color and new text reflected in the UI: +Within seconds, you should see the updated theme color and new text reflected in +the UI: -![Updated app UI on Android](https://i.postimg.cc/RZYtGPzv/Whats-App-Image-2026-01-21-at-14-29-22-(1).jpg) +![Updated app UI on Android]() -This fast feedback loop is one of Flutter’s biggest strengths. You edit Dart code, the framework rebuilds the widget tree, and the changes appear immediately. +This fast feedback loop is one of Flutter’s biggest strengths. You edit Dart +code, the framework rebuilds the widget tree, and the changes appear +immediately. -In the next step, we’ll take this simple customization further by preparing the app for its first Shorebird-powered release, setting the stage for OTA updates that go beyond local development. +In the next step, we’ll take this simple customization further by preparing the +app for its first Shorebird-powered release, setting the stage for OTA updates +that go beyond local development. ## Step 5: From development to release with Shorebird -Once your app is ready for users, Shorebird provides commands to build, preview, and distribute your releases. +Once your app is ready for users, Shorebird provides commands to build, preview, +and distribute your releases. + +**Creating a release** captures a snapshot of your compiled code that Shorebird +stores in the cloud. This becomes the baseline for future patches: -**Creating a release** captures a snapshot of your compiled code that Shorebird stores in the cloud. This becomes the baseline for future patches: ```bash shorebird release android # Creates an Android release (.aab) shorebird release ios # Creates an iOS release (.ipa) ``` -The [`shorebird release`](https://docs.shorebird.dev/code-push/release/) command builds your app using Shorebird's modified Flutter engine, uploads the compiled Dart code to Shorebird's servers, and outputs the artifacts you'll submit to the app stores. For Android, you get an `.aab` file for the [Play Store](https://docs.shorebird.dev/code-push/guides/stores/play-store/); for iOS, an `.ipa` for [App Store Connect](https://docs.shorebird.dev/code-push/guides/stores/app-store/). +The [`shorebird release`](https://docs.shorebird.dev/code-push/release/) command +builds your app using Shorebird's modified Flutter engine, uploads the compiled +Dart code to Shorebird's servers, and outputs the artifacts you'll submit to the +app stores. For Android, you get an `.aab` file for the +[Play Store](https://docs.shorebird.dev/code-push/guides/stores/play-store/); +for iOS, an `.ipa` for +[App Store Connect](https://docs.shorebird.dev/code-push/guides/stores/app-store/). **Previewing a release** lets you test the exact build that will ship to users: + ```bash ➜ my_flutter_app shorebird preview ✓ Fetching releases (0.5s) @@ -246,9 +360,15 @@ Which release would you like to preview? 1.0.0+1 ``` -The [`shorebird preview`](https://docs.shorebird.dev/code-push/preview/) command downloads the release artifacts from Shorebird's cloud and installs them on a connected device or emulator. It's particularly useful for verifying releases built on [CI/CD servers](https://docs.shorebird.dev/code-push/ci/github/) before distributing them to end users. +The [`shorebird preview`](https://docs.shorebird.dev/code-push/preview/) command +downloads the release artifacts from Shorebird's cloud and installs them on a +connected device or emulator. It's particularly useful for verifying releases +built on [CI/CD servers](https://docs.shorebird.dev/code-push/ci/github/) before +distributing them to end users. -After your initial release is live in the stores, you can push instant updates with [`shorebird patch`](https://docs.shorebird.dev/code-push/patch/) whenever you fix bugs or add features, no app store review required. +After your initial release is live in the stores, you can push instant updates +with [`shorebird patch`](https://docs.shorebird.dev/code-push/patch/) whenever +you fix bugs or add features, no app store review required. For instance, update the theme of the app to use the following: @@ -258,43 +378,67 @@ theme: ThemeData( ), ``` -Then, run `shorebird patch android`. Once the command completes running, try closing and restarting an installed release of the app. The theme of the app should get updated on a fresh run: +Then, run `shorebird patch android`. Once the command completes running, try +closing and restarting an installed release of the app. The theme of the app +should get updated on a fresh run: ![Releasing a patch](https://i.postimg.cc/0y393fhD/patch.gif) Also, you will be able to view the patch on your Shorebird Console: -Screenshot of the Shorebird release and patches - +Screenshot of the Shorebird release and patches If needed, you can rollback your patches easily from here: -Screenshot of rolling back a patch - +Screenshot of rolling back a patch ## Conclusion -Starting a Flutter project with `shorebird create` rather than `flutter create` costs you nothing in terms of development workflow; you still get the same project structure, the same hot reload experience, and the same widget-based UI development. What you gain is the ability to push critical fixes to users in minutes instead of waiting days for app store approval. +Starting a Flutter project with `shorebird create` rather than `flutter create` +costs you nothing in terms of development workflow; you still get the same +project structure, the same hot reload experience, and the same widget-based UI +development. What you gain is the ability to push critical fixes to users in +minutes instead of waiting days for app store approval. -The combination of Shorebird's OTA infrastructure with Flutter's widget composition model and hot reload creates a development experience optimized for rapid iteration at every stage, from first prototype to production maintenance. For any Flutter project that will eventually ship to real users, building in code push capability from day one is simply the pragmatic choice. +The combination of Shorebird's OTA infrastructure with Flutter's widget +composition model and hot reload creates a development experience optimized for +rapid iteration at every stage, from first prototype to production maintenance. +For any Flutter project that will eventually ship to real users, building in +code push capability from day one is simply the pragmatic choice. ## Next Steps -Now that you've created your first Shorebird-enabled Flutter project, here are some recommended next steps to deepen your understanding and optimize your workflow: - -**Establish a robust development workflow**: Learn how to integrate Shorebird into your team's development process with the [Development Workflow guide](https://docs.shorebird.dev/code-push/guides/development-workflow/). This covers best practices for testing patches locally, staging updates before production, and coordinating releases across team members. - -**Test patches before releasing to users**: Before pushing updates to production, you should verify they work correctly using the [Testing Patches guide](https://docs.shorebird.dev/code-push/guides/testing-patches/). Learn how to test patches on physical devices, emulators, and with different release versions to catch issues early. - -**Implement staged rollouts for safety**: Minimize risk by gradually rolling out patches to a percentage of users first. The [Percentage-Based Rollouts guide](https://docs.shorebird.dev/code-push/guides/percentage-based-rollouts/) shows you how to deploy patches to 10% of your user base, monitor for issues, and then expand to 100% once you're confident. - -**Integrate with your CI/CD pipeline**: Automate your patch delivery process by integrating Shorebird into your continuous integration system. Whether you use [GitHub Actions](https://docs.shorebird.dev/code-push/ci/github/), [Codemagic](https://docs.shorebird.dev/code-push/ci/codemagic/), or another platform, these guides show you how to automatically create and deploy patches on every merge to main. - -**Understand patch performance characteristics**: Learn how Shorebird optimizes patch delivery and what performance characteristics to expect in the [Patch Performance documentation](https://docs.shorebird.dev/code-push/performance/). This covers patch download sizes, update timing, and strategies to minimize impact on user experience. - +Now that you've created your first Shorebird-enabled Flutter project, here are +some recommended next steps to deepen your understanding and optimize your +workflow: + +**Establish a robust development workflow**: Learn how to integrate Shorebird +into your team's development process with the +[Development Workflow guide](https://docs.shorebird.dev/code-push/guides/development-workflow/). +This covers best practices for testing patches locally, staging updates before +production, and coordinating releases across team members. + +**Test patches before releasing to users**: Before pushing updates to +production, you should verify they work correctly using the +[Testing Patches guide](https://docs.shorebird.dev/code-push/guides/testing-patches/). +Learn how to test patches on physical devices, emulators, and with different +release versions to catch issues early. + +**Implement staged rollouts for safety**: Minimize risk by gradually rolling out +patches to a percentage of users first. The +[Percentage-Based Rollouts guide](https://docs.shorebird.dev/code-push/guides/percentage-based-rollouts/) +shows you how to deploy patches to 10% of your user base, monitor for issues, +and then expand to 100% once you're confident. + +**Integrate with your CI/CD pipeline**: Automate your patch delivery process by +integrating Shorebird into your continuous integration system. Whether you use +[GitHub Actions](https://docs.shorebird.dev/code-push/ci/github/), +[Codemagic](https://docs.shorebird.dev/code-push/ci/codemagic/), or another +platform, these guides show you how to automatically create and deploy patches +on every merge to main. + +**Understand patch performance characteristics**: Learn how Shorebird optimizes +patch delivery and what performance characteristics to expect in the +[Patch Performance documentation](https://docs.shorebird.dev/code-push/performance/). +This covers patch download sizes, update timing, and strategies to minimize +impact on user experience. From f2c026a6f2864de6c226db5cd717f102da42c7d4 Mon Sep 17 00:00:00 2001 From: Tom Arra Date: Fri, 6 Feb 2026 09:47:23 -0600 Subject: [PATCH 3/3] spelling --- .cspell.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.cspell.yaml b/.cspell.yaml index 043afb8f..1e9a3059 100644 --- a/.cspell.yaml +++ b/.cspell.yaml @@ -16,6 +16,7 @@ words: - aarch - aars - altool + - apks - appcenter - astro - astrojs