Xcode 26 的 Apple Watch 应用如何连接 .NET 10 MAUI iOS 应用?
原生 watchOS 应用可以通过 WatchConnectivity 与 MAUI 的 iOS 应用通信。当前配置中有一处明确的问题:WKCompanionAppBundleIdentifier 应配置在 watchOS 应用中,值为 iOS 应用的 bundle ID。在 MAUI iOS 应用中添加同名键并指向手表应用,不能建立反向关联。
这处配置问题还不足以解释全部现象。需要确认 MAUI 最终安装的应用标识,以及读取日志时 WCSession 是否已经激活。仅凭现有片段无法确定唯一的根因。
三个状态的含义
| 状态 | 含义 |
|---|---|
Paired: True | iPhone 已配对 Apple Watch,不代表两个应用已建立伴侣关系 |
WatchAppInstalled: False | 如果会话已成功激活,系统没有识别到当前 iOS 应用对应的手表应用已安装在当前活动手表上 |
Reachable: False | 对端应用当前无法进行即时消息通信 |
WatchAppInstalled 的值只有在会话成功激活后才有判断意义。先记录激活状态,再判断应用关联是否失效。Apple:isWatchAppInstalled
1. 修正伴侣应用标识的配置位置
按照题目中的标识,预期关系如下:
iOS CFBundleIdentifier:
com.theclubreferee.ioswatch.watchme
watchOS CFBundleIdentifier:
com.theclubreferee.ioswatch.watchme.watchkitapp
watchOS WKCompanionAppBundleIdentifier:
com.theclubreferee.ioswatch.watchme
手表端贴出的两项设置方向正确:
PRODUCT_BUNDLE_IDENTIFIER = com.theclubreferee.ioswatch.watchme.watchkitapp;
INFOPLIST_KEY_WKCompanionAppBundleIdentifier = com.theclubreferee.ioswatch.watchme;
从 MAUI iOS 应用的 Info.plist 中移除下面这组键值:
<key>WKCompanionAppBundleIdentifier</key>
<string>com.theclubreferee.ioswatch.watchme.watchkitapp</string>
该键用于指定手表应用对应的 iOS 应用,不用于指定 iOS 应用对应的手表应用。还要检查 watchOS 构建产物中的 Info.plist,确认相关 Build Settings 生成了预期值。Apple:WKCompanionAppBundleIdentifier
2. 核对 MAUI 实际使用的 ApplicationId
先检查 .csproj 中的 ApplicationId,以及 Debug、Release 或平台条件下是否存在其他赋值。期望值为:
<PropertyGroup>
<ApplicationId>com.theclubreferee.ioswatch.watchme</ApplicationId>
</PropertyGroup>
将它合并到现有配置中,避免重复或冲突的定义。Microsoft 文档说明,设置 ApplicationId 会指定应用清单中的 CFBundleIdentifier,因此只查看源文件中的 Info.plist 不足以确认最终标识。Microsoft:ApplicationId
可以在 MAUI 的 iOS 平台代码中直接打印运行时标识:
using Foundation;
Console.WriteLine(
$"Running bundle ID: {NSBundle.MainBundle.BundleIdentifier}");
这里应输出:
com.theclubreferee.ioswatch.watchme
“旧的 Xcode 应用被启动”不能证明 MAUI 的标识正确。应以此为线索,继续核对安装目标和实际标识。
3. 确认两端会话完成激活
两端都需要配置 WCSession 的 delegate 并激活会话。MAUI 可以在 iOS 平台代码中使用 WatchConnectivity 命名空间提供的绑定。Microsoft:WCSession
排查时,可以在 MAUI 的 iOS 平台服务中加入以下诊断代码。它用于读取状态,不能替代 delegate 配置和会话初始化:
using WatchConnectivity;
if (WCSession.IsSupported)
{
var session = WCSession.DefaultSession;
Console.WriteLine($"ActivationState: {session.ActivationState}");
if (session.ActivationState == WCSessionActivationState.Activated)
{
Console.WriteLine(
$"Paired: {session.Paired}, " +
$"WatchAppInstalled: {session.WatchAppInstalled}, " +
$"Reachable: {session.Reachable}");
}
}
初始化时应先设置 delegate,再调用 MAUI iOS 绑定中的 ActivateSession();watchOS 对应调用 activate()。激活是异步过程,应在激活完成回调中记录状态和错误,并持续持有 delegate 对象。iOS 端还应处理会话失活、停用和切换手表的生命周期。Apple:WCSession
如果日志是在调用激活方法后立即输出的,先调整日志位置,再分析 WatchAppInstalled: False。
4. 使用干净的安装组合验证
建议在测试设备上按以下顺序验证:
- 记录原生 iOS 版本和 MAUI 版本各自的运行时 bundle ID。
- 清理旧测试版本,重新构建并安装 MAUI iOS 应用。
- 重新构建、安装伴侣标识指向该 MAUI 应用的 watchOS 版本,确认安装到了当前活动手表。
- 分别启动两端应用,等待会话激活完成,再检查安装状态和即时消息收发。
分别安装后曾经通信成功,说明当时的安装组合能够工作,不能据此推断任意两个应用只要填好标识就一定能建立伴侣关系。还应区分没有 iOS 伴侣的 watch-only 应用,以及可以独立运行但仍有 iOS 伴侣的 watchOS 应用。
如果准备随 MAUI iOS 应用一起交付手表应用,还需要检查相应的构建、嵌入和签名流程。当前片段没有提供这些信息,无法确认是否已经配置完成。
5. 安装关联正常后,再处理开关同步
会话已激活且 WatchAppInstalled 为 True 后,Reachable 仍可能为 False。它表示当前是否满足即时通信条件,而非永久连接状态。调用 sendMessage 需要对端可达,而且仍应处理发送失败回调。Apple:isReachable
如果只需要同步最新的 on/off 值,可以考虑 updateApplicationContext(_:),在 MAUI iOS 绑定中对应 UpdateApplicationContext。它适合传递最新状态,会覆盖尚未传出的旧上下文。后台交付由系统调度,不保证立即到达。接收端应实现对应回调,并在主线程更新界面。Apple:WCSession 数据传输方式
如果必须保留每一次切换事件,则需要另外设计事件传输与顺序处理。无论使用哪种方式,都应避免收到远端值、更新本地开关后,又触发一次相同状态的发送。
备注:内容仅供参考。
