🕵️ SicherheitslückenCVE-2024-33668 | Zammad up to 6.2.x Upload Cache excessive authentication(17.09.2026 um 02:15 Uhr)
🕵️ SicherheitslückenCVE-2024-33668 | Zammad up to 6.2.x Upload Cache excessive authentication(17.09.2026 um 02:15 Uhr)
🔧 Programmierung 🕛 vor 2 Monaten 16 Min Lesezeit
0

Apple Watch & iMessage Integration in Flutter

↗ Quelle (dev.to)
🗣️ Stimme:
📑 Inhaltsübersicht




A Complete Developer Guide




App Bundle ID: com.example.demoapp

App Group: group.com.example.demoapp

Targets: Runner (iPhone) · DemoWatch Watch App · DemoMessages MessagesExtension










Table of Contents




  1. Architecture Overview

  2. Dependencies Added

  3. Xcode Setup (One-Time)


  4. Apple Watch Integration


    • 4.1 Flutter Side — WatchService

    • 4.2 Syncing Data to the Watch

    • 4.3 Listening for Watch Actions in Flutter

    • 4.4 Native Watch UI (SwiftUI)

    • 4.5 Watch Face Complications




  5. iMessage Integration


    • 5.1 Flutter Side — IMessageSyncService

    • 5.2 Syncing Trip Data for iMessage

    • 5.3 Native iMessage UI (UIKit/Swift)



  6. Data Flow Diagrams

  7. Publishing to the App Store

  8. Build & Archive Checklist

  9. Troubleshooting & Challenges Experienced









1. Architecture Overview



Flutter cannot run its UI engine on Apple Watch or inside iMessage extensions. Instead, we use two communication bridges:























Extension Bridge Technology Direction
Apple Watch
WatchConnectivity framework via watch_connectivity Flutter package
iPhone ↔ Watch (two-way, real-time)
iMessage
App Groups shared UserDefaults container via shared_preference_app_group package
Flutter → iMessage (one-way, cached)





CODE
┌─────────────────────┐         WatchConnectivity          ┌─────────────────────┐
│ Flutter App │ ◄──────────────────────────────► │ DemoWatch App │
│ (iPhone) │ │ (Apple Watch) │
└─────────────────────┘ └─────────────────────┘

│ App Groups (UserDefaults)
│ group.com.example.demoapp

┌─────────────────────┐
│ iMessage Extension │
│ DemoMessages │
└─────────────────────┘












2. Dependencies Added



The following packages were added to



This service is the bridge between your Flutter app and the Apple Watch.




CODE
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:watch_connectivity/watch_connectivity.dart';

class WatchService {
final WatchConnectivity _watch = WatchConnectivity();
StreamSubscription<Map<String, dynamic>>? _messageSubscription;

// All raw messages from the Watch
final _messageController = StreamController<Map<String, dynamic>>.broadcast();
Stream<Map<String, dynamic>> get messageStream => _messageController.stream;

// Only action commands from the Watch (e.g., quick_book, cancel_booking)
final _actionController = StreamController<Map<String, dynamic>>.broadcast();
Stream<Map<String, dynamic>> get actionStream => _actionController.stream;

WatchService() {
_messageSubscription = _watch.messageStream.listen((message) {
_messageController.add(message);
if (message.containsKey('action')) {
_actionController.add(message);
}
});
}

Future<bool> isSupported() async => await _watch.isSupported;
Future<bool> isReachable() async => await _watch.isReachable;

void dispose() {
_messageSubscription?.cancel();
_messageController.close();
_actionController.close();
}
}









4.2 Syncing Data to the Watch



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




CODE
final watchService = WatchService();

await watchService.syncTravelData(
walletBalance: 125.50,
walletCurrency: 'Ksh',
nextTripDestination: 'Nairobi → Mombasa',
nextTripDate: 'Aug 12, 2026',
nextTripTime: '08:30 AM',
nextTripSeat: '14B',
qrCodeData: 'TICKET-XYZ-12345', // the raw ticket/QR string
activeBookingsCount: 2,
unreadNotifications: 3,
);






