Hello! I recently completed a project where I created a Pomodoro timer app with Flutter and connected it to work on an Apple Watch. In the process, I encountered and solved several issues between the Flutter and native watchOS development environments. I’m documenting this journey to help other developers who might face similar struggles.
Initial Design: Where Flutter Meets Native
The first thing to realize is that Flutter doesn’t directly build watchOS apps. Therefore, our architecture was set up as follows:
- iPhone App: Built with Flutter (handling all core logic and data management).
- Apple Watch App: Built with SwiftUI in Xcode (acting as a remote control to display data from the iPhone app and send simple control commands).
These two communicate through a framework like watch_connectivity
. Now, let’s go through the problems I encountered in chronological order while building this structure.
Problem 1: ProviderNotFoundException
- Symptom: The app would crash immediately upon launch with a “Provider not found” error.
- Cause: This occurred because I used Hot Reload, which only partially applies changes, after modifying the app’s top-level structure in
main.dart
(such as setting up Providers). - Solution: Performing a Hot Restart, which reloads the entire app structure from scratch, solved the issue.
Problem 2: LateInitializationError
- Symptom: The app would crash if the
RESET
button was pressed before the timer had started. - Cause: The
_timer
variable, declared withlate
, was being accessed in thereset()
function (via_timer.cancel()
) before it had been initialized by thestart()
function. - Solution: I resolved this by adding a safety check (
if (_isRunning)
) in both thereset()
andpause()
functions to ensure the timer is active before attempting to use the_timer
variable.
Problem 3: Xcode Watch App Preview Failed
- Symptom: When trying to preview the watch UI (
ContentView.swift
) in Xcode, I got a “doesn’t match any of targeted device families” error. - Cause: Xcode’s execution target (Scheme) was still set to the iPhone app (
Runner
). Xcode was preparing to build for an iPhone, so the target device didn’t match when I tried to preview the watch screen. - Solution: I changed the Scheme at the top of Xcode from
Runner > iPhone...
toPomodoroWatchApp > Apple Watch...
.
Problem 4: CocoaPods Hell (pod install
failure)
- Symptom: The
pod install
command itself kept failing with errors likeModule not found
orUnable to find compatibility version
. This was the longest and most challenging problem. - Cause: It was a combination of multiple issues:
- Missing Podfile Version: The
platform :ios
version was not specified in thePodfile
, causing it to default to an older version and conflict with other plugins. - CocoaPods and Xcode Version Incompatibility: An older version of CocoaPods couldn’t understand the project files created by the latest Xcode.
- A Deeply Tangled Local Environment: The system’s Ruby environment itself had issues that couldn’t be fixed with a simple
sudo gem install
.
- Missing Podfile Version: The
- Solution: I essentially rebuilt my development environment through the following steps:
- Explicitly set the minimum deployment target in
ios/Podfile
, likeplatform :ios, '14.0'
. - Completely uninstalled CocoaPods (
sudo gem uninstall cocoapods
) and de-integrated it from the project (pod deintegrate
). - Used
rbenv
andHomebrew
to build a new, clean Ruby environment separate from the system, and then reinstalled CocoaPods on top of it. This was the final solution.
- Explicitly set the minimum deployment target in
Problem 5: Circular Dependency Error (Cycle inside Runner
)
- Symptom: When building the watch app, a circular dependency error occurred, stating something like, “to build A, you need B, and to build B, you need A.”
- Cause: Flutter’s build script was conflicting with Xcode’s
Embed Watch Content
build phase. - Solution: In Xcode, I navigated to the
Runner
target’s[Build Phases] > [Embed Watch Content]
section and removed the watch app file from the list using the—
button. This removed the redundant step, letting Flutter’s build process handle it correctly.
Problem 6: Minimum Deployment Target Error (is only available in iOS 14.0 or newer
)
- Symptom: The compiler threw an error because newer SwiftUI code was incompatible with the project’s minimum deployment target.
- Cause: The version change was missed in one or two places across the Podfile or Xcode project settings.
- Solution: In Xcode’s
[Build Settings]
tab, I searched for “Deployment Target” and unified the minimum version toiOS 14.0
andwatchOS 7.0
for all targets in the project (iPhone, Watch, etc.).
Problem 7: Failed to Run on Physical Device (Unable to find target device
)
- Symptom: The app failed to run on a physical iPhone, with an error stating the device could not be found.
- Cause: The issue was an unstable wireless debugging connection.
- Solution: Switching to a stable wired connection by directly linking the Mac and iPhone with a USB cable resolved it immediately.
Closing Thoughts
Developing with Flutter and native watchOS together was an experience that went beyond simply knowing two technologies. By solving the various environment configuration issues that arise at the intersection of these two ecosystems, I gained a deeper understanding of how Xcode and CocoaPods work.
I hope this post can save precious time for other developers taking on the challenge of integrating Flutter with watchOS.
Reference
https://heavenly.tistory.com/entry/Flutter와-watchOS-연동-개발-좌충우돌-문제-해결-과정-총정리
“Flutter & watchOS: A Deep Dive into My Troubleshooting Journey”에 대한 1개의 생각