What’s this about?
Soon, Xamarin will no longer support watchOS deployments. Because of this, you will need to develop a watch app using the native Swift project in Xcode.
However, getting a Xamarin/C# based phone app to deploy along with a native watchOS app is anything but intuitive. Very little documentation, and more questions than answers. Lots of people giving up and going with a full native solution. This guide is meant to help those development teams that either can’t go that route, or need to have a temporary workaround until they can fully develop a native solution.
Step 0: What do I need?
The following environment is expected:
- Visual Studio for Mac 2022
- Xamarin.iOS 16.1.1.27 (or greater)
- As of the writing of this post, 16.1.1.27 is currently the release candidate, and can be downloaded from here: https://github.com/xamarin/xamarin-macios/issues/16659
- Xcode 14.1 (or greater)
Step 1: Setup your folder structure
For the purposes of this guide, I’m going to assume that the project will be stored in the ~/Projects folder, and the name of the project is ExampleProject
Create a new folder named after your project. So ~/Projects/ExampleProject
Within that folder, create 2 more folders. Phone and Watch
Step 2: Create a new Xamarin.iOS Project
If you already have a Xamarin-based phone app, skip to step 3
Open Visual Studio and click New, then under iOS -> App -> Xamarin -> Single View App
Click Continue, then fill in the App name and update the Organization ID.
Uncheck “Put project file in a subfolder”, then click Browse, and find the Phone folder that you created earlier.
Step 3: Create watchOS Project
Open Xcode and choose “Create a new Xcode project”. Go to watchOS and select App, and click Next.
Enter the same project name and organization identifier that you used for the Phone app, and select Watch-only App
Place the project in the Watch folder that you created earlier.
Once you have the project open, go to File -> Project Settings, and changed the Derived Data location to “Project Relative”
Once you click Done and are back in the editor, click on the top project file in the file browser in Xcode, and select your Watch App target, then click on the Info tab.
Change the key for “App is only available as a standalone watchOS app” to “App can run independently of companion iPhone app”. Set the Value to “Yes” or “No”, depending on your use-case. Then right-click and click Add Row, and enter in the key “WKCompanionAppBundleIdentifier”, and set the value to the Bundle ID of the Xamarin phone app.
Step 4: Modify the Xamarin .csproj file to pull the watchOS App bundle
Back in Visual Studio, right-click on the Project (not the solution) and click Edit Project File. Add the following lines to the file:
<PropertyGroup>
<WatchAppProjectName>$(AssemblyName)</WatchAppProjectName>
<WatchAppBuildPath>$(MSBuildProjectDirectory)/../../../Watch/$(WatchAppProjectName)/DerivedData/$(WatchAppProjectName)/Build/Products/$(Configuration)-watchos</WatchAppBuildPath>
<WatchAppBundle>$(WatchAppProjectName) Watch App.app</WatchAppBundle>
<WatchAppBundleFullPath>$(WatchAppBuildPath)/$(WatchAppBundle)</WatchAppBundleFullPath>
</PropertyGroup>
<ItemGroup>
<_ResolvedWatchAppReferences Include="$(WatchAppBundleFullPath)" />
</ItemGroup>
<PropertyGroup Condition=" '$(_ResolvedWatchAppReferences)' != '' ">
<CodesignExtraArgs>--deep</CodesignExtraArgs>
</PropertyGroup>
If you named your watchOS project something different than the Xamarin app, you’ll want to replace the $(AssemblyName) reference with the name of the Xcode project.
Step 4: Build, Test, and Develop
From here, build the Xcode project (Cmd+B), then build and run the Xamarin project from Visual Studio. After the app is installed on your phone, open the Apple “Watch” app, scroll to the bottom, and install your app on the watch.
Once you have both apps installed, you can then run the Watch app from Xcode and debug it in real time. The initial install needs to happen from the app push first though, otherwise the phone app will not recognize that it’s installed.
I got an error!
The most common error that you’ll encounter while building this project is a vague “ditto” error.
This error is generated by the build target steps when trying to copy the Watch app bundle into the phone app during build. There’s a few things that can cause this.
- Visual Studio and Xcode have different build targets
- Check your build targets and make sure they’re both set to either a physical device, or to the same simulator target. Also make sure both are set to Debug or Release
- You used a different folder structure than what I have demonstrated
- You’ll need to modify the <WatchAppBuildPath> variable with the correct path. In my example I use a path relative to the current project directory. This path could be anywhere on your system that you have access to.
- The <WatchAppProjectName> variable isn’t getting set.
- If your solution looks like this:
then you need to move the Property and Item groups that you added for the Watch app down to the bottom of the file. - The resulting solution should look like this:
- If your solution looks like this:
Those are the most common scenarios that I found when attempting this project