Best places to call this:




  • After a successful booking API response

  • After the user tops up their wallet

  • In your home screen initState() when the app opens






4.3 Listening for Watch Actions in Flutter



When the user presses Quick Book or Cancel on the Apple Watch, the Watch sends a message to Flutter via actionStream. Listen to this in your BLoC, provider, or main widget tree:




CODE
final watchService = WatchService();

watchService.actionStream.listen((actionData) {
final action = actionData['action'] as String?;

switch (action) {
case 'quick_book':
// Trigger your booking flow / open the booking screen
NavigationKeys.mainNav.currentState?.pushNamed('/booking');
break;

case 'cancel_booking':
final destination = actionData['destination'] as String?;
// Call your cancel API
context.read<BookingBloc>().add(CancelBookingEvent(destination: destination));
break;
}
});









4.4 Native Watch UI (SwiftUI)



File:



The WatchViewModel is the native Swift equivalent of WatchService. It implements WCSessionDelegate to receive data from Flutter and manages all published state for the SwiftUI views.




CODE
// How the Watch receives data from Flutter:
func session(_ session: WCSession, didReceiveApplicationContext applicationContext: [String : Any]) {
DispatchQueue.main.async {
self.parseData(applicationContext)
}
}

// How the Watch sends actions back to Flutter:
func sendActionToFlutter(action: String, payload: [String: Any] = [:]) {
var message = payload
message["action"] = action
if session.isReachable {
session.sendMessage(message, replyHandler: nil, errorHandler: nil)
}
}









4.5 Watch Face Complications



File:



This service writes trip and wallet data into the shared App Group container so the iMessage extension can read them in Swift.




CODE
import 'dart:convert';
import 'package:shared_preference_app_group/shared_preference_app_group.dart';

const String _kAppGroup = 'group.com.example.demoapp';

class DemoTrip {
final String id;
final String destination;
final String origin;
final String date;
final String time;
final String seat;
final String qrCodeData;

DemoTrip({
required this.id,
required this.destination,
required this.origin,
required this.date,
required this.time,
required this.seat,
required this.qrCodeData,
});

Map<String, dynamic> toJson() => {
'id': id,
'destination': destination,
'origin': origin,
'date': date,
'time': time,
'seat': seat,
'qrCodeData': qrCodeData,
};
}

class IMessageSyncService {
static const String _tripsKey = 'demo_imessage_trips';
static const String _walletKey = 'demo_imessage_wallet';

// Call once at app startup (e.g. in main.dart)
Future<void> init() async {
await SharedPreferenceAppGroup.setAppGroup(_kAppGroup);
}

Future<void> syncAll({
required List<DemoTrip> trips,
required double walletBalance,
required String walletCurrency,
}) async {
await syncTrips(trips);
await syncWalletBalance(walletBalance, walletCurrency);
}

Future<void> syncTrips(List<DemoTrip> trips) async {
final encoded = jsonEncode(trips.map((t) => t.toJson()).toList());
await SharedPreferenceAppGroup.setString(_tripsKey, encoded);
}

Future<void> syncWalletBalance(double balance, String currency) async {
await SharedPreferenceAppGroup.setString(
_walletKey,
jsonEncode({'balance': balance, 'currency': currency}),
);
}
}









5.2 Syncing Trip Data for iMessage



Step 1 — Initialise once at app startup (e.g., in main.dart before runApp):




CODE
void main() async {
WidgetsFlutterBinding.ensureInitialized();

// ... existing initialisation ...

// Initialise iMessage sync
final iMessageSync = IMessageSyncService();
await iMessageSync.init();

runApp(const MyApp());
}






Step 2 — Sync whenever data changes:




CODE
final iMessageSync = IMessageSyncService();

await iMessageSync.syncAll(
walletBalance: 125.50,
walletCurrency: 'Ksh',
trips: [
DemoTrip(
id: 'booking-001',
origin: 'Nairobi',
destination: 'Mombasa',
date: 'Aug 12, 2026',
time: '08:30 AM',
seat: '14B',
qrCodeData: 'TICKET-XYZ-12345',
),
DemoTrip(
id: 'booking-002',
origin: 'Mombasa',
destination: 'Nairobi',
date: 'Aug 15, 2026',
time: '02:00 PM',
seat: '7A',
qrCodeData: 'TICKET-ABC-67890',
),
],
);









