didReceiveApplicationContext未被调用

eml*_*eeh 3 ios watchkit watchos-2 watchconnectivity

我刚刚使用教程/示例代码在我的应用程序中设置了WCConnectivity,我觉得我已经正确实现了它.我没有使用模拟器进行测试.出于某种原因,即使所有内容都已正确设置,也不会在监视应用程序中调用didReceiveApplicationContext.

我尝试在ExtensionDelegate中调用WatchKit应用程序的接口控制器,并使用NSUserDefaults来设置接口控制器数据.

iOS应用程序

ViewController.m

- (void) viewDidLoad{
if ([WCSession isSupported]) {
    WCSession *session = [WCSession defaultSession];
    session.delegate = self;
    [session activateSession];
  }
}

-(void) saveTrip{
NSMutableArray *currentTrips = [NSMutableArray arrayWithArray:[self.sharedDefaults objectForKey:@"UserLocations"]];

NSData *data = [NSKeyedArchiver archivedDataWithRootObject:newLocation];
[currentTrips addObject:data];
[self.sharedDefaults setObject:currentTrips forKey:@"UserLocations"];
[self.sharedDefaults synchronize];

WCSession *session = [WCSession defaultSession];
NSDictionary *applicationDict = [[NSDictionary alloc] initWithObjects:@[currentTrips] forKeys:@[@"UserLocations"]];;
[session updateApplicationContext:applicationDict error:nil];
}
Run Code Online (Sandbox Code Playgroud)

观看分机代码

ExtensionDelegate.m

- (void)applicationDidFinishLaunching {
if ([WCSession isSupported]) {
    WCSession *session = [WCSession defaultSession];
    session.delegate = self;
    [session activateSession];
}
}
- (void)session:(nonnull WCSession *)session didReceiveApplicationContext:(nonnull NSDictionary<NSString *,id> *)applicationContext {
self.places= [applicationContext objectForKey:@"UserLocations"];
[[NSUserDefaults standardUserDefaults] setObject:self.places forKey:@"UserLocations"];
[[NSUserDefaults standardUserDefaults] synchronize]; 
}
Run Code Online (Sandbox Code Playgroud)

InterfaceController.m

- (void)willActivate {
[super willActivate];
self.placesData = [NSMutableArray arrayWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:@"UserLocations"]];
[self loadData];
}
Run Code Online (Sandbox Code Playgroud)

Gra*_*rks 10

对我来说这是两件事:

  1. 在字典中传递无效值.甚至无法传递NSNull()来表示nil值.如果您的数据无法在plist中表示,则会失败.
  2. 如果字典没有改变,后续调用updateApplicationContext将不会触发相应的调用didReceiveApplicationContext.要强制更新,您可以向有效负载添加UUID,例如

    context["force_send"] = UUID().uuidString
    
    Run Code Online (Sandbox Code Playgroud)

  • 这是最重要的发现!applicationContext在iOS设备上进行缓冲,因此只有在它没有更改时才会转移到watch扩展名.在测试情况下,添加"更换器"非常有用(比如UUID解决方案,或者 - 甚至更好 - 一个NSDate.date). (2认同)

ccj*_*sen 5

处理任何错误可能证明是有用的,因此更改:

[session updateApplicationContext:applicationDict error:nil];
Run Code Online (Sandbox Code Playgroud)

NSError *error;    
if (![session updateApplicationContext:applicationDict error:&error]) {
    NSLog(@"updateApplicationContext failed with error %@", error);
}
Run Code Online (Sandbox Code Playgroud)


小智 2

如果它不起作用,则可能没有正确实施。

乍一看有几个问题:

  • 在您的 iOS 应用程序中,您可以获得对共享会话的引用并激活它,但不要将该局部变量分配给视图控制器上的任何属性。这意味着一旦退出,您的局部变量将超出范围viewDidLoad。您还需要在手表扩展中更正该问题。

  • 在 中saveTrip,您再次创建另一个本地会话,该会话未激活且没有任何委托。您需要使用之前设置并激活的第一个会话。

  • 在您的手表上,您保存收到的数据,但您的界面控制器不会知道它应该加载和显示新数据。

一些提示:

  • 如果您在 中设置并激活会话application:didFinishLaunchingWithOptions,它将在应用程序范围内可用(并在应用程序生命周期的早期激活)。

  • 您应该检查您的会话是否有效,因为手表可能未配对,或者手表应用程序可能未安装。这是一个很好的 (Swift) 教程,涵盖了这些情况,并且还使用会话管理器来更轻松地支持在整个应用程序中使用 Watch Connectivity。

  • 您可能希望向手表传递更少/更轻的数据,而不是尝试处理自定义对象数组的归档。

  • 顺便说一句,你想要做的事情NSUserDefaults非常复杂。它的真正目的是在发布过程中保持偏好。滥用它作为在扩展程序和控制器之间来回传递模型的方式是不合适的。