Flutter & watchOS: A Deep Dive into My Troubleshooting Journey

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 with late, was being accessed in the reset() function (via _timer.cancel()) before it had been initialized by the start() function.
  • Solution: I resolved this by adding a safety check (if (_isRunning)) in both the reset() and pause() 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... to PomodoroWatchApp > Apple Watch....

Problem 4: CocoaPods Hell (pod install failure)

  • Symptom: The pod install command itself kept failing with errors like Module not found or Unable 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 the Podfile, 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.
  • Solution: I essentially rebuilt my development environment through the following steps:
    1. Explicitly set the minimum deployment target in ios/Podfile, like platform :ios, '14.0'.
    2. Completely uninstalled CocoaPods (sudo gem uninstall cocoapods) and de-integrated it from the project (pod deintegrate).
    3. Used rbenv and Homebrew to build a new, clean Ruby environment separate from the system, and then reinstalled CocoaPods on top of it. This was the final solution.

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 to iOS 14.0 and watchOS 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-연동-개발-좌충우돌-문제-해결-과정-총정리

댓글 남기기