flutter_watch_connectivity

Define lightweight Apple Watch pages in Flutter, sync them to a paired Apple Watch with WatchConnectivity, and render them in a native SwiftUI watchOS app.

Flutter widgets do not run on Apple Watch. This package sends a portable page schema from the iPhone app; the Watch App target renders that schema natively with the included SwiftUI renderer.

What this package does

  • Lets your Flutter app define watch pages with Dart models.
  • Sends those pages from iPhone to Apple Watch through WCSession.
  • Provides a SwiftUI renderer file for the Watch App target.
  • Supports basic watch components: text, buttons, spacers, and dividers.

What you still need to do

Apple requires a real watchOS target. A Flutter package cannot automatically create or fully configure that target for the host app.

Every app using this package must do a one-time Xcode setup:

  • Add a Watch App target.
  • Add the renderer file to that Watch App target.
  • Link WatchConnectivity.framework.
  • Run the iOS app and the Watch App on paired devices or simulators.

Install

Add the package to your app:

dependencies:
  flutter_watch_connectivity: ^0.0.1

Then run:

flutter pub get

Define watch pages in Flutter

import 'package:flutter_watch_connectivity/flutter_watch_connectivity.dart';

const watch = FlutterWatchConnectivity();

Future<void> syncWatchPages() async {
  await watch.configurePages(
    initialPageId: 'home',
    pages: const [
      WatchPage(
        id: 'home',
        title: 'Daily summary',
        components: [
          WatchText('1,248 steps', style: WatchTextStyle.largeTitle),
          WatchText('Move ring is 72% complete.'),
          WatchSpacer(height: 10),
          WatchButton(title: 'Refresh', action: 'refresh_summary'),
        ],
      ),
      WatchPage(
        id: 'hydration',
        title: 'Hydration',
        components: [
          WatchText('4 cups logged', style: WatchTextStyle.title),
          WatchDivider(),
          WatchText('Goal: 8 cups'),
          WatchButton(title: 'Add cup', action: 'add_water'),
        ],
      ),
    ],
  );
}

Future<void> showHydrationPage() {
  return watch.showPage('hydration');
}

Call configurePages(...) when your app has the data that should appear on the watch. The package stores the latest payload in the watch connectivity application context, so the watch can read it when it opens.

Add the Watch App target

Open the iOS workspace:

open ios/Runner.xcworkspace

In Xcode:

  1. Select the blue project icon.
  2. Choose File -> New -> Target.
  3. Select watchOS -> Watch App.
  4. Create the watch target for your iOS app.
  5. Use SwiftUI for the Watch App interface.

Add the renderer to the Watch App

Copy this file from the package into your Watch App target:

watchos/WatchConnectivityPageRenderer.swift

When adding the file in Xcode, make sure target membership is checked for the Watch App target, not only for the iOS Runner target.

Then replace your Watch App entry point with:

import SwiftUI

@main
struct MyWatchApp: App {
  var body: some Scene {
    WindowGroup {
      WatchPageRenderer()
    }
  }
}

You can keep your own app struct name. The important part is that the watch window shows WatchPageRenderer().

Some Xcode versions do not show a Watch Connectivity capability. That is OK. Link the framework instead.

For the iOS app target:

  1. Select the iOS app target, usually Runner.
  2. Open General.
  3. Find Frameworks, Libraries, and Embedded Content.
  4. Click +.
  5. Add WatchConnectivity.framework.

For the Watch App target:

  1. Select the Watch App target.
  2. Open General.
  3. Find Frameworks, Libraries, and Embedded Content.
  4. Click +.
  5. Add WatchConnectivity.framework.

If you do not see that section, use:

Build Phases -> Link Binary With Libraries -> + -> WatchConnectivity.framework

Check build phase order

If your iOS app target has a watch companion app, Xcode can produce a dependency cycle if the watch app is embedded after Flutter's Thin Binary script.

For the iOS app target, open Build Phases and keep this order:

Run Script
Sources
Frameworks
Resources
Embed Frameworks
Embed Watch Content
Thin Binary

If Embed Watch Content is below Thin Binary, drag it above Thin Binary. Then run Product -> Clean Build Folder.

Run on simulators

You need a paired iPhone simulator and Apple Watch simulator.

  1. Open Xcode.
  2. Select the iOS app scheme, usually Runner.
  3. Select a paired iPhone simulator.
  4. Run the iOS app.
  5. Press the button in your app that calls configurePages(...).
  6. Select the Watch App scheme.
  7. Select the paired Apple Watch simulator.
  8. Run the Watch App.

The watch should show the latest page sent by the iOS app.

You can also build from the command line, but Flutter needs a concrete paired simulator id when the app has a watch companion:

flutter devices
flutter run -d <iphone-simulator-id>

Run on real devices

  1. Pair your real Apple Watch with your iPhone.
  2. Open ios/Runner.xcworkspace in Xcode.
  3. Select the iOS app target and set signing.
  4. Select the Watch App target and set signing.
  5. Run the iOS app on the iPhone.
  6. Run or install the Watch App on the paired Apple Watch.
  7. Open the iOS app and call configurePages(...).
  8. Open the Watch App.

If the watch opens first, it may show:

Open the iPhone app to sync watch pages.

Open the iOS app and sync pages again.

Test this package locally

From the package root:

flutter analyze
flutter test
flutter pub publish --dry-run

From the example app:

cd example
flutter test test

To compile only the example Watch App target:

cd example/ios
xcodebuild -project Runner.xcodeproj \
  -target "RunnerWatchApp Watch App" \
  -configuration Debug \
  -destination generic/platform=watchOS \
  build

Supported components

WatchText

const WatchText('Hello watch');
const WatchText('Big number', style: WatchTextStyle.largeTitle);

WatchButton

const WatchButton(title: 'Refresh', action: 'refresh');

Button taps are sent by the SwiftUI renderer as action messages. A Dart action stream is planned, but not exposed yet.

WatchSpacer

const WatchSpacer(height: 12);

WatchDivider

const WatchDivider();

Troubleshooting

I do not see a Watch Connectivity capability

That is normal in many Xcode versions. Add WatchConnectivity.framework to both the iOS app target and the Watch App target.

Cycle inside Runner

Move Embed Watch Content above Thin Binary in the iOS app target's build phases, then clean the build folder.

The watch shows the empty message

Run the iOS app and call configurePages(...). The watch needs page data from the phone before it can render anything.

The watch layout looks old after changing the renderer

In Xcode, run Product -> Clean Build Folder, then rebuild the Watch App.

Can this package create the Watch App target automatically?

No. Flutter packages cannot create or fully configure host app Xcode targets. The one-time Watch App target setup must be done in Xcode.