<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Michael Otieno Olang</title>
    <description>The latest articles on DEV Community by Michael Otieno Olang (@mikeyolang).</description>
    <link>https://dev.to/mikeyolang</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F837727%2F29d59d4b-ae20-4bac-8d62-d62a478bf456.jpeg</url>
      <title>DEV Community: Michael Otieno Olang</title>
      <link>https://dev.to/mikeyolang</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mikeyolang"/>
    <language>en</language>
    <item>
      <title>Apple Watch &amp; iMessage Integration in Flutter</title>
      <dc:creator>Michael Otieno Olang</dc:creator>
      <pubDate>Thu, 09 Jul 2026 09:01:50 +0000</pubDate>
      <link>https://dev.to/mikeyolang/apple-watch-imessage-integration-in-flutter-38f2</link>
      <guid>https://dev.to/mikeyolang/apple-watch-imessage-integration-in-flutter-38f2</guid>
      <description>&lt;h3&gt;
  
  
  A Complete Developer Guide
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;App Bundle ID:&lt;/strong&gt; &lt;code&gt;com.example.demoapp&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;App Group:&lt;/strong&gt; &lt;code&gt;group.com.example.demoapp&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Targets:&lt;/strong&gt; &lt;code&gt;Runner&lt;/code&gt; (iPhone) · &lt;code&gt;DemoWatch Watch App&lt;/code&gt; · &lt;code&gt;DemoMessages MessagesExtension&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Architecture Overview&lt;/li&gt;
&lt;li&gt;Dependencies Added&lt;/li&gt;
&lt;li&gt;Xcode Setup (One-Time)&lt;/li&gt;
&lt;li&gt;
Apple Watch Integration

&lt;ul&gt;
&lt;li&gt;4.1 Flutter Side — WatchService
&lt;/li&gt;
&lt;li&gt;4.2 Syncing Data to the Watch
&lt;/li&gt;
&lt;li&gt;4.3 Listening for Watch Actions in Flutter
&lt;/li&gt;
&lt;li&gt;4.4 Native Watch UI (SwiftUI)
&lt;/li&gt;
&lt;li&gt;4.5 Watch Face Complications
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
iMessage Integration

&lt;ul&gt;
&lt;li&gt;5.1 Flutter Side — IMessageSyncService
&lt;/li&gt;
&lt;li&gt;5.2 Syncing Trip Data for iMessage
&lt;/li&gt;
&lt;li&gt;5.3 Native iMessage UI (UIKit/Swift)
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Data Flow Diagrams&lt;/li&gt;
&lt;li&gt;Publishing to the App Store&lt;/li&gt;
&lt;li&gt;Build &amp;amp; Archive Checklist&lt;/li&gt;
&lt;li&gt;Troubleshooting &amp;amp; Challenges Experienced&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  1. Architecture Overview
&lt;/h2&gt;

&lt;p&gt;Flutter &lt;strong&gt;cannot&lt;/strong&gt; run its UI engine on Apple Watch or inside iMessage extensions. Instead, we use two communication bridges:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Extension&lt;/th&gt;
&lt;th&gt;Bridge Technology&lt;/th&gt;
&lt;th&gt;Direction&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Apple Watch&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;WatchConnectivity&lt;/code&gt; framework via &lt;code&gt;watch_connectivity&lt;/code&gt; Flutter package&lt;/td&gt;
&lt;td&gt;iPhone ↔ Watch (two-way, real-time)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;iMessage&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;App Groups&lt;/code&gt; shared &lt;code&gt;UserDefaults&lt;/code&gt; container via &lt;code&gt;shared_preference_app_group&lt;/code&gt; package&lt;/td&gt;
&lt;td&gt;Flutter → iMessage (one-way, cached)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────┐         WatchConnectivity          ┌─────────────────────┐
│   Flutter App        │  ◄──────────────────────────────►  │  DemoWatch App   │
│   (iPhone)           │                                     │  (Apple Watch)      │
└─────────────────────┘                                     └─────────────────────┘
          │
          │  App Groups (UserDefaults)
          │  group.com.example.demoapp
          ▼
┌─────────────────────┐
│  iMessage Extension  │
│  DemoMessages      │
└─────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  2. Dependencies Added
&lt;/h2&gt;

&lt;p&gt;The following packages were added to &lt;a href="//pubspec.yaml"&gt;&lt;code&gt;pubspec.yaml&lt;/code&gt;&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;dependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;watch_connectivity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^0.2.8&lt;/span&gt;        &lt;span class="c1"&gt;# Apple Watch two-way communication&lt;/span&gt;
  &lt;span class="na"&gt;shared_preference_app_group&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;^2.1.0&lt;/span&gt;  &lt;span class="c1"&gt;# Shared container for iMessage&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;flutter pub get
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  3. Xcode Setup (One-Time)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  3.1 App Groups Capability
&lt;/h3&gt;

