Flutter is Google’s cross platform development framework. It uses the Dart programming language to create apps for iOS, Android, Web, MacOS, Windows and Linux. There are many advantages to using Flutter. This blog post lists some of them. However, one of the perceived disadvantages of using Flutter, is the fact that it does not support building apps for the Apple Watch. While this is true, the team at Google has provided a way to do that. In this blog post, I will go through the steps required to add Apple Watch Support with Flutter. I will go through a scenario where an existing Flutter app is available, and add support for Apple Watch to it.
For this to work, you will need to make changes on the Flutter side in your preferred editor, like VSCode, (Dart code). And, you will also have to make changes on the iOS side in Xcode (Swift). The idea is that the Flutter code will interact with the native iOS code using messages passed back and forth between the two. This communication is possible through the MethodChannel
class on the Flutter side, and FlutterAppDelegate
class on the Swift side. In this post, I will only discuss sending messages from Flutter to the native code (the watch), but the other side of the communication uses the same concept.
Changes in Flutter
First step on the Flutter side is to add the following code in the class where you want to send data from:
static const channel = MethodChannel('channel_name');
In the above code, replace channel_name
with a name that you know will be unique on the user’s phone and watch. Ideally, the bundle ID of the app, which is usually your company’s domain name in reverse order. This name will be used whenever messages are exchanged between the app on the phone and on the watch. Depending on your existing code, you may have to add this import statement as well.
import 'package:flutter/services.dart';
Now that the channel of communication has been established, the next step is to actually send some data from Flutter to the watch. The below line of code does just that:
await channel.invokeMethod("flutterToWatch", { "method": method_name, "data": some_data });
Here, I’m invoking a method with the name method_name
, and sending some_data
. This is happening on a channel called flutterToWatch
, but it can be anything. Whatever name you choose, this will be the name that the iOS code will be looking for.
This is all that is required on the Flutter side. Next, we will talk about the changes that are required on the iOS (Xcode) side.
Changes in Xcode
First, open the workspace in Xcode. We will have to add a new project to the existing workspace. Go to File -> New -> Target

From this dialog, make sure you go to the watchOS
tab, and select App
. Then click Next.
From the next dialog, enter a Product Name and select your Team (assuming you are deploying the app to the App Store). And, make sure to select “Watch App for Existing iOS App”. After this step, you should have 2 targets in your Xcode project, one for iPhone (Runner) and a new one for the Watch.
Select the Watch target and click on the Info tab. You should have the following key, WKCompanionAppBundleIdentifier
with a value that’s equal to the bundle ID of the iPhone app. And, the Bundle ID of the Watch app should be the bundle ID of the iPhone app followed by .watchkitapp
exactly.
Next, open the AppDelegate.swift
file and make some modifications. Below is how the file should look like after you complete all the modifications:
import UIKit
import Flutter
import WatchConnectivity
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
var session: WCSession?
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?
) -> Bool {
initFlutterChannel()
if WCSession.isSupported() {
session = WCSession.default;
session?.delegate = self;
session?.activate();
}
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
private func initFlutterChannel() {
if let controller = window?.rootViewController as? FlutterViewController {
let channel = FlutterMethodChannel(
name: "channel_name",
binaryMessenger: controller.binaryMessenger)
channel.setMethodCallHandler({ [weak self] (
call: FlutterMethodCall,
result: @escaping FlutterResult) -> Void in
switch call.method {
case "method_name":
guard let watchSession = self?.session, watchSession.isPaired, watchSession.isReachable, let methodData = call.arguments as? [String: Any], let method = methodData["method"], let data = methodData["data"] else {
result(false)
return
}
let watchData: [String: Any] = ["method": method, "data": data]
// Pass the receiving message to Apple Watch
watchSession.sendMessage(watchData, replyHandler: nil, errorHandler: nil)
result(true)
default:
result(FlutterMethodNotImplemented)
}
})
}
}
}
extension AppDelegate: WCSessionDelegate {
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
}
func sessionDidBecomeInactive(_ session: WCSession) {
}
func sessionDidDeactivate(_ session: WCSession) {
}
func session(_ session: WCSession, didReceiveMessage message: [String : Any]) {
DispatchQueue.main.async {
if let method = message["method"] as? String, let controller = self.window?.rootViewController as? FlutterViewController {
let channel = FlutterMethodChannel(
name: "channel_name",
binaryMessenger: controller.binaryMessenger)
channel.invokeMethod(method, arguments: message)
}
}
}
}
From the above code, replace channel_name
and method_name
with the same values that you used in the Dart code on the Flutter side.
That’s it! Now, you can receive the data that’s sent from the iPhone app and use it in the Watch app.
Running in Simulator
To actually run the project in the simulator, you have to do this from Xcode, which means you will not have support for Flutter hot reloading.
From the top of Xcode, change the target to the Watch app, and then click the Start button (play icon). It should look something like this:

If you have any questions, or face issues with this process, please feel free to contact me or comment here.