Watchkit, openParentApplication con la extensión WatchKit
appdelegate apple-watch (2)
La primera vez no funciona "Nulo" (antes de abrir la aplicación en iPhone)
y algunas veces no funciona, pero quiero un bucle o temporizador para repetir esta solicitud para obtener el resultado:
aqui esta mi codigo
- (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);
}
Ver código de aplicación
- (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);
}];
}
¿Cómo puede recordar para obtener finalmente resultado
Bueno, no recomendaría usar nada relacionado con las operaciones de red en el reloj. En primer lugar porque Apple no recomienda hacerlo por razones obvias. Lo único que se realiza directamente en la red en el reloj es cargar imágenes.
He estado luchando con las operaciones de red y observé durante una semana y llegué a la conclusión de que la forma más estable de hacerlo en este momento no es obvia.
El problema principal es que
WKInterfaceController.openParentApplication(...)
no funciona como se esperaba.
Uno no puede simplemente solicitar abrir la aplicación de iPhone y devolver la respuesta tal como está.
Hay toneladas de soluciones que indican que la creación de subproceso de fondo en la
- (void)application:(UIApplication *)application handleWatchKitExtensionRequest:(NSDictionary *)userInfo reply:(void (^)(NSDictionary *))reply
funcionaría bien, pero en realidad no.
El problema es que este método tiene que enviar
reply(...);
inmediatamente.
Incluso la creación de solicitudes sincrónicas no ayudará, seguirá recibiendo "error -2 la aplicación de iPhone no respondió ..." como 5 veces nuestro de 10.
Entonces, mi solución es la siguiente:
Implementas:
func requestUserToken() {
WKInterfaceController.openParentApplication(["request" : "token"], reply: responseParser)
}
y analizar la respuesta para el error que podría ocurrir si no hay respuesta del iPhone.
En el lado de 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];
} );
}
Este código solo crea un hilo de fondo que obliga al iPhone a enviar una solicitud de red. Imaginemos que tendría una clase especial en su aplicación de iPhone que enviaría estas solicitudes y enviaría la respuesta para ver. Por ahora, esto solo se puede lograr con Grupos de aplicaciones . Por lo tanto, debe crear un grupo de aplicaciones para su aplicación y la extensión del kit de vigilancia. Después, recomendaría usar MMWormhole para establecer comunicación entre su aplicación y extensión. El manual es bastante autoexplicativo.
Ahora, ¿qué sentido tiene todo esto? Debe implementar la solicitud de envío al servidor y enviar la respuesta a través del agujero de gusano. Yo uso ReactiveCocoa, así que el ejemplo de mi código es así:
- (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"];
}];
}
Como puede ver aquí, le devuelvo el objeto de respuesta o el error. Tenga en cuenta que todo lo que envíe a través del agujero de gusano debe ser compatible con NSCoding.
Ahora en el reloj, probablemente analizarás una respuesta como esta:
override func awakeWithContext(context: AnyObject?) {
super.awakeWithContext(context)
PSWatchOperations.sharedInstance.requestUserToken()
PSWatchOperations.sharedInstance.wormhole.listenForMessageWithIdentifier("token", listener: { (messageObject) -> Void in
// parse message object here
}
})
}
Entonces, para llegar a una conclusión. Envía una solicitud a la aplicación principal para que se active desde el fondo e inicie la operación asincrónica. Enviar respuesta () de vuelta inmediatamente. Cuando reciba respuesta de la operación, envíe una notificación de que tiene respuesta. Mientras tanto, escuche la respuesta en su relojExtensión.
Lo siento, eso fue mucho texto, pero solo espero que te ayude a mantener la calma, porque he gastado muchos nervios en eso.
Puede ser que puedas tratar de explicar el problema exacto un poco más claramente. Pero una cosa que puede hacer independientemente es hacer la llamada openParentApp en awakeWithContext: en lugar de willActivate.