&lt;p&gt;App Groups allow all three targets to share a single data container (&lt;code&gt;group.com.example.demoapp&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;You must add this capability to &lt;strong&gt;each target&lt;/strong&gt; in Xcode:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;code&gt;ios/Runner.xcworkspace&lt;/code&gt; in Xcode.&lt;/li&gt;
&lt;li&gt;In the Project Navigator (left panel), select &lt;strong&gt;Runner&lt;/strong&gt; target.&lt;/li&gt;
&lt;li&gt;Go to &lt;strong&gt;Signing &amp;amp; Capabilities&lt;/strong&gt; tab.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;+ Capability&lt;/strong&gt; → &lt;strong&gt;App Groups&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Add: &lt;code&gt;group.com.example.demoapp&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Repeat steps 2–5 for &lt;strong&gt;DemoWatch Watch App&lt;/strong&gt; target.&lt;/li&gt;
&lt;li&gt;Repeat steps 2–5 for &lt;strong&gt;DemoMessages MessagesExtension&lt;/strong&gt; target.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;✅ Confirmation: Check the entitlements file at&lt;br&gt;
&lt;code&gt;ios/DemoWatch Watch App/DemoWatch Watch App.entitlements&lt;/code&gt; — it should contain:&lt;/p&gt;


&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;com.apple.security.application-groups&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;array&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;group.com.example.demoapp&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/array&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  3.2 Complication Data Source (Apple Watch only)
&lt;/h3&gt;

&lt;p&gt;To enable watch face complications:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Select the &lt;strong&gt;DemoWatch Watch App&lt;/strong&gt; target in Xcode.&lt;/li&gt;
&lt;li&gt;Go to the &lt;strong&gt;Info&lt;/strong&gt; tab.&lt;/li&gt;
&lt;li&gt;Add a new row with key: &lt;code&gt;CLKComplicationDataSource&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Set value to: &lt;code&gt;ComplicationController&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  3.3 Watch Target Platform Settings
&lt;/h3&gt;

&lt;p&gt;The Watch target must resolve as a watchOS target during archive. If Xcode resolves it as &lt;code&gt;iphoneos&lt;/code&gt;, the Watch asset catalog will be compiled as an iOS asset catalog and the archive will fail with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Assets.xcassets: The stickers icon set, app icon set, or icon stack named "AppIcon" did not have any applicable content.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the &lt;code&gt;DemoWatch Watch App&lt;/code&gt; target, confirm these build settings in Debug, Release, and Profile:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting&lt;/th&gt;
&lt;th&gt;Required value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SDKROOT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;watchos&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SUPPORTED_PLATFORMS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;watchos watchsimulator&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;TARGETED_DEVICE_FAMILY&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;4&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ASSETCATALOG_COMPILER_APPICON_NAME&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;AppIcon&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;AccentColor&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The current project pins these in &lt;code&gt;ios/Runner.xcodeproj/project.pbxproj&lt;/code&gt;. This matters because the project-level Flutter/iOS configuration sets &lt;code&gt;SDKROOT = iphoneos&lt;/code&gt; and &lt;code&gt;SUPPORTED_PLATFORMS = iphoneos&lt;/code&gt;; the Watch target must explicitly override that inherited iOS platform.&lt;/p&gt;

&lt;p&gt;You can verify the resolved target settings with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;xcodebuild &lt;span class="nt"&gt;-showBuildSettings&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-project&lt;/span&gt; ios/Runner.xcodeproj &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-scheme&lt;/span&gt; &lt;span class="s2"&gt;"DemoWatch Watch App"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-configuration&lt;/span&gt; Release &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-destination&lt;/span&gt; &lt;span class="s2"&gt;"generic/platform=watchOS"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-derivedDataPath&lt;/span&gt; /tmp/travler-derived-data &lt;span class="se"&gt;\&lt;/span&gt;
  | rg &lt;span class="s2"&gt;"PLATFORM_NAME|SDKROOT|SUPPORTED_PLATFORMS|TARGETED_DEVICE_FAMILY|BUILT_PRODUCTS_DIR"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected output should include:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BUILT_PRODUCTS_DIR = .../Release-watchos
PLATFORM_NAME = watchos
SDKROOT = .../WatchOS.platform/.../WatchOS*.sdk
SUPPORTED_PLATFORMS = watchos watchsimulator
TARGETED_DEVICE_FAMILY = 4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3.4 Watch AppIcon Asset Catalog
&lt;/h3&gt;

&lt;p&gt;The Watch app icon set lives at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ios/DemoWatch Watch App/Assets.xcassets/AppIcon.appiconset
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Contents.json&lt;/code&gt; must declare watch-specific icon slots, not only the 1024 marketing icon. The catalog should include these families:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;th&gt;Sizes currently covered&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;notificationCenter&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;24x24, 27.5x27.5, 33x33&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;companionSettings&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;29x29 at 2x and 3x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;appLauncher&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;40x40, 44x44, 46x46, 50x50, 51x51, 54x54&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;quickLook&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;86x86, 98x98, 108x108, 117x117, 129x129&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;watch-marketing&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1024x1024&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If new icon artwork is generated, preserve the filenames declared in &lt;code&gt;Contents.json&lt;/code&gt; or update the JSON and PNGs together. A missing filename, wrong idiom, or iOS-only icon set will break archive.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Apple Watch Integration
&lt;/h2&gt;

&lt;h3&gt;
  
  
  4.1 Flutter Side — WatchService
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File:&lt;/strong&gt; &lt;a href="//lib/services/watch_service.dart"&gt;&lt;code&gt;lib/services/watch_service.dart&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This service is the bridge between your Flutter app and the Apple Watch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'dart:async'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:flutter/foundation.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:watch_connectivity/watch_connectivity.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WatchService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;WatchConnectivity&lt;/span&gt; &lt;span class="n"&gt;_watch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WatchConnectivity&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;StreamSubscription&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;dynamic&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;_messageSubscription&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// All raw messages from the Watch&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;_messageController&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;StreamController&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;dynamic&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;broadcast&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;Stream&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;dynamic&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="n"&gt;messageStream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_messageController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Only action commands from the Watch (e.g., quick_book, cancel_booking)&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;_actionController&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;StreamController&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;dynamic&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;broadcast&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;Stream&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;dynamic&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="n"&gt;actionStream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_actionController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="n"&gt;WatchService&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;_messageSubscription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_watch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;messageStream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;_messageController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;containsKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'action'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_actionController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;isSupported&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_watch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isSupported&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;isReachable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_watch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isReachable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;dispose&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;_messageSubscription&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;_messageController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;_actionController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4.2 Syncing Data to the Watch
&lt;/h3&gt;

&lt;p&gt;Call &lt;code&gt;syncTravelData()&lt;/code&gt; whenever the user's data changes — after login, booking, or wallet top-up. The data is sent using &lt;strong&gt;Application Context&lt;/strong&gt;, which means the Watch receives the latest state even if it was not connected at the time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;watchService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WatchService&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;watchService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;syncTravelData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;walletBalance:&lt;/span&gt; &lt;span class="mf"&gt;125.50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;walletCurrency:&lt;/span&gt; &lt;span class="s"&gt;'Ksh'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;nextTripDestination:&lt;/span&gt; &lt;span class="s"&gt;'Nairobi → Mombasa'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;nextTripDate:&lt;/span&gt; &lt;span class="s"&gt;'Aug 12, 2026'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;nextTripTime:&lt;/span&gt; &lt;span class="s"&gt;'08:30 AM'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;nextTripSeat:&lt;/span&gt; &lt;span class="s"&gt;'14B'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;qrCodeData:&lt;/span&gt; &lt;span class="s"&gt;'TICKET-XYZ-12345'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// the raw ticket/QR string&lt;/span&gt;
  &lt;span class="nl"&gt;activeBookingsCount:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;unreadNotifications:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Best places to call this:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;After a successful booking API response&lt;/li&gt;
&lt;li&gt;After the user tops up their wallet&lt;/li&gt;
&lt;li&gt;In your home screen &lt;code&gt;initState()&lt;/code&gt; when the app opens&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4.3 Listening for Watch Actions in Flutter
&lt;/h3&gt;

&lt;p&gt;When the user presses &lt;strong&gt;Quick Book&lt;/strong&gt; or &lt;strong&gt;Cancel&lt;/strong&gt; on the Apple Watch, the Watch sends a message to Flutter via &lt;code&gt;actionStream&lt;/code&gt;. Listen to this in your BLoC, provider, or main widget tree:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;watchService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WatchService&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;watchService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;actionStream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;actionData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;actionData&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'action'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;'quick_book'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;// Trigger your booking flow / open the booking screen&lt;/span&gt;
      &lt;span class="n"&gt;NavigationKeys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;mainNav&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currentState&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;pushNamed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'/booking'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;'cancel_booking'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
      &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;destination&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;actionData&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'destination'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="c1"&gt;// Call your cancel API&lt;/span&gt;
      &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;read&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;BookingBloc&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CancelBookingEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;destination:&lt;/span&gt; &lt;span class="n"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4.4 Native Watch UI (SwiftUI)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File:&lt;/strong&gt; &lt;a href="//ios/DemoWatch%20Watch%20App/ContentView.swift"&gt;&lt;code&gt;ios/DemoWatch Watch App/ContentView.swift&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Watch app has a &lt;strong&gt;4-tab swipeable interface&lt;/strong&gt;. Each tab is a SwiftUI view powered by &lt;code&gt;WatchViewModel&lt;/code&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tab&lt;/th&gt;
&lt;th&gt;View&lt;/th&gt;
&lt;th&gt;Content&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;TripDashboardView&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Next trip destination, date, time, seat + Quick Book &amp;amp; Cancel buttons&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;code&gt;TicketQRView&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Auto-generated QR code scannable at the boarding point&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;code&gt;WalletView&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Wallet balance + active bookings count&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SupportNotificationsView&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Call Support button + unread notification count&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;File:&lt;/strong&gt; &lt;a href="//ios/DemoWatch%20Watch%20App/WatchViewModel.swift"&gt;&lt;code&gt;ios/DemoWatch Watch App/WatchViewModel.swift&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;WatchViewModel&lt;/code&gt; is the native Swift equivalent of &lt;code&gt;WatchService&lt;/code&gt;. It implements &lt;code&gt;WCSessionDelegate&lt;/code&gt; to receive data from Flutter and manages all published state for the SwiftUI views.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// How the Watch receives data from Flutter:&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;session&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;session&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;WCSession&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;didReceiveApplicationContext&lt;/span&gt; &lt;span class="nv"&gt;applicationContext&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;DispatchQueue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parseData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;applicationContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// How the Watch sends actions back to Flutter:&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;sendActionToFlutter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[:])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;
    &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"action"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isReachable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;replyHandler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;errorHandler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4.5 Watch Face Complications
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File:&lt;/strong&gt; &lt;a href="//ios/DemoWatch%20Watch%20App/ComplicationController.swift"&gt;&lt;code&gt;ios/DemoWatch Watch App/ComplicationController.swift&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Complications display DemoTravel info right on the Apple Watch clock face — without the user needing to open the app.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Supported complication families:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Family&lt;/th&gt;
&lt;th&gt;Watch Face&lt;/th&gt;
&lt;th&gt;What's Shown&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;graphicCorner&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Infograph&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;🚌 Mombasa&lt;/code&gt; + departure time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;graphicCircular&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Infograph Modular&lt;/td&gt;
&lt;td&gt;Bus icon + time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;graphicBezel&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Infograph&lt;/td&gt;
&lt;td&gt;Circle with full destination curved around it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;modularLarge&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Modular&lt;/td&gt;
&lt;td&gt;3-row table: Trip / Time / Seat&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;utilitarianLarge&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Utility&lt;/td&gt;
&lt;td&gt;&lt;code&gt;🚌 Nairobi → Mombasa · 08:30&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;utilitarianSmall&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Utility&lt;/td&gt;
&lt;td&gt;&lt;code&gt;🚌 08:30&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;modularSmall&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Modular&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Bus&lt;/code&gt; + time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;circularSmall&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Color / Chronograph&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Bus&lt;/code&gt; + time&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;How complications stay up to date:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When &lt;code&gt;WatchViewModel.parseData()&lt;/code&gt; receives new data from Flutter, it automatically:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Writes the data to &lt;code&gt;UserDefaults(suiteName: "group.com.example.demoapp")&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Calls &lt;code&gt;CLKComplicationServer.sharedInstance().reloadTimeline(for:)&lt;/code&gt; on all active complications&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This means the watch face updates instantly every time you call &lt;code&gt;syncTravelData()&lt;/code&gt; from Flutter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The &lt;code&gt;ComplicationController&lt;/code&gt; reads from UserDefaults:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;defaults&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;UserDefaults&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;suiteName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"group.com.example.demoapp"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;destination&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;defaults&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;forKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"nextTripDestination"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="s"&gt;"No Trip"&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;time&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;defaults&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;forKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"nextTripTime"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="s"&gt;"--"&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;seat&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;defaults&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;forKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"nextTripSeat"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="s"&gt;"--"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  5. iMessage Integration
&lt;/h2&gt;

&lt;h3&gt;
  
  
  5.1 Flutter Side — IMessageSyncService
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File:&lt;/strong&gt; &lt;a href="//lib/services/imessage_sync_service.dart"&gt;&lt;code&gt;lib/services/imessage_sync_service.dart&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This service writes trip and wallet data into the shared App Group container so the iMessage extension can read them in Swift.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'dart:convert'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:shared_preference_app_group/shared_preference_app_group.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;_kAppGroup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'group.com.example.demoapp'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DemoTrip&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;seat&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;qrCodeData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="n"&gt;DemoTrip&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;seat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;qrCodeData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kt"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;dynamic&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;toJson&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;'id'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;'destination'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;'origin'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;'date'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;'time'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;'seat'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;seat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;'qrCodeData'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;qrCodeData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;IMessageSyncService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;_tripsKey&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'demo_imessage_trips'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;_walletKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'demo_imessage_wallet'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Call once at app startup (e.g. in main.dart)&lt;/span&gt;
  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;SharedPreferenceAppGroup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setAppGroup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_kAppGroup&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;syncAll&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;DemoTrip&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;trips&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;walletBalance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;walletCurrency&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;syncTrips&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trips&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;syncWalletBalance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;walletBalance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;walletCurrency&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;syncTrips&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;DemoTrip&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;trips&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;encoded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;jsonEncode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trips&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toJson&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;SharedPreferenceAppGroup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_tripsKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encoded&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;syncWalletBalance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;SharedPreferenceAppGroup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;_walletKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;jsonEncode&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s"&gt;'balance'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'currency'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5.2 Syncing Trip Data for iMessage
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Step 1 — Initialise once at app startup&lt;/strong&gt; (e.g., in &lt;code&gt;main.dart&lt;/code&gt; before &lt;code&gt;runApp&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;WidgetsFlutterBinding&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ensureInitialized&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// ... existing initialisation ...&lt;/span&gt;

  &lt;span class="c1"&gt;// Initialise iMessage sync&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;iMessageSync&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;IMessageSyncService&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;iMessageSync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;init&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="n"&gt;runApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;MyApp&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2 — Sync whenever data changes:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;iMessageSync&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;IMessageSyncService&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;iMessageSync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;syncAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;walletBalance:&lt;/span&gt; &lt;span class="mf"&gt;125.50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;walletCurrency:&lt;/span&gt; &lt;span class="s"&gt;'Ksh'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;trips:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="n"&gt;DemoTrip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;id:&lt;/span&gt; &lt;span class="s"&gt;'booking-001'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;origin:&lt;/span&gt; &lt;span class="s"&gt;'Nairobi'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;destination:&lt;/span&gt; &lt;span class="s"&gt;'Mombasa'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;date:&lt;/span&gt; &lt;span class="s"&gt;'Aug 12, 2026'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;time:&lt;/span&gt; &lt;span class="s"&gt;'08:30 AM'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;seat:&lt;/span&gt; &lt;span class="s"&gt;'14B'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;qrCodeData:&lt;/span&gt; &lt;span class="s"&gt;'TICKET-XYZ-12345'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;DemoTrip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;id:&lt;/span&gt; &lt;span class="s"&gt;'booking-002'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;origin:&lt;/span&gt; &lt;span class="s"&gt;'Mombasa'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;destination:&lt;/span&gt; &lt;span class="s"&gt;'Nairobi'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;date:&lt;/span&gt; &lt;span class="s"&gt;'Aug 15, 2026'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;time:&lt;/span&gt; &lt;span class="s"&gt;'02:00 PM'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;seat:&lt;/span&gt; &lt;span class="s"&gt;'7A'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;qrCodeData:&lt;/span&gt; &lt;span class="s"&gt;'TICKET-ABC-67890'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5.3 Native iMessage UI (UIKit/Swift)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File:&lt;/strong&gt; &lt;a href="//ios/DemoMessages%20MessagesExtension/MessagesViewController.swift"&gt;&lt;code&gt;ios/DemoMessages MessagesExtension/MessagesViewController.swift&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The iMessage extension is built with UIKit. It:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Reads trip and wallet data from &lt;code&gt;UserDefaults(suiteName: "group.com.example.demoapp")&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Displays a scrollable list of upcoming trips&lt;/li&gt;
&lt;li&gt;When a trip is tapped, inserts a rich &lt;code&gt;MSMessage&lt;/code&gt; bubble into the chat&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Reading from the shared container in Swift:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;defaults&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;UserDefaults&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;suiteName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"group.com.example.demoapp"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Read trips&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;tripsString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;defaults&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;forKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"demo_imessage_trips"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
   &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tripsString&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;using&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;utf8&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
   &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;rawList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="kt"&gt;JSONSerialization&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;jsonObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;with&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as?&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;trips&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rawList&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compactMap&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kt"&gt;DemoTrip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Read wallet&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;walletString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;defaults&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;forKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"demo_imessage_wallet"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
   &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;walletString&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;using&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;utf8&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
   &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;dict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="kt"&gt;JSONSerialization&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;jsonObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;with&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as?&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;walletBalance&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"balance"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="k"&gt;as?&lt;/span&gt; &lt;span class="kt"&gt;Double&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="n"&gt;walletCurrency&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"currency"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;as?&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="s"&gt;"Ksh"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Sending a rich iMessage bubble:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;sendTrip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;trip&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;DemoTrip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;conversation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;currentConversation&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;MSMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;session&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;conversation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;selectedMessage&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="kt"&gt;MSSession&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;layout&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;MSMessageTemplateLayout&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;caption&lt;/span&gt;             &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"🚌 &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;trip&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;origin&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt; → &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;trip&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;destination&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;subcaption&lt;/span&gt;          &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;trip&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt; at &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;trip&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;trailingCaption&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Seat &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;trip&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;seat&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;trailingSubcaption&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Trip Booking"&lt;/span&gt;
    &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;               &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generateQRImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;trip&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;qrCodeData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// QR code&lt;/span&gt;

    &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;
    &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;string&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"https://example.com"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;

    &lt;span class="n"&gt;conversation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;completionHandler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Important: do not name your stored conversation property &lt;code&gt;activeConversation&lt;/code&gt;. &lt;code&gt;MSMessagesAppViewController&lt;/code&gt; already exposes an inherited &lt;code&gt;activeConversation&lt;/code&gt; property. Use a separate name such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;currentConversation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;MSConversation&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;

&lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;willBecomeActive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="nv"&gt;conversation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;MSConversation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;currentConversation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conversation&lt;/span&gt;
    &lt;span class="nf"&gt;loadData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What the recipient sees:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The recipient sees a custom rich bubble in their chat containing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;🚌 Nairobi → Mombasa&lt;/code&gt; (caption)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Aug 12, 2026 at 08:30 AM&lt;/code&gt; (subcaption)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Seat 14B&lt;/code&gt; (trailing)&lt;/li&gt;
&lt;li&gt;QR code image embedded in the bubble&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  6. Data Flow Diagrams
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Apple Watch — Data Flow
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Flutter (Dart)                        Apple Watch (Swift)
─────────────────                     ────────────────────
WatchService.syncTravelData()
        │
        │  WatchConnectivity
        │  updateApplicationContext()
        │ ─────────────────────────►  WatchViewModel.didReceiveApplicationContext()
        │                                      │
        │                                      ├──► Updates @Published UI state
        │                                      ├──► Persists to UserDefaults (App Group)
        │                                      └──► Reloads watch face complications
        │
        │  WCSession.sendMessage()
        │ ◄─────────────────────────  WatchViewModel.sendActionToFlutter()
        │           (user taps Quick Book / Cancel on Watch)
        │
WatchService.actionStream emits
        │
        └──► Your BLoC / Provider handles the action
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  iMessage — Data Flow
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Flutter (Dart)                        iMessage Extension (Swift)
─────────────────                     ──────────────────────────
IMessageSyncService.syncAll()
        │
        │  UserDefaults
        │  (suiteName: group.com.example.demoapp)
        │ ─────────────────────────►  MessagesViewController.loadData()
        │                                      │
        │                                      ├──► Renders trip list
        │                                      └──► User taps trip → sends MSMessage bubble
        │
        │  (No return path — iMessage is one-way)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  7. Publishing to the App Store
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;Good news:&lt;/strong&gt; The Apple Watch and iMessage extensions are &lt;strong&gt;bundled inside your main iOS app&lt;/strong&gt;. You do not submit them separately. When users download DemoTravel from the App Store, the Watch app automatically installs on their paired Apple Watch.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Step-by-step publishing process:
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Step 1 — Archive the app:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;flutter build ipa
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or in Xcode: &lt;strong&gt;Product → Archive&lt;/strong&gt; (with "Any iOS Device" selected as the destination).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2 — Open Xcode Organizer:&lt;/strong&gt;&lt;br&gt;
After archiving, Xcode Organizer opens automatically. Select your archive and click &lt;strong&gt;Distribute App&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3 — Upload to App Store Connect:&lt;/strong&gt;&lt;br&gt;
Choose &lt;strong&gt;App Store Connect → Upload&lt;/strong&gt;. Follow the prompts. The Watch and iMessage extensions are included automatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4 — Add Apple Watch Screenshots:&lt;/strong&gt;&lt;br&gt;
In App Store Connect, navigate to your app listing. You will now see a section for &lt;strong&gt;Apple Watch Screenshots&lt;/strong&gt;. Take screenshots from the Watch Simulator in Xcode and upload them here. Apple requires these before the app can be reviewed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Required Watch screenshot sizes:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;40mm: 394 × 324 px&lt;/li&gt;
&lt;li&gt;41mm: 352 × 430 px (Series 7/8/9)&lt;/li&gt;
&lt;li&gt;44mm: 368 × 448 px&lt;/li&gt;
&lt;li&gt;45mm: 396 × 484 px&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Step 5 — Submit for Review:&lt;/strong&gt;&lt;br&gt;
Once screenshots are uploaded and everything looks good, click &lt;strong&gt;Submit for Review&lt;/strong&gt;. Apple reviews the Watch and iMessage extensions as part of the same review process.&lt;/p&gt;


&lt;h2&gt;
  
  
  8. Build &amp;amp; Archive Checklist
&lt;/h2&gt;

&lt;p&gt;Use this checklist before creating an App Store or TestFlight archive that includes Apple Watch and iMessage targets.&lt;/p&gt;
&lt;h3&gt;
  
  
  8.1 Before archiving
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Open &lt;code&gt;ios/Runner.xcworkspace&lt;/code&gt;, not &lt;code&gt;ios/Runner.xcodeproj&lt;/code&gt;, when using Xcode manually.&lt;/li&gt;
&lt;li&gt;Confirm the &lt;code&gt;Runner&lt;/code&gt; scheme includes dependencies on:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;DemoWatch Watch App&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DemoMessages MessagesExtension&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Confirm &lt;code&gt;DemoWatch Watch App&lt;/code&gt; resolves as watchOS:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;PLATFORM_NAME = watchos&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;BUILT_PRODUCTS_DIR&lt;/code&gt; contains &lt;code&gt;Release-watchos&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SUPPORTED_PLATFORMS = watchos watchsimulator&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Confirm &lt;code&gt;DemoMessages MessagesExtension&lt;/code&gt; resolves as iPhoneOS:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;PLATFORM_NAME = iphoneos&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PRODUCT_TYPE = com.apple.product-type.app-extension.messages&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Confirm all targets share the App Group:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Runner&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DemoWatch Watch App&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DemoMessages MessagesExtension&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  8.2 Useful build-only verification
&lt;/h3&gt;

&lt;p&gt;This command checks the Watch and iMessage target build path without running tests or static analysis:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;xcodebuild build &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-project&lt;/span&gt; ios/Runner.xcodeproj &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-scheme&lt;/span&gt; &lt;span class="s2"&gt;"DemoWatch Watch App"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-configuration&lt;/span&gt; Release &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-destination&lt;/span&gt; &lt;span class="s2"&gt;"generic/platform=watchOS"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-derivedDataPath&lt;/span&gt; /tmp/travler-derived-data &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nv"&gt;CODE_SIGNING_ALLOWED&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;NO
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Successful Watch asset catalog output looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CompileAssetCatalogVariant ... DemoWatch Watch App/Assets.xcassets
... --app-icon AppIcon --target-device watch --platform watchos
/* com.apple.actool.compilation-results */
.../Assets.car
LinkAssetCatalog ... DemoWatch Watch App/Assets.xcassets
note: Emplaced .../DemoWatch Watch App.app/Assets.car
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  8.3 What not to run for this workflow
&lt;/h3&gt;

&lt;p&gt;For fast archive debugging, skip:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;flutter &lt;span class="nb"&gt;test
&lt;/span&gt;flutter analyze
dart analyze
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The archive blockers here are Xcode target configuration, asset catalogs, and native Swift extension compilation. Unit/widget tests and Dart static analysis do not diagnose those issues.&lt;/p&gt;




&lt;h2&gt;
  
  
  9. Troubleshooting &amp;amp; Challenges Experienced
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Watch data not updating?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Make sure &lt;code&gt;syncTravelData()&lt;/code&gt; is being called &lt;strong&gt;after&lt;/strong&gt; a booking or login.&lt;/li&gt;
&lt;li&gt;Confirm the Watch app is installed on a paired Watch.&lt;/li&gt;
&lt;li&gt;On a physical device, both the iPhone and Watch must be connected.&lt;/li&gt;
&lt;li&gt;Check that the App Group &lt;code&gt;group.com.example.demoapp&lt;/code&gt; is listed in &lt;strong&gt;both&lt;/strong&gt; the Runner and Watch targets in Xcode.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  iMessage extension shows "No upcoming trips"?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Make sure &lt;code&gt;IMessageSyncService.init()&lt;/code&gt; is called at app startup &lt;strong&gt;before&lt;/strong&gt; any sync calls.&lt;/li&gt;
&lt;li&gt;Confirm &lt;code&gt;syncAll()&lt;/code&gt; has been called at least once.&lt;/li&gt;
&lt;li&gt;Verify the App Group identifier &lt;code&gt;group.com.example.demoapp&lt;/code&gt; is set on &lt;strong&gt;both&lt;/strong&gt; Runner and DemoMessages targets.&lt;/li&gt;
&lt;li&gt;Double check the key names in Swift (&lt;code&gt;demo_imessage_trips&lt;/code&gt;, &lt;code&gt;demo_imessage_wallet&lt;/code&gt;) match the constants in Dart.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Watch face complications not appearing?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Confirm &lt;code&gt;CLKComplicationDataSource = ComplicationController&lt;/code&gt; is set in the Watch target's Info.plist in Xcode.&lt;/li&gt;
&lt;li&gt;Long-press your watch face → Edit → browse Complications for "DemoTravel".&lt;/li&gt;
&lt;li&gt;After calling &lt;code&gt;syncTravelData()&lt;/code&gt; in Flutter, the complication should update within seconds.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Build error: &lt;code&gt;No such module 'CoreImage.CIFilterBuiltins'&lt;/code&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;This module does not exist on watchOS. Use plain &lt;code&gt;import CoreImage&lt;/code&gt; instead.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;CIFilter(name: "CIQRCodeGenerator")&lt;/code&gt; instead of &lt;code&gt;CIFilter.qrCodeGenerator()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;Image(cgImage:, scale:, label:)&lt;/code&gt; in SwiftUI instead of &lt;code&gt;Image(uiImage:)&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;pod install&lt;/code&gt; fails with xcodeproj compatibility error?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;This is a known CocoaPods issue with Xcode 26+. Run &lt;code&gt;flutter run&lt;/code&gt; from the command line instead of &lt;code&gt;pod install&lt;/code&gt; directly — Flutter's tooling handles the pod installation correctly.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Archive error: &lt;code&gt;AppIcon did not have any applicable content&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Symptom:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/ios/DemoWatch Watch App/Assets.xcassets:
The stickers icon set, app icon set, or icon stack named "AppIcon" did not have any applicable content.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Root causes seen in this project:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The Watch target was resolving as &lt;code&gt;iphoneos&lt;/code&gt;, so Xcode was trying to compile watch-only icon slots as iOS icons.&lt;/li&gt;
&lt;li&gt;The Watch &lt;code&gt;AppIcon.appiconset/Contents.json&lt;/code&gt; only exposed &lt;code&gt;watch-marketing&lt;/code&gt; content or incomplete watch slots.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Fix:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In &lt;code&gt;ios/Runner.xcodeproj/project.pbxproj&lt;/code&gt;, ensure the &lt;code&gt;DemoWatch Watch App&lt;/code&gt; target has:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SDKROOT = watchos;
SUPPORTED_PLATFORMS = "watchos watchsimulator";
TARGETED_DEVICE_FAMILY = 4;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;In &lt;code&gt;ios/DemoWatch Watch App/Assets.xcassets/AppIcon.appiconset/Contents.json&lt;/code&gt;, declare actual &lt;code&gt;idiom: watch&lt;/code&gt; entries for &lt;code&gt;notificationCenter&lt;/code&gt;, &lt;code&gt;companionSettings&lt;/code&gt;, &lt;code&gt;appLauncher&lt;/code&gt;, and &lt;code&gt;quickLook&lt;/code&gt;, plus &lt;code&gt;watch-marketing&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Confirm every filename referenced by &lt;code&gt;Contents.json&lt;/code&gt; exists and has the expected pixel dimensions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Verification:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;jq empty &lt;span class="s2"&gt;"ios/DemoWatch Watch App/Assets.xcassets/AppIcon.appiconset/Contents.json"&lt;/span&gt;
sips &lt;span class="nt"&gt;-g&lt;/span&gt; pixelWidth &lt;span class="nt"&gt;-g&lt;/span&gt; pixelHeight &lt;span class="s2"&gt;"ios/DemoWatch Watch App/Assets.xcassets/AppIcon.appiconset/"&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;.png
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then confirm the target is not resolving as iPhoneOS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;xcodebuild &lt;span class="nt"&gt;-showBuildSettings&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-project&lt;/span&gt; ios/Runner.xcodeproj &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-scheme&lt;/span&gt; &lt;span class="s2"&gt;"DemoWatch Watch App"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-configuration&lt;/span&gt; Release &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-destination&lt;/span&gt; &lt;span class="s2"&gt;"generic/platform=watchOS"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-derivedDataPath&lt;/span&gt; /tmp/travler-derived-data &lt;span class="se"&gt;\&lt;/span&gt;
  | rg &lt;span class="s2"&gt;"PLATFORM_NAME|SDKROOT|SUPPORTED_PLATFORMS|BUILT_PRODUCTS_DIR"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Build error: &lt;code&gt;No available simulator runtimes for platform watchsimulator&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This can happen when &lt;code&gt;actool&lt;/code&gt; runs in a restricted environment or Xcode cannot access simulator runtime services.&lt;/p&gt;

&lt;p&gt;Symptoms:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;No available simulator runtimes for platform watchsimulator.
SimServiceContext supportedRuntimes=[]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fix:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run the build from normal Terminal or Xcode, not a restricted sandbox.&lt;/li&gt;
&lt;li&gt;Open Xcode once and let it finish installing components.&lt;/li&gt;
&lt;li&gt;Check &lt;strong&gt;Xcode → Settings → Platforms&lt;/strong&gt; and install the required watchOS simulator runtime if missing.&lt;/li&gt;
&lt;li&gt;Use a device/generic watchOS destination for archive:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;xcodebuild build &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-project&lt;/span&gt; ios/Runner.xcodeproj &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-scheme&lt;/span&gt; &lt;span class="s2"&gt;"DemoWatch Watch App"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-configuration&lt;/span&gt; Release &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-destination&lt;/span&gt; &lt;span class="s2"&gt;"generic/platform=watchOS"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-derivedDataPath&lt;/span&gt; /tmp/travler-derived-data &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nv"&gt;CODE_SIGNING_ALLOWED&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;NO
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Build error: &lt;code&gt;activeConversation&lt;/code&gt; override in iMessage extension
&lt;/h3&gt;

&lt;p&gt;Symptom:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;overriding property must be as accessible as its enclosing type
cannot override with a stored property 'activeConversation'
ambiguous use of 'activeConversation'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cause:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;MSMessagesAppViewController&lt;/code&gt; already has an inherited &lt;code&gt;activeConversation&lt;/code&gt; property. A stored property with the same name in &lt;code&gt;MessagesViewController&lt;/code&gt; conflicts with it.&lt;/p&gt;

&lt;p&gt;Fix:&lt;/p&gt;

&lt;p&gt;Rename the custom property:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;currentConversation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;MSConversation&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;

&lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;willBecomeActive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="nv"&gt;conversation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;MSConversation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;currentConversation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conversation&lt;/span&gt;
    &lt;span class="nf"&gt;loadData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;sendTrip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;trip&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;DemoTrip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;conversation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;currentConversation&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// insert MSMessage...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Build reaches &lt;code&gt;Run Script&lt;/code&gt; and appears stuck
&lt;/h3&gt;

&lt;p&gt;After Watch assets and iMessage compile issues are fixed, the build can spend a long time in Flutter/Xcode script phases, especially &lt;code&gt;Run Script&lt;/code&gt;, &lt;code&gt;Thin Binary&lt;/code&gt;, or Flutter embed steps.&lt;/p&gt;

&lt;p&gt;What to check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Confirm previous failures are gone before interrupting. In the log, Watch asset success looks like &lt;code&gt;Emplaced .../DemoWatch Watch App.app/Assets.car&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Run from a normal Terminal when possible so script phases can access the full user environment.&lt;/li&gt;
&lt;li&gt;If the script is silent for several minutes, rerun with Xcode's report navigator open to see the exact active phase.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Documentation generated for DemoTravel v3.5.4 — Apple Watch &amp;amp; iMessage Integration&lt;/em&gt;&lt;br&gt;
&lt;em&gt;This sample project is provided for educational purposes.&lt;/em&gt;&lt;br&gt;
&lt;em&gt;Bundle ID: &lt;code&gt;com.example.demoapp&lt;/code&gt; · App Group: &lt;code&gt;group.com.example.demoapp&lt;/code&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>ios</category>
      <category>mobile</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Flutter Apps and Android's 16KB Page Size Requirement: A Complete Developer Guide</title>
      <dc:creator>Michael Otieno Olang</dc:creator>
      <pubDate>Thu, 04 Sep 2025 06:44:24 +0000</pubDate>
      <link>https://dev.to/mikeyolang/flutter-apps-and-androids-16kb-page-size-requirement-a-complete-developer-guide-1p71</link>
      <guid>https://dev.to/mikeyolang/flutter-apps-and-androids-16kb-page-size-requirement-a-complete-developer-guide-1p71</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftxwvmggb07w2t8wzrvwp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftxwvmggb07w2t8wzrvwp.png" alt=" " width="800" height="436"&gt;&lt;/a&gt;&lt;br&gt;
Google Play Store is rolling out a significant change that every Android developer needs to know about. Starting November 1, 2025, all new apps and app updates targeting Android 15+ must be compatible with 16KB memory pages. This requirement has caught many developers off guard, especially those working with Flutter applications.&lt;br&gt;
In this comprehensive guide, we'll dive deep into what this means, why it's happening, and most importantly, how to ensure your Flutter apps are ready.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Understanding Memory Page Sizes&lt;/strong&gt;&lt;br&gt;
Memory pages are fixed-size blocks of virtual memory that the operating system uses to manage RAM efficiently. Think of them as standardized containers for data that help the OS organize and access memory. For years, Android devices have predominantly used 4KB page sizes. This worked well for devices with limited RAM, but as smartphones evolved with more memory and processing power, larger page sizes became beneficial.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why 16KB Pages?&lt;/strong&gt;&lt;br&gt;
The shift to 16KB pages isn't arbitrary. &lt;br&gt;
Here's what the research shows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Faster App Launches: Up to 30% improvement in cold start times&lt;/li&gt;
&lt;li&gt;Better Memory Efficiency: Reduced memory fragmentation&lt;/li&gt;
&lt;li&gt;Improved System Performance: Faster boot times and overall responsiveness&lt;/li&gt;
&lt;li&gt;Enhanced Battery Life: More efficient memory management reduces CPU overhead&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Step-by-Step Implementation Guide&lt;/strong&gt;&lt;br&gt;
1.Update Flutter SDK&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Check current version&lt;/span&gt;
flutter &lt;span class="nt"&gt;--version&lt;/span&gt;

&lt;span class="c"&gt;# Update to latest stable&lt;/span&gt;
flutter upgrade

&lt;span class="c"&gt;# Verify you're on the latest stable channel&lt;/span&gt;
flutter channel stable
flutter upgrade
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Minimum recommended versions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Flutter SDK: 3.16.0 or later&lt;/li&gt;
&lt;li&gt;Dart SDK: 3.2.0 or later&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;2.Update Android Gradle Plugin (AGP)&lt;br&gt;
In your &lt;code&gt;android/build.gradle&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gradle"&gt;&lt;code&gt;&lt;span class="k"&gt;buildscript&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ext&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;kotlin_version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'1.9.10'&lt;/span&gt;
    &lt;span class="k"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Update to AGP 8.5.0 or later&lt;/span&gt;
        &lt;span class="n"&gt;classpath&lt;/span&gt; &lt;span class="s1"&gt;'com.android.tools.build:gradle:8.1.0'&lt;/span&gt;
        &lt;span class="n"&gt;classpath&lt;/span&gt; &lt;span class="s2"&gt;"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;3.Update Android NDK&lt;br&gt;
In &lt;code&gt;android/app/build.gradle&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gradle"&gt;&lt;code&gt;&lt;span class="n"&gt;android&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;compileSdkVersion&lt;/span&gt; &lt;span class="mi"&gt;35&lt;/span&gt;
    &lt;span class="n"&gt;ndkVersion&lt;/span&gt; &lt;span class="s2"&gt;"28.x.xxxxxxx"&lt;/span&gt; 

    &lt;span class="n"&gt;compileOptions&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;sourceCompatibility&lt;/span&gt; &lt;span class="n"&gt;JavaVersion&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;VERSION_1_8&lt;/span&gt;
        &lt;span class="n"&gt;targetCompatibility&lt;/span&gt; &lt;span class="n"&gt;JavaVersion&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;VERSION_1_8&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;4.Dependency Audit&lt;br&gt;
Check if you have the latest versions of every dependency in the &lt;code&gt;pubspec.yaml&lt;/code&gt; file&lt;/p&gt;

&lt;p&gt;Critical Plugins to Check&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Focus on these plugin categories:&lt;/li&gt;
&lt;li&gt;Camera/Media: &lt;code&gt;camera, image_picker, video_player&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Database: &lt;code&gt;sqflite, hive, objectbox&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Networking: &lt;code&gt;dio&lt;/code&gt;with native interceptors&lt;/li&gt;
&lt;li&gt;Firebase: All Firebase plugins&lt;/li&gt;
&lt;li&gt;Maps: &lt;code&gt;google_maps_flutter&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Payment: &lt;code&gt;stripe_android&lt;/code&gt;, payment gateway SDKs&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>flutter</category>
      <category>android</category>
      <category>androiddev</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Navigating the Journey: Becoming a Mobile App Developer</title>
      <dc:creator>Michael Otieno Olang</dc:creator>
      <pubDate>Sun, 31 Mar 2024 15:42:25 +0000</pubDate>
      <link>https://dev.to/mikeyolang/navigating-the-journey-becoming-a-mobile-app-developer-4f2l</link>
      <guid>https://dev.to/mikeyolang/navigating-the-journey-becoming-a-mobile-app-developer-4f2l</guid>
      <description>&lt;p&gt;We'll embark on a journey together into the realm of mobile app development. In today's digital age, mobile applications have become an integral part of our daily lives, from communication and entertainment to productivity and commerce. If you've ever wondered what it takes to create these innovative tools that reside in our pockets, you're in the right place. In this guide, we'll explore the steps, tools, and resources you need to kickstart your career as a mobile app developer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the Landscape:
&lt;/h2&gt;

&lt;p&gt;Before diving into the technical aspects, it's crucial to grasp the landscape of mobile app development. Mobile platforms such as iOS and Android dominate the market, each with its own set of development tools, languages, and guidelines. Additionally, cross-platform frameworks like React Native and Flutter offer the ability to build apps for multiple platforms using a single codebase. Understanding these options will help you chart your path forward.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learning the Fundamentals:
&lt;/h2&gt;

&lt;p&gt;As with any craft, mastering the fundamentals is essential for success. Start by familiarizing yourself with programming languages commonly used in mobile app development, such as Java, Kotlin, Swift, or Dart. Online platforms like Codecademy, Udemy, and Coursera offer comprehensive courses tailored to beginners.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing Your Platform:
&lt;/h2&gt;

&lt;p&gt;Once you've gained a solid understanding of programming fundamentals, it's time to choose your platform. Are you drawn to the sleek design and user experience of iOS apps, or do you prefer the flexibility and customization options of Android? Your decision will influence the tools and technologies you'll need to learn next.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exploring Development Tools:
&lt;/h2&gt;

&lt;p&gt;Equipped with a programming language and platform of choice, it's time to explore the development tools available to you. For iOS development, Xcode is the primary Integrated Development Environment (IDE) used by developers, while Android Studio is the go-to choice for Android development. Additionally, familiarize yourself with version control systems like Git, which are indispensable for collaborative development.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mastering Mobile UI/UX Design:
&lt;/h2&gt;

&lt;p&gt;In the competitive world of mobile apps, user interface (UI) and user experience (UX) design play a crucial role in determining the success of your app. Learn the principles of mobile UI/UX design, including navigation patterns, typography, and usability testing. Tools like Sketch, Figma, and Adobe XD can aid in prototyping and designing your app's interface.&lt;/p&gt;

&lt;h2&gt;
  
  
  Embracing Continuous Learning:
&lt;/h2&gt;

&lt;p&gt;Mobile app development is a dynamic field that constantly evolves with new technologies and trends. Embrace a mindset of continuous learning by staying updated on the latest developments, attending conferences, and participating in online communities. Engage with fellow developers, seek mentorship, and don't be afraid to experiment with new ideas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building Your Portfolio:
&lt;/h2&gt;

&lt;p&gt;As you gain proficiency in mobile app development, start building a portfolio of projects to showcase your skills to potential employers or clients. Whether it's a personal project, freelance work, or contributions to open-source projects, a strong portfolio demonstrates your capabilities and passion for the craft.&lt;/p&gt;

</description>
      <category>mobile</category>
      <category>softwaredevelopment</category>
      <category>career</category>
      <category>learning</category>
    </item>
    <item>
      <title>Excited to share insights on Android Development Testing!</title>
      <dc:creator>Michael Otieno Olang</dc:creator>
      <pubDate>Mon, 11 Mar 2024 08:55:59 +0000</pubDate>
      <link>https://dev.to/mikeyolang/excited-to-share-insights-on-android-development-testing-3ahn</link>
      <guid>https://dev.to/mikeyolang/excited-to-share-insights-on-android-development-testing-3ahn</guid>
      <description>&lt;p&gt;In the world of mobile app development, ensuring seamless user experiences is paramount. That's why Testing on Android development holds such crucial significance. 🛠️&lt;/p&gt;

&lt;p&gt;Here are some key points I'd like to highlight:&lt;/p&gt;

&lt;p&gt;1️⃣ Unit Testing: Building robust and reliable code starts here. Unit testing allows developers to test individual components in isolation, ensuring they function as expected.&lt;/p&gt;

&lt;p&gt;2️⃣ Integration Testing: Assembling the pieces of your app? Integration testing ensures that these components work together seamlessly, catching any potential conflicts or issues.&lt;/p&gt;

&lt;p&gt;3️⃣ UI Testing: Your app's interface is the user's gateway to functionality. UI testing verifies that each element behaves as intended, providing a smooth and intuitive experience.&lt;/p&gt;

&lt;p&gt;4️⃣ Automation: Embracing automation accelerates testing cycles and enhances efficiency. Tools like Espresso and Robolectric streamline testing processes, enabling developers to focus more on innovation.&lt;/p&gt;

&lt;p&gt;5️⃣ Device Fragmentation: Testing across various devices and OS versions is key to ensuring compatibility and performance consistency. Emulators and real-device testing help tackle this challenge effectively.&lt;/p&gt;

&lt;p&gt;Incorporating these testing strategies into your Android development workflow not only enhances the quality of your app but also boosts user satisfaction and retention. &lt;/p&gt;

</description>
      <category>testing</category>
      <category>android</category>
      <category>flutter</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>A Simple Dart Tutorial</title>
      <dc:creator>Michael Otieno Olang</dc:creator>
      <pubDate>Wed, 11 Oct 2023 18:57:32 +0000</pubDate>
      <link>https://dev.to/mikeyolang/a-simple-dart-tutorial-5ho2</link>
      <guid>https://dev.to/mikeyolang/a-simple-dart-tutorial-5ho2</guid>
      <description>&lt;h2&gt;
  
  
  Dart Tutorial
&lt;/h2&gt;

&lt;p&gt;Welcome to the Dart Tutorial! This tutorial is designed to help you get started with Dart programming. Whether you're a beginner or an experienced developer, you'll find valuable information here to enhance your skills in Dart.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Dart Tutorial&lt;/li&gt;
&lt;li&gt;Table of Contents&lt;/li&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Prerequisites&lt;/li&gt;
&lt;li&gt;Getting Started&lt;/li&gt;
&lt;li&gt;Topics Covered&lt;/li&gt;
&lt;li&gt;
Dart Basics

&lt;ul&gt;
&lt;li&gt;1. Hello, Dart!&lt;/li&gt;
&lt;li&gt;2. Variables and Data Types&lt;/li&gt;
&lt;li&gt;3. Control Flow&lt;/li&gt;
&lt;li&gt;4. Functions&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Contributing&lt;/li&gt;

&lt;li&gt;Happy coding!&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Dart is a modern, open-source programming language developed by Google. It's known for its speed, efficiency, and ease of learning. Dart can be used for web, mobile, server, and desktop applications.&lt;/p&gt;

&lt;p&gt;This tutorial aims to provide a comprehensive introduction to Dart, covering the basics and gradually progressing to more advanced concepts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before starting this tutorial, make sure you have the following prerequisites:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Basic understanding of programming concepts&lt;/li&gt;
&lt;li&gt;Code editor (e.g., Visual Studio Code, IntelliJ IDEA)&lt;/li&gt;
&lt;li&gt;Dart SDK installed on your system&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you haven't installed Dart SDK yet, you can download it from the &lt;a href="https://dart.dev/get-dart" rel="noopener noreferrer"&gt;official Dart website&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;To get started with Dart, follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://dart.dev/get-dart" rel="noopener noreferrer"&gt;Install Dart SDK&lt;/a&gt; on your system.&lt;/li&gt;
&lt;li&gt;Set up your development environment by configuring a code editor (e.g., Visual Studio Code) for Dart.&lt;/li&gt;
&lt;li&gt;Clone this &lt;a href="https://github.com/mikeyolang/Dart-Tutorial.git" rel="noopener noreferrer"&gt;repository&lt;/a&gt;`&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Topics Covered
&lt;/h2&gt;

&lt;p&gt;This tutorial covers the following topics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dart basics&lt;/li&gt;
&lt;li&gt;Variables and data types&lt;/li&gt;
&lt;li&gt;Control flow (if-else, switch, loops)&lt;/li&gt;
&lt;li&gt;Functions and error handling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Feel free to explore the code and documentation for each topic in detail.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dart Basics
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Hello, Dart!
&lt;/h3&gt;

&lt;p&gt;The traditional "Hello, World!" program in Dart:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;dart&lt;br&gt;
void main() {&lt;br&gt;
  print('Hello, Dart!');&lt;br&gt;
}&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Variables and Data Types
&lt;/h3&gt;

&lt;p&gt;In Dart, you can declare variables using &lt;code&gt;var&lt;/code&gt;, &lt;code&gt;int&lt;/code&gt;, &lt;code&gt;double&lt;/code&gt;, &lt;code&gt;String&lt;/code&gt;, &lt;code&gt;bool&lt;/code&gt;, and more. Example:&lt;br&gt;
&lt;code&gt;&lt;/code&gt;&lt;code&gt;dart&lt;br&gt;
void main() {&lt;br&gt;
  var name = 'John Doe';  // String&lt;br&gt;
  int age = 30;           // Integer&lt;br&gt;
  double height = 6.2;     // Double&lt;br&gt;
  bool isStudent = true;   // Boolean&lt;br&gt;
}&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;br&gt;
Dart is a statically typed language, meaning that variable types are known at compile time. However, you can use &lt;code&gt;var&lt;/code&gt; to have Dart infer the type.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Control Flow
&lt;/h3&gt;

&lt;p&gt;Dart supports common control flow structures like &lt;code&gt;if&lt;/code&gt;, &lt;code&gt;else&lt;/code&gt;, &lt;code&gt;switch&lt;/code&gt;, and &lt;strong&gt;loops&lt;/strong&gt; (&lt;code&gt;for&lt;/code&gt;, &lt;code&gt;while&lt;/code&gt;, &lt;code&gt;do-while&lt;/code&gt;). Example:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`dart&lt;br&gt;
void main() {&lt;br&gt;
  var age = 30;&lt;/p&gt;

&lt;p&gt;if (age &amp;lt; 18) {&lt;br&gt;
    print('You are a minor.');&lt;br&gt;
  } else if (age &amp;gt;= 18 &amp;amp;&amp;amp; age &amp;lt; 60) {&lt;br&gt;
    print('You are an adult.');&lt;br&gt;
  } else {&lt;br&gt;
    print('You are a senior citizen.');&lt;br&gt;
  }&lt;br&gt;
}&lt;br&gt;
`&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Functions
&lt;/h3&gt;

&lt;p&gt;Creating a simple function in Dart:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`dart&lt;br&gt;
    void main() {&lt;br&gt;
      print(greet('John Doe'));&lt;br&gt;
    }&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;String greet(String name) {
  return 'Hello, $name!';
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;`&lt;code&gt;&lt;/code&gt;&lt;br&gt;
Dart also supports &lt;strong&gt;anonymous functions&lt;/strong&gt; (functions without a name) and &lt;strong&gt;arrow functions&lt;/strong&gt; (functions with a single expression). Example:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`dart&lt;br&gt;
void main() {&lt;br&gt;
  var numbers = [1, 2, 3, 4, 5];&lt;/p&gt;

&lt;p&gt;// Anonymous function&lt;br&gt;
  numbers.forEach((number) {&lt;br&gt;
    print(number);&lt;br&gt;
  });&lt;/p&gt;

&lt;p&gt;// Arrow function&lt;br&gt;
  numbers.forEach((number) =&amp;gt; print(number));&lt;br&gt;
}&lt;br&gt;
`&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Contributing
&lt;/h2&gt;

&lt;p&gt;If you find any issues or have suggestions for improvement, please feel free to open an issue or create a pull request in my &lt;a href="https://github.com/mikeyolang/Dart-Tutorial.git" rel="noopener noreferrer"&gt;GitHub Repository&lt;/a&gt;. We welcome contributions from the community to make this tutorial even better!&lt;/p&gt;

&lt;p&gt;To contribute, follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fork the repository.&lt;/li&gt;
&lt;li&gt;Create a new branch for your contribution.&lt;/li&gt;
&lt;li&gt;Make your changes and commit them.&lt;/li&gt;
&lt;li&gt;Push the changes to your fork.&lt;/li&gt;
&lt;li&gt;Open a pull request with a detailed description of your contribution.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Happy coding!
&lt;/h2&gt;

</description>
      <category>tutorial</category>
      <category>dart</category>
      <category>beginners</category>
      <category>codenewbie</category>
    </item>
    <item>
      <title>My Flutter Journey</title>
      <dc:creator>Michael Otieno Olang</dc:creator>
      <pubDate>Thu, 02 Mar 2023 22:14:53 +0000</pubDate>
      <link>https://dev.to/mikeyolang/my-flutter-journey-372f</link>
      <guid>https://dev.to/mikeyolang/my-flutter-journey-372f</guid>
      <description>&lt;p&gt;Flutter is a framework based on dart and developed by google for creating cross-platform applications. It can be used to create android, iOS, Windows, Mac OS, and Linux applications under one code base. It also uses Firebase as its back-end but you can also use the various back-end tech stacks for your back- end such as node js and many others.&lt;/p&gt;

&lt;p&gt;I was introduced to flutter 4 months ago by a tech friend who by that time was using Kotlin to develop mobile applications, majorly android applications. We were to create our association's Mobile app within a week and he suggested that for ease and productivity we use the flutter framework for the app. We were both new to the framework but we really wanted to try out this new mobile development technique. We had downloaded a number of YouTube crash courses and some clone apps tutorials.&lt;/p&gt;

&lt;p&gt;I never knew what I was doing, I never knew what was happening but I could only follow the YouTube tutor. After some two days, our UI was done and we presented the app as our project&lt;/p&gt;

&lt;p&gt;I am still a beginner in the field but these are some of the advantages of Flutter I have noticed so far;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Flutter is easy to learn&lt;/li&gt;
&lt;li&gt;Flutter has a great UI design which is simple to implement&lt;/li&gt;
&lt;li&gt;Flutter uses widgets&lt;/li&gt;
&lt;li&gt;Running Apps is relatively easy&lt;/li&gt;
&lt;li&gt;Its beginner friendly&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I would really advise you guys to try out Flutter&lt;br&gt;
Thank you&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>mobile</category>
      <category>android</category>
      <category>dart</category>
    </item>
    <item>
      <title>Creating a simple Linked List In C programming</title>
      <dc:creator>Michael Otieno Olang</dc:creator>
      <pubDate>Thu, 17 Nov 2022 14:00:57 +0000</pubDate>
      <link>https://dev.to/mikeyolang/creating-a-simple-linked-list-in-c-programming-49bc</link>
      <guid>https://dev.to/mikeyolang/creating-a-simple-linked-list-in-c-programming-49bc</guid>
      <description>&lt;p&gt;&lt;strong&gt;Linked Lists&lt;/strong&gt; are list of elements in which the various elements are linked together. Data in a linked list are stored in a &lt;strong&gt;linear manner&lt;/strong&gt;. The Data are placed in &lt;strong&gt;nodes&lt;/strong&gt; and the nodes are connected in a specific desired fashion.&lt;br&gt;
&lt;strong&gt;Node&lt;/strong&gt; is a container or a box which contains data and other information in it. In a list a node is connected to a different node forming a chain of nodes.&lt;br&gt;
The first step in making a linked list is making a node which will store data into it.&lt;br&gt;
&lt;strong&gt;C program for a Linked List&lt;/strong&gt;&lt;br&gt;
We first create a structure named node which stores an integer named data and a pointer named next to another structure (node).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;struct node
{
    int data;
    struct node *next;
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We then make two nodes (structure named node) and allocating space to them using the &lt;code&gt;malloc&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;struct node *a, *b;
    a = malloc(sizeof(struct node));
    b = malloc(sizeof(struct node));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We then set the values of data of the nodes a and b.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    a-&amp;gt;data = 10;
    b-&amp;gt;data = 20;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We then store the address of b in the next variable of a. Thus, next of a is now storing the address of b or we can say the next of a is pointing to b.Since there is no node for the next of b, so we are making next of b null.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    a-&amp;gt;next = b;
    b-&amp;gt;next = NULL;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We then Print to see the output&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;printf("%d\n%d\n", a-&amp;gt;data, a-&amp;gt;next-&amp;gt;data);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Below is the Combined Code&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmjrswjzdz4pcrvyhl8rc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmjrswjzdz4pcrvyhl8rc.png" alt=" " width="800" height="558"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>welcome</category>
      <category>beginners</category>
      <category>spanish</category>
    </item>
    <item>
      <title>Shell Programming Using C Programming Language</title>
      <dc:creator>Michael Otieno Olang</dc:creator>
      <pubDate>Sat, 11 Jun 2022 18:38:03 +0000</pubDate>
      <link>https://dev.to/mikeyolang/shell-programming-using-c-programming-language-4acb</link>
      <guid>https://dev.to/mikeyolang/shell-programming-using-c-programming-language-4acb</guid>
      <description>&lt;p&gt;The following C_Program is used to append text from one file to the end of another file. Does any one have an Idea on how I can implement the code using the &lt;strong&gt;COMMANDLINE ARGUMENTS&lt;/strong&gt; and the various &lt;strong&gt;FLAGS&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fazppxmjeb7qeugx87s8p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fazppxmjeb7qeugx87s8p.png" alt=" " width="800" height="1150"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>shellprogramming</category>
      <category>c</category>
      <category>programming</category>
      <category>unix</category>
    </item>
    <item>
      <title>A Must have Vs Code Extensions</title>
      <dc:creator>Michael Otieno Olang</dc:creator>
      <pubDate>Sat, 28 May 2022 15:39:35 +0000</pubDate>
      <link>https://dev.to/mikeyolang/a-must-have-vs-code-extensions-1h33</link>
      <guid>https://dev.to/mikeyolang/a-must-have-vs-code-extensions-1h33</guid>
      <description>&lt;ol&gt;
&lt;li&gt;Gitlens&lt;/li&gt;
&lt;li&gt;Better Comments&lt;/li&gt;
&lt;li&gt;Prettier&lt;/li&gt;
&lt;li&gt;ESLint
If there are any,kindly add them comment sections. &lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>webdev</category>
      <category>vscode</category>
    </item>
  </channel>
</rss>