5.3 Native iMessage UI (UIKit/Swift)



File: ios/DemoMessages MessagesExtension/MessagesViewController.swift



The iMessage extension is built with UIKit. It:




  1. Reads trip and wallet data from UserDefaults(suiteName: "group.com.example.demoapp")

  2. Displays a scrollable list of upcoming trips

  3. When a trip is tapped, inserts a rich MSMessage bubble into the chat



Reading from the shared container in Swift:




CODE
let defaults = UserDefaults(suiteName: "group.com.example.demoapp")

// Read trips
if let tripsString = defaults?.string(forKey: "demo_imessage_trips"),
let data = tripsString.data(using: .utf8),
let rawList = try? JSONSerialization.jsonObject(with: data) as? [[String: Any]] {
trips = rawList.compactMap { DemoTrip(dict: $0) }
}

// Read wallet
if let walletString = defaults?.string(forKey: "demo_imessage_wallet"),
let data = walletString.data(using: .utf8),
let dict = try? JSONSerialization.jsonObject(with: data) as? [String: Any] {
walletBalance = dict["balance"] as? Double ?? 0
walletCurrency = dict["currency"] as? String ?? "Ksh"
}






Sending a rich iMessage bubble:




CODE
func sendTrip(_ trip: DemoTrip) {
guard let conversation = currentConversation else { return }

let message = MSMessage(session: conversation.selectedMessage?.session ?? MSSession())
let layout = MSMessageTemplateLayout()

layout.caption = "🚌 \(trip.origin)\(trip.destination)"
layout.subcaption = "\(trip.date) at \(trip.time)"
layout.trailingCaption = "Seat \(trip.seat)"
layout.trailingSubcaption = "Trip Booking"
layout.image = generateQRImage(from: trip.qrCodeData) // QR code

message.layout = layout
message.url = URL(string: "https://example.com")!

conversation.insert(message, completionHandler: nil)
}






Important: do not name your stored conversation property activeConversation. MSMessagesAppViewController already exposes an inherited activeConversation property. Use a separate name such as:




CODE
private var currentConversation: MSConversation?

override func willBecomeActive(with conversation: MSConversation) {
currentConversation = conversation
loadData()
}






What the recipient sees:



The recipient sees a custom rich bubble in their chat containing:





  • 🚌 Nairobi → Mombasa (caption)


  • Aug 12, 2026 at 08:30 AM (subcaption)


  • Seat 14B (trailing)

  • QR code image embedded in the bubble









6. Data Flow Diagrams






Apple Watch — Data Flow






CODE
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









iMessage — Data Flow






CODE
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)












7. Publishing to the App Store




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







Step-by-step publishing process:



Step 1 — Archive the app:




CODE
flutter build ipa






Or in Xcode: Product → Archive (with "Any iOS Device" selected as the destination).



Step 2 — Open Xcode Organizer:

After archiving, Xcode Organizer opens automatically. Select your archive and click Distribute App.



Step 3 — Upload to App Store Connect:

Choose App Store Connect → Upload. Follow the prompts. The Watch and iMessage extensions are included automatically.



Step 4 — Add Apple Watch Screenshots:

In App Store Connect, navigate to your app listing. You will now see a section for Apple Watch Screenshots. Take screenshots from the Watch Simulator in Xcode and upload them here. Apple requires these before the app can be reviewed.



Required Watch screenshot sizes:




  • 40mm: 394 × 324 px

  • 41mm: 352 × 430 px (Series 7/8/9)

  • 44mm: 368 × 448 px

  • 45mm: 396 × 484 px



Step 5 — Submit for Review:

Once screenshots are uploaded and everything looks good, click Submit for Review. Apple reviews the Watch and iMessage extensions as part of the same review process.







8. Build & Archive Checklist



Use this checklist before creating an App Store or TestFlight archive that includes Apple Watch and iMessage targets.





