Watchkit , openParentApplication 和 WatchKit 扩展

Posted

技术标签:

【中文标题】Watchkit , openParentApplication 和 WatchKit 扩展【英文标题】:Watchkit , openParentApplication with WatchKit Extension 【发布时间】:2015-08-01 16:40:09 【问题描述】:

第一次不起作用“Null”(在 iPhone 中打开 App 之前)

有些时候不起作用,但我想要一个循环或计时器来重复此请求以获得结果:

这是我的代码

- (void)application:(UIApplication *)application handleWatchKitExtensionRequest:(NSDictionary *)userInfo reply:(void (^)(NSDictionary *))reply

    // Temporary fix, I hope.
    // --------------------
    __block UIBackgroundTaskIdentifier bogusWorkaroundTask;
    bogusWorkaroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^
        [[UIApplication sharedApplication] endBackgroundTask:bogusWorkaroundTask];
    ];
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^
        [[UIApplication sharedApplication] endBackgroundTask:bogusWorkaroundTask];
    );
    // --------------------

    __block UIBackgroundTaskIdentifier realBackgroundTask;
    realBackgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^
        reply(nil);
        [[UIApplication sharedApplication] endBackgroundTask:realBackgroundTask];
    ];

    // Kick off a network request, heavy processing work, etc.

    // Return any data you need to, obviously.
    // reply(nil);
    reply(@@"Confirmation" : @"Text was received.");

    [[UIApplication sharedApplication] endBackgroundTask:realBackgroundTask];

    //  NSLog(@"User Info: %@", userInfo);





观看应用代码

- (void)willActivate 
    // This method is called when watch view controller is about to be visible to user
    [super willActivate];




    NSDictionary *dictionary = [[NSDictionary alloc] initWithObjectsAndKeys:@"MyCamande", @"OK", nil];

    [InterfaceController openParentApplication:dictionary reply:^(NSDictionary *replyInfo, NSError *error) 
        NSLog(@"Reply received by Watch app: %@", replyInfo);
    ];


如何回忆才能得到最终结果

【问题讨论】:

我的回答真的对你有帮助吗? :) 【参考方案1】:

好吧,我不建议您在手表本身上使用与网络操作相关的任何东西。首先是因为苹果不建议这样做,原因很明显。唯一直接在手表上执行的网络操作是加载图像。

我一直在为网络运营苦苦挣扎,观察了大约一周,得出的结论是,目前最稳定的方法并不明显。

主要问题是WKInterfaceController.openParentApplication(...) 无法按预期工作。不能只请求打开 iPhone 应用程序并按原样返回响应。有很多解决方案表明在- (void)application:(UIApplication *)application handleWatchKitExtensionRequest:(NSDictionary *)userInfo reply:(void (^)(NSDictionary *))reply 中创建后台线程可以正常工作,但实际上并没有。问题是这个方法必须马上发送reply(...);。即使创建同步请求也无济于事,您将不断收到“错误 -2 iPhone 应用程序未回复..”,就像我们的 10 次中的 5 倍一样。

所以,我的解决方案如下:

你实施:

func requestUserToken() 
        WKInterfaceController.openParentApplication(["request" : "token"], reply: responseParser)
    

如果没有来自 iPhone 的响应,则解析响应以查找可能发生的错误。

ios

- (void)application:(UIApplication *)application handleWatchKitExtensionRequest:(NSDictionary *)userInfo reply:(void (^)(NSDictionary *))reply



    __block UIBackgroundTaskIdentifier watchKitHandler;
    watchKitHandler = [[UIApplication sharedApplication] beginBackgroundTaskWithName:@"backgroundTask"
                                                                   expirationHandler:^
                                                                       watchKitHandler = UIBackgroundTaskInvalid;
                                                                   ];

    NSString *request = userInfo[@"request"];

    if ([request isEqualToString:@"token"])
    
        reply(@@"token" : @"OK");

        [PSWatchNetworkOperations.shared loginUser];
     

    dispatch_after( dispatch_time( DISPATCH_TIME_NOW, (int64_t)NSEC_PER_SEC * 1 ), dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0 ), ^
        [[UIApplication sharedApplication] endBackgroundTask:watchKitHandler];
     );

这段代码只是创建了一个后台线程来强制 iPhone 发送网络请求。假设您的 iPhone 应用程序中有一个特殊的类,它会发送这些请求并将答案发送给 watch。目前,这只能使用App Groups 完成。因此,您必须为您的应用程序和 watchkit 扩展创建一个应用程序组。之后,我建议使用MMWormhole 来建立您的应用程序和扩展程序之间的通信。该手册非常不言自明。

现在这一切有什么意义。您必须实现向服务器发送请求并通过虫洞发送响应。我使用 ReactiveCocoa,所以我的代码中的示例是这样的:

- (void)fetchShoppingLists

    RACSignal *signal = [PSHTTPClient.sharedAPIClient rac_GET:@"list/my" parameters:@@"limit":@20, @"offset":@0 resultClass:PSShoppingListsModel.class];
    [signal subscribeNext:^(PSShoppingListsModel* shoppingLists) 
        [self.wormHole passMessageObject:shoppingLists identifier:@"shoppingLists"];
    ];

    [signal subscribeError:^(NSError *error) 
        [self.wormHole passMessageObject:error identifier:@"error"];
    ];

正如您在此处看到的,我发回响应对象或错误。请注意,您通过 wormhole 发送的所有内容都应该与 NSCoding 兼容。

现在在手表上你可能会像这样解析响应:

override func awakeWithContext(context: AnyObject?) 
    super.awakeWithContext(context)

    PSWatchOperations.sharedInstance.requestUserToken()

    PSWatchOperations.sharedInstance.wormhole.listenForMessageWithIdentifier("token", listener:  (messageObject) -> Void in
        // parse message object here
        
    )


所以,得出一个结论。您向父应用程序发送请求以从后台唤醒并启动异步操作。立即发送回复()。当您收到操作的答复时,发送通知您已收到答复。同时在您的 watchExtension 中收听响应。

对不起,那是很多文字,但我只是希望它有助于保持冷静,因为我为此花费了很多精力。

【讨论】:

【参考方案2】:

也许您可以尝试更清楚地解释确切的问题。但无论如何,您可能想做的一件事是在 awakeWithContext: 中调用 openParentApp:而不是 willActivate。

【讨论】:

以上是关于Watchkit , openParentApplication 和 WatchKit 扩展的主要内容,如果未能解决你的问题,请参考以下文章

Apple Watch 和 openParentApplication 在后台

Apple Watch 在 15 分钟后失去与 iOS 应用程序的连接

向 +[WKInterfaceController openParentApplication:reply:] 提供自定义错误

Apple Watch: WatchKit 应用程序要点

如何下载 WatchKit? [关闭]

watchkit 应用程序的企业配置?