iOS-WatchKit 文件传输工作不可靠

Nat*_*ate 5 objective-c ios watchkit watchos-2

我已经为 iOS 9 和 WatchOS 2 构建了一个应用程序。iOS 应用程序会定期将图像文件从 iPhone 传输到手表。有时,这些是从应用程序推送的,有时是 Watch 请求(拉取)它们。如果拉取,我将请求异步,并使用完全相同的 iOS 代码在两种情况下传输图像。

大约一半的时间(可能是 2/3),文件传输有效。其他时候,似乎什么也没发生。无论我是推还是拉图像,这都是一样的。

在 iOS 端,我使用类似于此的代码(会话已激活):

   if ([WCSession isSupported]) {
      WCSession *session = [WCSession defaultSession];
      if (session.reachable) {
         NSData *imgData = UIImagePNGRepresentation(img);

         NSURL *tempFile = [[session watchDirectoryURL] URLByAppendingPathComponent: @"camera.png"];
         BOOL success = [imgData writeToFile: [tempFile path] atomically: NO];
         if (success) {
            NSLog(@"transferFile:metadata:");
            [session transferFile: tempFile metadata: nil];
         } else {
            NSLog(@"will not call transferFile:metadata:");
         }
      } else {
         NSLog(@"Camera watch client not reachable.");
      }
   }
Run Code Online (Sandbox Code Playgroud)

在手表扩展端,我有一个单例来激活手表会话并接收文件:

- (void)session:(WCSession *)session didReceiveFile:(WCSessionFile *)file {
   // pass the data file to the data listener (if any)
   [self.dataListener session: session didReceiveFile: file];
}
Run Code Online (Sandbox Code Playgroud)

我的“数据侦听器”将文件转换为 aUIImage并将其显示在 UI 线程上。然而,这可能无关紧要,因为失败的操作永远不会那么远。

在不成功的传输期间,session:didReceiveFile:永远不会被调用。但是,如果我检查 iOS 应用程序的日志,我只会在失败的操作期间看到这些消息:

12 月 26 日 15:10:47 主机名伴侣应用程序 [74893]:(注)WatchKit:应用程序(com.mycompany.MyApp.watchkitapp),安装状态:2,消息:应用程序安装成功

12 月 26 日 15:10:47 主机名伴侣应用程序 [74893]:(注意)WatchKit:从安装队列中清除 com.mycompany.MyApp.watchkitapp,剩余 0 个应用程序

这里发生了什么?该应用程序似乎正在尝试重新安装 Watch 应用程序 (?)。当发生这种情况,我也不会看手表应用程序崩溃/关闭并重新启动。它只是什么都不做。没有收到文件。

在 iOS 端,我将图像缩小到大约 136x170 像素,因此 PNG 文件不应太大。

任何想法出了什么问题?

更新:

我已经在 Github 上发布了一个完整的、最小的项目来演示这个问题

4ob*_*oby 0

这就是我设法将文件从手机传输到手表的方法:
为了使其正常工作,文件必须位于 appGroupFolder 中,并且必须从功能选项卡中启用手机和手表的“应用程序组” 。

为了获取 appGroup 文件夹,请使用以下代码行:

NSURL * myFileLocationFolder = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier: @"myGroupID"]; //something like group.bundle.projName
Run Code Online (Sandbox Code Playgroud)

一旦你得到了它,就可以使用它来发送消息并处理来自手表的响应:

 [session sendMessage:@{@"file":myFileURL.absoluteString} replyHandler:^(NSDictionary<NSString *,id> * _Nonnull replyMessage) {
                //got reply
            } errorHandler:^(NSError * _Nonnull error) {
                //got Error
            }];
Run Code Online (Sandbox Code Playgroud)

尽管WCSession *session = [WCSession defaultSession]; 我注意到有时session会被释放,所以你可能会考虑使用[WCSession defaultSession];它。

要在电话上捕获此信息,请使用:

- (void)session:(WCSession *)session didReceiveMessage:(NSDictionary<NSString *, id> *)message replyHandler:(void(^)(NSDictionary<NSString *, id> *replyMessage))replyHandler{
 //message[@"file"] - addres to my file
 //do stuff with it here

 replyHandler(@{@"myResponse":@"responseData"}); //this call triggers replyHandler block on the watch
}
Run Code Online (Sandbox Code Playgroud)

现在,如果您没有忘记实施WCSessionDelegate和使用

if ([WCSession isSupported]) {
    _session = [WCSession defaultSession];
    _session.delegate = self;
    [_session activateSession];
}
//here session is @property (strong, nonatomic) WCSession * session;
Run Code Online (Sandbox Code Playgroud)

这一切都应该有效。

做出了更广泛的回答,希望能够覆盖到更多的人。

  • Watch OS 2 不再支持应用程序组:https://forums.developer.apple.com/thread/3927 (2认同)