8.1 Before archiving




  • Open ios/Runner.xcworkspace, not ios/Runner.xcodeproj, when using Xcode manually.

  • Confirm the Runner scheme includes dependencies on:


    • DemoWatch Watch App

    • DemoMessages MessagesExtension



  • Confirm DemoWatch Watch App resolves as watchOS:


    • PLATFORM_NAME = watchos


    • BUILT_PRODUCTS_DIR contains Release-watchos

    • SUPPORTED_PLATFORMS = watchos watchsimulator



  • Confirm DemoMessages MessagesExtension resolves as iPhoneOS:


    • PLATFORM_NAME = iphoneos

    • PRODUCT_TYPE = com.apple.product-type.app-extension.messages



  • Confirm all targets share the App Group:


    • Runner

    • DemoWatch Watch App

    • DemoMessages MessagesExtension







8.2 Useful build-only verification



This command checks the Watch and iMessage target build path without running tests or static analysis:




CODE
xcodebuild build \
-project ios/Runner.xcodeproj \
-scheme "DemoWatch Watch App" \
-configuration Release \
-destination "generic/platform=watchOS" \
-derivedDataPath /tmp/travler-derived-data \
CODE_SIGNING_ALLOWED=NO






Successful Watch asset catalog output looks like:




CODE
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









8.3 What not to run for this workflow



For fast archive debugging, skip:




CODE
flutter test
flutter analyze
dart analyze






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.









9. Troubleshooting & Challenges Experienced






Watch data not updating?




  • Make sure syncTravelData() is being called after a booking or login.

  • Confirm the Watch app is installed on a paired Watch.

  • On a physical device, both the iPhone and Watch must be connected.

  • Check that the App Group group.com.example.demoapp is listed in both the Runner and Watch targets in Xcode.






iMessage extension shows "No upcoming trips"?




  • Make sure IMessageSyncService.init() is called at app startup before any sync calls.

  • Confirm syncAll() has been called at least once.

  • Verify the App Group identifier group.com.example.demoapp is set on both Runner and DemoMessages targets.

  • Double check the key names in Swift (demo_imessage_trips, demo_imessage_wallet) match the constants in Dart.






Watch face complications not appearing?




  • Confirm CLKComplicationDataSource = ComplicationController is set in the Watch target's Info.plist in Xcode.

  • Long-press your watch face → Edit → browse Complications for "DemoTravel".

  • After calling syncTravelData() in Flutter, the complication should update within seconds.






Build error: No such module 'CoreImage.CIFilterBuiltins'




  • This module does not exist on watchOS. Use plain import CoreImage instead.

  • Use CIFilter(name: "CIQRCodeGenerator") instead of CIFilter.qrCodeGenerator().

  • Use Image(cgImage:, scale:, label:) in SwiftUI instead of Image(uiImage:).






pod install fails with xcodeproj compatibility error?




  • This is a known CocoaPods issue with Xcode 26+. Run flutter run from the command line instead of pod install directly — Flutter's tooling handles the pod installation correctly.






Archive error: AppIcon did not have any applicable content



Symptom:




CODE
/ios/DemoWatch Watch App/Assets.xcassets:
The stickers icon set, app icon set, or icon stack named "AppIcon" did not have any applicable content.






Root causes seen in this project:




  1. The Watch target was resolving as iphoneos, so Xcode was trying to compile watch-only icon slots as iOS icons.

  2. The Watch AppIcon.appiconset/Contents.json only exposed watch-marketing content or incomplete watch slots.



Fix:




  • In ios/Runner.xcodeproj/project.pbxproj, ensure the DemoWatch Watch App target has:




CODE
SDKROOT = watchos;
SUPPORTED_PLATFORMS = "watchos watchsimulator";
TARGETED_DEVICE_FAMILY = 4;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;







  • In ios/DemoWatch Watch App/Assets.xcassets/AppIcon.appiconset/Contents.json, declare actual idiom: watch entries for notificationCenter, companionSettings, appLauncher, and quickLook, plus watch-marketing.

  • Confirm every filename referenced by Contents.json exists and has the expected pixel dimensions.



