Actualización del contenido cuando se usa contenido alojado en Apple para la compra en la aplicación

Estoy implementando la compra en la aplicación usando contenido alojado en Apple. Anteriormente estaba usando Urban Airship para alojar mi contenido y usar su SDK para proporcionar la interfaz de usuario de la tienda en la aplicación y la funcionalidad de compra.

Como Urban Airship está descontinuando su apoyo IAP este mes de julio, tengo que replacelo.

El SDK de Urban Airship tenía soporte para actualizar el contenido comprado. Veo que StoreKit proporciona esta funcionalidad (al less hasta cierto punto) pero no estoy segura de cómo implementar correctamente la actualización de contenido.

SKProduct tiene un downloadContentVersion que especifica la versión del contenido que se puede download de Apple. Realizo un seguimiento de la versión que se está descargando actualmente dentro de la aplicación, así que sé cuándo hay disponible una actualización.

La parte con la que me quedo es cómo download realmente el contenido actualizado?

Mi primer pensamiento fue hacer un Restore para esa compra en particular, pero parece que no hay manera de restaurar productos individuales (solo todos los productos). El segundo pensamiento fue simplemente volver a comprar el producto, pero esto presenta una alerta al usuario indicando que se cobrarán nuevamente; sin embargo, no se cobrarán, ya que se muestra otra alerta después de la compra que informa al usuario que la el contenido ya se ha comprado y se volverá a download de forma gratuita, pero para mí esto se siente como una mala experiencia de usuario, puede que no sepan necesariamente que no se volverán a cargar hasta después de aceptar la compra.

La documentation dice que no SKDownload instancias de SKDownload yo mismo, así que no puedo solo crear una y agregarla a la queue de descarga.

¿Cómo se supone que debo implementar actualizaciones de contenido para la compra en la aplicación cuando uso contenido alojado en Apple?

Gracias a Jasarien por contactarse con Apple en este caso. Aquí hay un código de ejemplo para cualquier persona que encuentre este tema tratando de averiguar cómo actualizar el contenido de la aplicación.

Primero, cuando obtenga su respuesta de SKProductsRequest, consulte downloadContentVersion con la versión de su contenido descargado previamente. Puede get la versión de contenido para su contenido existente con un código como este:

 NSString *pathToYourContent = @""; // Put your path here NSString *contentInfoPath = [pathToYourContent stringByAppendingPathComponent:@"ContentInfo.plist"]; NSDictionary *contentInfo = [NSDictionary dictionaryWithContentsOfFile:contentInfoPath]; NSString *contentVersion = [contentInfo objectForKey:@"ContentVersion"]; NSString *iapProductIdentifier = [contentInfo objectForKey:@"IAPProductIdentifier"]; 

Entonces, si observa que la versión ha cambiado, puede pedirle al usuario que actualice. Si están de acuerdo, inicie una restauración.

[[SKPaymentQueue defaultQueue] restreCompletedTransactions];

Luego, cuando las transactions comienzan a llegar, debe decidir cuáles aceptar y cuáles ignorar. En este ejemplo de mi aplicación, que descarga el contenido de la canción, tengo una class YHSongVersion que almacena la ID y la versión de todas las canciones que hemos descargado, y estas se almacenan en la matriz self.ownedSongVersions. Este ejemplo aceptará las restauraciones donde los numbers de versión sean diferentes o no tengamos el contenido.

 - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions { for (SKPaymentTransaction *transaction in transactions) { switch (transaction.transactionState) { case SKPaymentTransactionStateFailed: break; case SKPaymentTransactionStatePurchased: [self provideContentForTransaction:transaction]; break; case SKPaymentTransactionStatePurchasing: break; case SKPaymentTransactionStateRestonetworking: [self restrePurchaseIfRequinetworking:transaction]; break; } } } /// On a restre download the content if either we don't have the content or the version number has changed. - (void)restrePurchaseIfRequinetworking:(SKPaymentTransaction *)transaction { BOOL haveSong = NO; SKDownload *download = [transaction.downloads objectAtIndex:0]; for (YHSongVersion *ownedSongVersion in self.ownedSongVersions) { BOOL isSongForThisDownload = [ownedSongVersion.iapProductIdentifier isEqualToString:download.contentIdentifier]; if (isSongForThisDownload) { haveSong = YES; BOOL hasDifferentVersionNumber = ![ownedSongVersion.contentVersion isEqualToString:download.contentVersion]; if (hasDifferentVersionNumber) { [self provideContentForTransaction:transaction]; } else { // Do nothing [self completeTransaction:transaction]; NSLog(@"Ignoring restre for %@", ownedSongVersion.iapProductIdentifier); } } } if (!haveSong) { [self provideContentForTransaction:transaction]; } } 

Hablé con algunos ingenieros de Store Kit en WWDC y les hice esta pregunta.

Su respuesta no fue tan positiva como esperaba.

Confirmaron la ausencia de una API para restaurar un único producto como error y me alentaron a presentar dos errores (uno para una request de mejora para esa API en el kit de la tienda y otro para la documentation demasiado escasa en esta área de actualización de productos) .

En cuanto al problema inmediato, su sugerencia era implementar una function de "actualizar todo", en la que todos los productos se restauran para get sus transactions y sus objects de descarga (la opción que finalmente elegí), o de manera similar, restaurar todos los productos, pero ignore todos los productos excepto el que está intentando actualizar (inútil, en última instancia, ya que está restaurando todo varias veces si sigue este enfoque para cada producto).

Actualizaré esta respuesta con los numbers de radar para los errores que presente una vez que lo haga, para que otros puedan duplicarlos si es necesario (¡recuerde, engaña a los errores!)

Editar

He informado sobre el error y su número es rdar: // 14174034 – no dude en duplicar.