PAYATHON 2026

Xcode 26 的 Apple Watch 应用如何连接 .NET 10 MAUI iOS 应用?

数据阿明

原生 watchOS 应用可以通过 WatchConnectivity 与 MAUI 的 iOS 应用通信。当前配置中有一处明确的问题:WKCompanionAppBundleIdentifier 应配置在 watchOS 应用中,值为 iOS 应用的 bundle ID。在 MAUI iOS 应用中添加同名键并指向手表应用,不能建立反向关联。

这处配置问题还不足以解释全部现象。需要确认 MAUI 最终安装的应用标识,以及读取日志时 WCSession 是否已经激活。仅凭现有片段无法确定唯一的根因。

三个状态的含义

状态含义
Paired: TrueiPhone 已配对 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. 使用干净的安装组合验证

建议在测试设备上按以下顺序验证:

  1. 记录原生 iOS 版本和 MAUI 版本各自的运行时 bundle ID。
  2. 清理旧测试版本,重新构建并安装 MAUI iOS 应用。
  3. 重新构建、安装伴侣标识指向该 MAUI 应用的 watchOS 版本,确认安装到了当前活动手表。
  4. 分别启动两端应用,等待会话激活完成,再检查安装状态和即时消息收发。

分别安装后曾经通信成功,说明当时的安装组合能够工作,不能据此推断任意两个应用只要填好标识就一定能建立伴侣关系。还应区分没有 iOS 伴侣的 watch-only 应用,以及可以独立运行但仍有 iOS 伴侣的 watchOS 应用。

如果准备随 MAUI iOS 应用一起交付手表应用,还需要检查相应的构建、嵌入和签名流程。当前片段没有提供这些信息,无法确认是否已经配置完成。

5. 安装关联正常后,再处理开关同步

会话已激活且 WatchAppInstalled 为 True 后,Reachable 仍可能为 False。它表示当前是否满足即时通信条件,而非永久连接状态。调用 sendMessage 需要对端可达,而且仍应处理发送失败回调。Apple:isReachable

如果只需要同步最新的 on/off 值,可以考虑 updateApplicationContext(_:),在 MAUI iOS 绑定中对应 UpdateApplicationContext。它适合传递最新状态,会覆盖尚未传出的旧上下文。后台交付由系统调度,不保证立即到达。接收端应实现对应回调,并在主线程更新界面。Apple:WCSession 数据传输方式

如果必须保留每一次切换事件,则需要另外设计事件传输与顺序处理。无论使用哪种方式,都应避免收到远端值、更新本地开关后,又触发一次相同状态的发送。

备注:内容仅供参考。