Verification:




CODE
jq empty "ios/DemoWatch Watch App/Assets.xcassets/AppIcon.appiconset/Contents.json"
sips -g pixelWidth -g pixelHeight "ios/DemoWatch Watch App/Assets.xcassets/AppIcon.appiconset/"*.png






Then confirm the target is not resolving as iPhoneOS:




CODE
xcodebuild -showBuildSettings \
-project ios/Runner.xcodeproj \
-scheme "DemoWatch Watch App" \
-configuration Release \
-destination "generic/platform=watchOS" \
-derivedDataPath /tmp/travler-derived-data \
| rg "PLATFORM_NAME|SDKROOT|SUPPORTED_PLATFORMS|BUILT_PRODUCTS_DIR"









Build error: No available simulator runtimes for platform watchsimulator



This can happen when actool runs in a restricted environment or Xcode cannot access simulator runtime services.



Symptoms:




CODE
No available simulator runtimes for platform watchsimulator.
SimServiceContext supportedRuntimes=[]






Fix:




  • Run the build from normal Terminal or Xcode, not a restricted sandbox.

  • Open Xcode once and let it finish installing components.

  • Check Xcode → Settings → Platforms and install the required watchOS simulator runtime if missing.

  • Use a device/generic watchOS destination for archive:




CODE
xcodebuild build \
-project ios/Runner.xcodeproj \
-scheme "DemoWatch Watch App" \
-configuration Release \
-destination "generic/platform=watchOS" \
-derivedDataPath /tmp/travler-derived-data \
CODE_SIGNING_ALLOWED=NO









Build error: activeConversation override in iMessage extension



Symptom:




CODE
overriding property must be as accessible as its enclosing type
cannot override with a stored property 'activeConversation'
ambiguous use of 'activeConversation'






Cause:



MSMessagesAppViewController already has an inherited activeConversation property. A stored property with the same name in MessagesViewController conflicts with it.



Fix:



Rename the custom property:




CODE
private var currentConversation: MSConversation?

override func willBecomeActive(with conversation: MSConversation) {
currentConversation = conversation
loadData()
}

private func sendTrip(_ trip: DemoTrip) {
guard let conversation = currentConversation else { return }
// insert MSMessage...
}









Build reaches Run Script and appears stuck



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



What to check:




  • Confirm previous failures are gone before interrupting. In the log, Watch asset success looks like Emplaced .../DemoWatch Watch App.app/Assets.car.

  • Run from a normal Terminal when possible so script phases can access the full user environment.

  • If the script is silent for several minutes, rerun with Xcode's report navigator open to see the exact active phase.






Documentation generated for DemoTravel v3.5.4 — Apple Watch & iMessage Integration

This sample project is provided for educational purposes.

Bundle ID: com.example.demoapp · App Group: group.com.example.demoapp

Vollständiger Original-Artikel
Den kompletten Beitrag mit allen Details direkt auf dev.to lesen.
↗ Original-Artikel auf dev.to lesen
Wie bewertest du diesen Beitrag?
1 Klick Feedback
Teilen mit Netzwerk & Team:

Community-Analysen & Experten-Meinungen 0

Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
Community Pulse: Relevanz-Einschätzung
1 Klick Experten-Votum
🔴 Akute Relevanz 0%
🟡 In Evaluierung 0%
🟢 Keine Auswirkung 0%
Spannende Innovation 0%
Verwandte Story-Cluster & Quellen (Vektor-KI)
Port 8095 Engine
3 Quellen
CVE-2020-20212 | MikroTik RouterOS 6.44.5 /nova/bin/console null pointer dereference
2 Quellen
CVE-2017-17537 | MikroTik RouterBOARD 6.39.2/6.40.5 TCP Service 53 input validation (EDB-43200 / ID 860320)
2 Quellen
CVE-2023-27169 | Xpand IT Write-Back Manager 2.3.1 hash predictable salt (EUVD-2023-30949)
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Apple Watch & iMessage Integration in Flutter

Thematisch verwandte Begriffe: Apple, Watch, iMessage, Integration · 6 Treffer

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...